diff --git a/x-pack/plugins/observability_solution/apm/common/critical_path/get_critical_path.test.ts b/x-pack/plugins/observability_solution/apm/common/critical_path/get_critical_path.test.ts index 61720dba3d472..6aba57f8339dc 100644 --- a/x-pack/plugins/observability_solution/apm/common/critical_path/get_critical_path.test.ts +++ b/x-pack/plugins/observability_solution/apm/common/critical_path/get_critical_path.test.ts @@ -6,18 +6,29 @@ */ import { apm, ApmFields, dedot } from '@kbn/apm-synthtrace-client'; import { getWaterfall } from '../../public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers'; -import { Span } from '../../typings/es_schemas/ui/span'; import { Transaction } from '../../typings/es_schemas/ui/transaction'; import { getCriticalPath } from './get_critical_path'; +import { WaterfallSpan, WaterfallTransaction } from '../waterfall/typings'; describe('getCriticalPath', () => { function getCriticalPathFromEvents(events: ApmFields[]) { events = events.filter((event) => event['processor.event'] !== 'metric'); const entryTransaction = dedot(events[0]!, {}) as Transaction; + + const traceDocs = events.map((event: any) => { + Object.keys(event).forEach((key) => { + const item = event[key]; + if (!Array.isArray(item)) { + event[key] = [item]; + } + }); + return event as WaterfallSpan | WaterfallTransaction; + }); + const waterfall = getWaterfall({ traceItems: { - traceDocs: events.map((event) => dedot(event, {}) as Transaction | Span), + traceDocs, errorDocs: [], exceedsMax: false, spanLinksCountById: {}, @@ -72,7 +83,9 @@ describe('getCriticalPath', () => { .serialize() ); - const longerSpan = waterfall.items.find((item) => (item.doc as Span).span?.name === 'bar'); + const longerSpan = waterfall.items.find( + (item) => ((item.doc as WaterfallSpan)['span.name']?.[0] as string) === 'bar' + ); expect(segments).toEqual([ { self: false, duration: 100000, item: waterfall.items[0], offset: 0 }, diff --git a/x-pack/plugins/observability_solution/apm/common/waterfall/typings.ts b/x-pack/plugins/observability_solution/apm/common/waterfall/typings.ts index 49f282473e9dd..34d650241fa1b 100644 --- a/x-pack/plugins/observability_solution/apm/common/waterfall/typings.ts +++ b/x-pack/plugins/observability_solution/apm/common/waterfall/typings.ts @@ -6,83 +6,61 @@ */ import { Exception } from '../../typings/es_schemas/raw/error_raw'; -import { EventOutcome } from '../../typings/es_schemas/raw/fields/event_outcome'; -import { SpanLink } from '../../typings/es_schemas/raw/fields/span_links'; -import { TimestampUs } from '../../typings/es_schemas/raw/fields/timestamp_us'; import { AgentName } from '../../typings/es_schemas/ui/fields/agent'; export interface WaterfallTransaction { - timestamp: TimestampUs; - trace: { id: string }; - service: { - name: string; - environment?: string; - }; - agent: { name: AgentName }; - event?: { outcome?: EventOutcome }; - parent?: { id?: string }; - processor: { event: 'transaction' }; - transaction: { - duration: { us: number }; - id: string; - name: string; - type: string; - result?: string; - }; - faas?: { - coldstart?: boolean; - }; - span?: { - links?: SpanLink[]; - }; + 'timestamp.us': number[]; + 'trace.id': string[]; + 'service.name': string[]; + 'service.environment'?: string[]; + 'agent.name': string[]; + 'event.outcome'?: string[]; + 'parent.id'?: string[]; + 'processor.event': ['transaction']; + 'transaction.duration.us': number[]; + 'transaction.id': string[]; + 'transaction.name': string[]; + 'transaction.type': string[]; + 'transaction.result'?: string[]; + 'faas.coldstart'?: boolean[]; + 'span.links.span.id'?: string[]; + 'span.links.trace.id'?: string[]; } export interface WaterfallSpan { - timestamp: TimestampUs; - trace: { id: string }; - service: { - name: string; - environment?: string; - }; - agent: { name: AgentName }; - event?: { outcome?: EventOutcome }; - parent?: { id?: string }; - processor: { event: 'span' }; - span: { - id: string; - type: string; - subtype?: string; - action?: string; - name: string; - composite?: { - count: number; - sum: { us: number }; - compression_strategy: string; - }; - sync?: boolean; - duration: { us: number }; - links?: SpanLink[]; - }; - transaction?: { - id: string; - }; - child?: { id: string[] }; + 'timestamp.us': number[]; + 'trace.id': string[]; + 'service.name': string[]; + 'service.environment'?: string[]; + 'agent.name': AgentName[]; + 'event.outcome'?: string[]; + 'parent.id'?: string[]; + 'processor.event': ['span']; + 'span.id': string[]; + 'span.type': string[]; + 'span.subtype'?: string[]; + 'span.action'?: string[]; + 'span.name': string[]; + 'span.composite.count'?: number[]; + 'span.composite.sum.us'?: number[]; + 'span.composite.compression_strategy'?: string[]; + 'span.sync'?: boolean[]; + 'span.duration.us': number[]; + 'span.links.span.id'?: string[]; + 'span.links.trace.id'?: string[]; + 'transaction.id'?: string[]; + 'child.id'?: string[]; } export interface WaterfallError { - timestamp: TimestampUs; - trace?: { id: string }; - transaction?: { id: string }; - parent?: { id: string }; - error: { - id: string; - log?: { - message: string; - }; - exception?: Exception[]; - grouping_key: string; - }; - service: { - name: string; - }; + 'timestamp.us': number[]; + 'trace.id'?: string[]; + 'transaction.id'?: string[]; + 'parent.id'?: string[]; + 'error.id': string[]; + 'error.log.message'?: string[]; + 'error.exception.message'?: string[]; + 'error.exception'?: Exception[]; + 'error.grouping_key': string[]; + 'service.name': string[]; } diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx index ef7ea348d37f7..cd6953b2fece9 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx @@ -24,6 +24,7 @@ import { TransactionTab } from '../transaction_details/waterfall_with_summary/tr import { DependencyOperationDistributionChart } from './dependency_operation_distribution_chart'; import { DetailViewHeader } from './detail_view_header'; import { maybeRedirectToAvailableSpanSample } from './maybe_redirect_to_available_span_sample'; +import { SERVICE_NAME } from '../../../../common/es_fields/apm'; export function DependencyOperationDetailView() { const router = useApmRouter(); @@ -187,7 +188,9 @@ export function DependencyOperationDetailView() { traceSamplesFetchStatus={spanFetch.status} onSampleClick={onSampleClick} onTabClick={onTabClick} - serviceName={waterfallFetch.waterfall.entryWaterfallTransaction?.doc.service.name} + serviceName={ + waterfallFetch.waterfall.entryWaterfallTransaction?.doc[SERVICE_NAME]?.[0] + } waterfallItemId={waterfallItemId} detailTab={detailTab} selectedSample={selectedSample || null} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/trace_explorer/trace_explorer_waterfall.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/trace_explorer/trace_explorer_waterfall.tsx index 1bda6985e534e..40b06a34b9a19 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/trace_explorer/trace_explorer_waterfall.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/trace_explorer/trace_explorer_waterfall.tsx @@ -7,6 +7,7 @@ import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public'; import React, { useCallback, useEffect } from 'react'; import { useHistory } from 'react-router-dom'; +import { SERVICE_NAME } from '@kbn/apm-types/es_fields'; import { useApmParams } from '../../../hooks/use_apm_params'; import { useTimeRange } from '../../../hooks/use_time_range'; import { useTraceExplorerSamples } from '../../../hooks/use_trace_explorer_samples'; @@ -106,7 +107,9 @@ export function TraceExplorerWaterfall() { onTabClick={onTabClick} detailTab={detailTab} waterfallItemId={waterfallItemId} - serviceName={waterfallFetchResult.waterfall.entryWaterfallTransaction?.doc.service.name} + serviceName={ + waterfallFetchResult.waterfall.entryWaterfallTransaction?.doc[SERVICE_NAME]?.[0] + } showCriticalPath={showCriticalPath} onShowCriticalPathChange={onShowCriticalPathChange} /> diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/distribution/index.tsx index f7a976b3cc82d..ceb6f21c52327 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/distribution/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/distribution/index.tsx @@ -61,9 +61,8 @@ export function TransactionDistribution({ const { waterfallItemId, detailTab } = urlParams; const { serviceName } = useApmServiceContext(); - const markerCurrentEvent = - waterfallFetchResult.waterfall.entryWaterfallTransaction?.doc.transaction.duration.us; + waterfallFetchResult.waterfall.entryWaterfallTransaction?.doc['transaction.duration.us'][0]; const { chartData, hasData, percentileThresholdValue, status, totalDocCount } = useTransactionDistributionChartData(); diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/maybe_view_trace_link.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/maybe_view_trace_link.tsx index 0a0d69fa71169..3e78c06ee7f8d 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/maybe_view_trace_link.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/maybe_view_trace_link.tsx @@ -15,6 +15,14 @@ import { IWaterfall } from './waterfall_container/waterfall/waterfall_helpers/wa import { Environment } from '../../../../../common/environment_rt'; import { useAnyOfApmParams } from '../../../../hooks/use_apm_params'; import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types'; +import { + SERVICE_ENVIRONMENT, + SERVICE_NAME, + TRACE_ID, + TRANSACTION_ID, + TRANSACTION_NAME, + TRANSACTION_TYPE, +} from '../../../../../common/es_fields/apm'; function FullTraceButton({ isLoading, isDisabled }: { isLoading?: boolean; isDisabled?: boolean }) { return ( @@ -93,17 +101,17 @@ export function MaybeViewTraceLink({ // the user is viewing a zoomed in version of the trace. Link to the full trace } else { const nextEnvironment = getNextEnvironmentUrlParam({ - requestedEnvironment: rootTransaction.service.environment, + requestedEnvironment: rootTransaction[SERVICE_ENVIRONMENT]?.[0], currentEnvironmentUrlParam: environment, }); return ( { docType: 'error', offset: 10, skew: 5, - doc: { error: { id: 1 }, service: { name: 'opbeans-java' } }, + doc: { 'error.id': [1], 'service.name': ['opbeans-java'] }, color: 'red', } as unknown, { docType: 'error', offset: 50, skew: 0, - doc: { error: { id: 2 }, service: { name: 'opbeans-node' } }, + doc: { 'error.id': [2], 'service.name': ['opbeans-node'] }, color: 'blue', } as unknown, ] as IWaterfallError[]; @@ -38,7 +38,7 @@ describe('getErrorMarks', () => { offset: 15, verticalLine: false, id: 1, - error: { error: { id: 1 }, service: { name: 'opbeans-java' } }, + error: { 'error.id': [1], 'service.name': ['opbeans-java'] }, serviceColor: 'red', }, { @@ -46,7 +46,7 @@ describe('getErrorMarks', () => { offset: 50, verticalLine: false, id: 2, - error: { error: { id: 2 }, service: { name: 'opbeans-node' } }, + error: { 'error.id': [2], 'service.name': ['opbeans-node'] }, serviceColor: 'blue', }, ]); @@ -58,14 +58,14 @@ describe('getErrorMarks', () => { docType: 'error', offset: 10, skew: 5, - doc: { error: { id: 1 }, service: { name: 'opbeans-java' } }, + doc: { 'error.id': [1], 'service.name': ['opbeans-java'] }, color: '', } as unknown, { docType: 'error', offset: 50, skew: 0, - doc: { error: { id: 2 }, service: { name: 'opbeans-node' } }, + doc: { 'error.id': [2], 'service.name': ['opbeans-node'] }, color: '', } as unknown, ] as IWaterfallError[]; @@ -75,7 +75,7 @@ describe('getErrorMarks', () => { offset: 15, verticalLine: false, id: 1, - error: { error: { id: 1 }, service: { name: 'opbeans-java' } }, + error: { 'error.id': [1], 'service.name': ['opbeans-java'] }, serviceColor: '', }, { @@ -83,7 +83,7 @@ describe('getErrorMarks', () => { offset: 50, verticalLine: false, id: 2, - error: { error: { id: 2 }, service: { name: 'opbeans-node' } }, + error: { 'error.id': [2], 'service.name': ['opbeans-node'] }, serviceColor: '', }, ]); diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/marks/get_error_marks.ts b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/marks/get_error_marks.ts index 2e932c6e27632..5947757edc164 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/marks/get_error_marks.ts +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/marks/get_error_marks.ts @@ -25,7 +25,7 @@ export const getErrorMarks = (errorItems: IWaterfallError[]): ErrorMark[] => { type: 'errorMark', offset: Math.max(error.offset + error.skew, 0), verticalLine: false, - id: error.doc.error.id, + id: error.doc['error.id']?.[0], error: error.doc, serviceColor: error.color, })); diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx index d0197f23d5fd5..263f8d7e4ee18 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx @@ -30,6 +30,7 @@ import { import { WaterfallItem } from './waterfall_item'; import { WaterfallContextProvider } from './context/waterfall_context'; import { useWaterfallContext } from './context/use_waterfall'; +import { EVENT_OUTCOME } from '../../../../../../../common/es_fields/apm'; interface AccordionWaterfallProps { isOpen: boolean; @@ -208,7 +209,7 @@ const WaterfallNode = React.memo((props: WaterfallNodeProps) => { style={{ position: 'relative' }} buttonClassName={`button_${node.item.id}`} id={node.item.id} - hasError={node.item.doc.event?.outcome === 'failure'} + hasError={node.item.doc[EVENT_OUTCOME]?.[0] === 'failure'} marginLeftLevel={marginLeftLevel} buttonContentClassName="accordion__buttonContent" buttonContent={ diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_flyout.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_flyout.tsx index 3c45ba1587d93..99c6f08f01820 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_flyout.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_flyout.tsx @@ -54,7 +54,7 @@ export function WaterfallFlyout({ waterfallItemId, waterfall, toggleFlyout }: Pr totalDuration={waterfall.duration} spanId={currentItem.id} parentTransactionId={parentTransactionId} - traceId={currentItem.doc.trace.id} + traceId={currentItem.doc['trace.id'][0]} onClose={() => toggleFlyout({ history })} spanLinksCount={currentItem.spanLinksCount} flyoutDetailTab={flyoutDetailTab} @@ -66,7 +66,7 @@ export function WaterfallFlyout({ waterfallItemId, waterfall, toggleFlyout }: Pr return ( toggleFlyout({ history })} rootTransactionDuration={waterfall.rootWaterfallTransaction?.duration} errorCount={waterfall.getErrorCount(currentItem.id)} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap index d1bb2e73e62f9..c274a145159f7 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap @@ -4,12 +4,12 @@ exports[`waterfall_helpers getWaterfallItems should handle cyclic references 1`] Array [ Object { "doc": Object { - "timestamp": Object { - "us": 10, - }, - "transaction": Object { - "id": "a", - }, + "timestamp.us": Array [ + 10, + ], + "transaction.id": Array [ + "a", + ], }, "docType": "transaction", "id": "a", @@ -19,27 +19,27 @@ Array [ }, Object { "doc": Object { - "parent": Object { - "id": "a", - }, - "span": Object { - "id": "b", - }, - "timestamp": Object { - "us": 20, - }, + "parent.id": Array [ + "a", + ], + "span.id": Array [ + "b", + ], + "timestamp.us": Array [ + 20, + ], }, "docType": "span", "id": "b", "offset": 10, "parent": Object { "doc": Object { - "timestamp": Object { - "us": 10, - }, - "transaction": Object { - "id": "a", - }, + "timestamp.us": Array [ + 10, + ], + "transaction.id": Array [ + "a", + ], }, "docType": "transaction", "id": "a", @@ -58,16 +58,18 @@ Array [ Object { "color": "", "doc": Object { - "service": Object { - "name": "opbeans-java", - }, - "timestamp": Object { - "us": 1536763736366000, - }, - "transaction": Object { - "id": "a", - "name": "APIRestController#products", - }, + "service.name": Array [ + "opbeans-java", + ], + "timestamp.us": Array [ + 1536763736366000, + ], + "transaction.id": Array [ + "a", + ], + "transaction.name": Array [ + "APIRestController#products", + ], }, "docType": "transaction", "duration": 9480, @@ -87,22 +89,24 @@ Array [ Object { "color": "", "doc": Object { - "parent": Object { - "id": "a", - }, - "service": Object { - "name": "opbeans-java", - }, - "span": Object { - "id": "b2", - "name": "GET [0:0:0:0:0:0:0:1]", - }, - "timestamp": Object { - "us": 1536763736367000, - }, - "transaction": Object { - "id": "a", - }, + "parent.id": Array [ + "a", + ], + "service.name": Array [ + "opbeans-java", + ], + "span.id": Array [ + "b2", + ], + "span.name": Array [ + "GET [0:0:0:0:0:0:0:1]", + ], + "timestamp.us": Array [ + 1536763736367000, + ], + "transaction.id": Array [ + "a", + ], }, "docType": "span", "duration": 4694, @@ -115,16 +119,18 @@ Array [ "parent": Object { "color": "", "doc": Object { - "service": Object { - "name": "opbeans-java", - }, - "timestamp": Object { - "us": 1536763736366000, - }, - "transaction": Object { - "id": "a", - "name": "APIRestController#products", - }, + "service.name": Array [ + "opbeans-java", + ], + "timestamp.us": Array [ + 1536763736366000, + ], + "transaction.id": Array [ + "a", + ], + "transaction.name": Array [ + "APIRestController#products", + ], }, "docType": "transaction", "duration": 9480, @@ -151,22 +157,24 @@ Array [ Object { "color": "", "doc": Object { - "parent": Object { - "id": "a", - }, - "service": Object { - "name": "opbeans-java", - }, - "span": Object { - "id": "b", - "name": "GET [0:0:0:0:0:0:0:1]", - }, - "timestamp": Object { - "us": 1536763736368000, - }, - "transaction": Object { - "id": "a", - }, + "parent.id": Array [ + "a", + ], + "service.name": Array [ + "opbeans-java", + ], + "span.id": Array [ + "b", + ], + "span.name": Array [ + "GET [0:0:0:0:0:0:0:1]", + ], + "timestamp.us": Array [ + 1536763736368000, + ], + "transaction.id": Array [ + "a", + ], }, "docType": "span", "duration": 4694, @@ -179,16 +187,18 @@ Array [ "parent": Object { "color": "", "doc": Object { - "service": Object { - "name": "opbeans-java", - }, - "timestamp": Object { - "us": 1536763736366000, - }, - "transaction": Object { - "id": "a", - "name": "APIRestController#products", - }, + "service.name": Array [ + "opbeans-java", + ], + "timestamp.us": Array [ + 1536763736366000, + ], + "transaction.id": Array [ + "a", + ], + "transaction.name": Array [ + "APIRestController#products", + ], }, "docType": "transaction", "duration": 9480, @@ -215,19 +225,21 @@ Array [ Object { "color": "", "doc": Object { - "parent": Object { - "id": "b", - }, - "service": Object { - "name": "opbeans-java", - }, - "timestamp": Object { - "us": 1536763736369000, - }, - "transaction": Object { - "id": "c", - "name": "APIRestController#productsRemote", - }, + "parent.id": Array [ + "b", + ], + "service.name": Array [ + "opbeans-java", + ], + "timestamp.us": Array [ + 1536763736369000, + ], + "transaction.id": Array [ + "c", + ], + "transaction.name": Array [ + "APIRestController#productsRemote", + ], }, "docType": "transaction", "duration": 3581, @@ -240,22 +252,24 @@ Array [ "parent": Object { "color": "", "doc": Object { - "parent": Object { - "id": "a", - }, - "service": Object { - "name": "opbeans-java", - }, - "span": Object { - "id": "b", - "name": "GET [0:0:0:0:0:0:0:1]", - }, - "timestamp": Object { - "us": 1536763736368000, - }, - "transaction": Object { - "id": "a", - }, + "parent.id": Array [ + "a", + ], + "service.name": Array [ + "opbeans-java", + ], + "span.id": Array [ + "b", + ], + "span.name": Array [ + "GET [0:0:0:0:0:0:0:1]", + ], + "timestamp.us": Array [ + 1536763736368000, + ], + "transaction.id": Array [ + "a", + ], }, "docType": "span", "duration": 4694, @@ -268,16 +282,18 @@ Array [ "parent": Object { "color": "", "doc": Object { - "service": Object { - "name": "opbeans-java", - }, - "timestamp": Object { - "us": 1536763736366000, - }, - "transaction": Object { - "id": "a", - "name": "APIRestController#products", - }, + "service.name": Array [ + "opbeans-java", + ], + "timestamp.us": Array [ + 1536763736366000, + ], + "transaction.id": Array [ + "a", + ], + "transaction.name": Array [ + "APIRestController#products", + ], }, "docType": "transaction", "duration": 9480, @@ -311,22 +327,24 @@ Array [ Object { "color": "", "doc": Object { - "parent": Object { - "id": "c", - }, - "service": Object { - "name": "opbeans-java", - }, - "span": Object { - "id": "d", - "name": "SELECT", - }, - "timestamp": Object { - "us": 1536763736371000, - }, - "transaction": Object { - "id": "c", - }, + "parent.id": Array [ + "c", + ], + "service.name": Array [ + "opbeans-java", + ], + "span.id": Array [ + "d", + ], + "span.name": Array [ + "SELECT", + ], + "timestamp.us": Array [ + 1536763736371000, + ], + "transaction.id": Array [ + "c", + ], }, "docType": "span", "duration": 210, @@ -339,19 +357,21 @@ Array [ "parent": Object { "color": "", "doc": Object { - "parent": Object { - "id": "b", - }, - "service": Object { - "name": "opbeans-java", - }, - "timestamp": Object { - "us": 1536763736369000, - }, - "transaction": Object { - "id": "c", - "name": "APIRestController#productsRemote", - }, + "parent.id": Array [ + "b", + ], + "service.name": Array [ + "opbeans-java", + ], + "timestamp.us": Array [ + 1536763736369000, + ], + "transaction.id": Array [ + "c", + ], + "transaction.name": Array [ + "APIRestController#productsRemote", + ], }, "docType": "transaction", "duration": 3581, @@ -364,22 +384,24 @@ Array [ "parent": Object { "color": "", "doc": Object { - "parent": Object { - "id": "a", - }, - "service": Object { - "name": "opbeans-java", - }, - "span": Object { - "id": "b", - "name": "GET [0:0:0:0:0:0:0:1]", - }, - "timestamp": Object { - "us": 1536763736368000, - }, - "transaction": Object { - "id": "a", - }, + "parent.id": Array [ + "a", + ], + "service.name": Array [ + "opbeans-java", + ], + "span.id": Array [ + "b", + ], + "span.name": Array [ + "GET [0:0:0:0:0:0:0:1]", + ], + "timestamp.us": Array [ + 1536763736368000, + ], + "transaction.id": Array [ + "a", + ], }, "docType": "span", "duration": 4694, @@ -392,16 +414,18 @@ Array [ "parent": Object { "color": "", "doc": Object { - "service": Object { - "name": "opbeans-java", - }, - "timestamp": Object { - "us": 1536763736366000, - }, - "transaction": Object { - "id": "a", - "name": "APIRestController#products", - }, + "service.name": Array [ + "opbeans-java", + ], + "timestamp.us": Array [ + 1536763736366000, + ], + "transaction.id": Array [ + "a", + ], + "transaction.name": Array [ + "APIRestController#products", + ], }, "docType": "transaction", "duration": 9480, diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.test.ts b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.test.ts index 9d7d60944acdd..c7cf4d782246c 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.test.ts +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.test.ts @@ -6,7 +6,6 @@ */ import { groupBy } from 'lodash'; -import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { getClockSkew, @@ -23,8 +22,8 @@ import { IWaterfallNode, IWaterfallNodeFlatten, } from './waterfall_helpers'; -import { APMError } from '../../../../../../../../typings/es_schemas/ui/apm_error'; import { + WaterfallError, WaterfallSpan, WaterfallTransaction, } from '../../../../../../../../common/waterfall/typings'; @@ -32,108 +31,86 @@ import { describe('waterfall_helpers', () => { const hits = [ { - processor: { event: 'transaction' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { - duration: { us: 49660 }, - name: 'GET /api', - id: 'myTransactionId1', - }, - timestamp: { us: 1549324795784006 }, - } as Transaction, + 'processor.event': ['transaction'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.duration.us': [49660], + 'transaction.name': ['GET /api'], + 'transaction.id': ['myTransactionId1'], + 'timestamp.us': [1549324795784006], + } as unknown as WaterfallTransaction, { - parent: { id: 'mySpanIdA' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId2' }, - timestamp: { us: 1549324795825633 }, - span: { - duration: { us: 481 }, - name: 'SELECT FROM products', - id: 'mySpanIdB', - }, - } as Span, + 'parent.id': ['mySpanIdA'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId2'], + 'timestamp.us': [1549324795825633], + 'span.duration.us': [481], + 'span.name': ['SELECT FROM products'], + 'span.id': ['mySpanIdB'], + } as unknown as WaterfallSpan, { - parent: { id: 'myTransactionId2' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId2' }, - span: { - duration: { us: 6161 }, - name: 'Api::ProductsController#index', - id: 'mySpanIdA', - }, - timestamp: { us: 1549324795824504 }, - } as Span, + 'parent.id': ['myTransactionId2'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId2'], + 'span.duration.us': [6161], + 'span.name': ['Api::ProductsController#index'], + 'span.id': ['mySpanIdA'], + 'timestamp.us': [1549324795824504], + } as unknown as WaterfallSpan, { - parent: { id: 'mySpanIdA' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId2' }, - span: { - duration: { us: 532 }, - name: 'SELECT FROM product', - id: 'mySpanIdC', - }, - timestamp: { us: 1549324795827905 }, - } as Span, + 'parent.id': ['mySpanIdA'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId2'], + 'span.duration.us': [532], + 'span.name': ['SELECT FROM product'], + 'span.id': ['mySpanIdC'], + 'timestamp.us': [1549324795827905], + } as unknown as WaterfallSpan, { - parent: { id: 'myTransactionId1' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 47557 }, - name: 'GET opbeans-ruby:3000/api/products', - id: 'mySpanIdD', - }, - timestamp: { us: 1549324795785760 }, - } as Span, + 'parent.id': ['myTransactionId1'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [47557], + 'span.name': ['GET opbeans-ruby:3000/api/products'], + 'span.id': ['mySpanIdD'], + 'timestamp.us': [1549324795785760], + } as unknown as WaterfallSpan, { - parent: { id: 'mySpanIdD' }, - processor: { event: 'transaction' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { - duration: { us: 8634 }, - name: 'Api::ProductsController#index', - id: 'myTransactionId2', - marks: { - agent: { - domInteractive: 382, - domComplete: 383, - timeToFirstByte: 14, - }, - }, - }, - timestamp: { us: 1549324795823304 }, - } as unknown as Transaction, + 'parent.id': ['mySpanIdD'], + 'processor.event': ['transaction'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.duration.us': [8634], + 'transaction.name': ['Api::ProductsController#index'], + 'transaction.id': ['myTransactionId2'], + 'transaction.marks.agent.domInteractive': [382], + 'transaction.marks.agent.domComplete': [383], + 'transaction.marks.agent.timeToFirstByte': [14], + 'timestamp.us': [1549324795823304], + } as unknown as WaterfallTransaction, ]; const errorDocs = [ { - processor: { event: 'error' }, - parent: { id: 'myTransactionId1' }, - timestamp: { us: 1549324795810000 }, - trace: { id: 'myTraceId' }, - transaction: { id: 'myTransactionId1' }, - error: { - id: 'error1', - grouping_key: 'errorGroupingKey1', - log: { - message: 'error message', - }, - }, - service: { name: 'opbeans-ruby' }, - agent: { - name: 'ruby', - version: '2', - }, - } as unknown as APMError, + 'processor.event': ['error'], + 'parent.id': ['myTransactionId1'], + 'timestamp.us': [1549324795810000], + 'trace.id': ['myTraceId'], + 'transaction.id': ['myTransactionId1'], + 'error.id': ['error1'], + 'error.grouping_key': ['errorGroupingKey1'], + 'error.log.message': ['error message'], + 'service.name': ['opbeans-ruby'], + 'agent.name': ['ruby'], + 'agent.version': ['2'], + } as unknown as WaterfallError, ]; describe('getWaterfall', () => { @@ -207,69 +184,59 @@ describe('waterfall_helpers', () => { it('should reparent spans', () => { const traceItems = [ { - processor: { event: 'transaction' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { - duration: { us: 49660 }, - name: 'GET /api', - id: 'myTransactionId1', - }, - timestamp: { us: 1549324795784006 }, - } as Transaction, + 'processor.event': ['transaction'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.duration.us': [49660], + 'transaction.name': ['GET /api'], + 'transaction.id': ['myTransactionId1'], + 'timestamp.us': [1549324795784006], + } as WaterfallTransaction, { - parent: { id: 'mySpanIdD' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId1' }, - timestamp: { us: 1549324795825633 }, - span: { - duration: { us: 481 }, - name: 'SELECT FROM products', - id: 'mySpanIdB', - }, - child: { id: ['mySpanIdA', 'mySpanIdC'] }, - } as Span, + 'parent.id': ['mySpanIdD'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId1'], + 'timestamp.us': [1549324795825633], + 'span.duration.us': [481], + 'span.name': ['SELECT FROM products'], + 'span.id': ['mySpanIdB'], + 'child.id': ['mySpanIdA', 'mySpanIdC'], + } as unknown as WaterfallSpan, { - parent: { id: 'mySpanIdD' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 6161 }, - name: 'Api::ProductsController#index', - id: 'mySpanIdA', - }, - timestamp: { us: 1549324795824504 }, - } as Span, + 'parent.id': ['mySpanIdD'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [6161], + 'span.name': ['Api::ProductsController#index'], + 'span.id': ['mySpanIdA'], + 'timestamp.us': [1549324795824504], + } as WaterfallSpan, { - parent: { id: 'mySpanIdD' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 532 }, - name: 'SELECT FROM product', - id: 'mySpanIdC', - }, - timestamp: { us: 1549324795827905 }, - } as Span, + 'parent.id': ['mySpanIdD'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [532], + 'span.name': ['SELECT FROM product'], + 'span.id': ['mySpanIdC'], + 'timestamp.us': [1549324795827905], + } as WaterfallSpan, { - parent: { id: 'myTransactionId1' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 47557 }, - name: 'GET opbeans-ruby:3000/api/products', - id: 'mySpanIdD', - }, - timestamp: { us: 1549324795785760 }, - } as Span, + 'parent.id': ['myTransactionId1'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [47557], + 'span.name': ['GET opbeans-ruby:3000/api/products'], + 'span.id': ['mySpanIdD'], + 'timestamp.us': [1549324795785760], + } as WaterfallSpan, ]; const waterfall = getWaterfall({ traceItems: { @@ -325,69 +292,59 @@ describe('waterfall_helpers', () => { it("shouldn't reparent spans when child id isn't found", () => { const traceItems = [ { - processor: { event: 'transaction' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { - duration: { us: 49660 }, - name: 'GET /api', - id: 'myTransactionId1', - }, - timestamp: { us: 1549324795784006 }, - } as Transaction, + 'processor.event': ['transaction'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.duration.us': [49660], + 'transaction.name': ['GET /api'], + 'transaction.id': ['myTransactionId1'], + 'timestamp.us': [1549324795784006], + } as unknown as WaterfallTransaction, { - parent: { id: 'mySpanIdD' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId1' }, - timestamp: { us: 1549324795825633 }, - span: { - duration: { us: 481 }, - name: 'SELECT FROM products', - id: 'mySpanIdB', - }, - child: { id: ['incorrectId', 'mySpanIdC'] }, - } as Span, + 'parent.id': ['mySpanIdD'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId1'], + 'timestamp.us': [1549324795825633], + 'span.duration.us': [481], + 'span.name': ['SELECT FROM products'], + 'span.id': ['mySpanIdB'], + 'child.id': ['incorrectId', 'mySpanIdC'], + } as unknown as WaterfallSpan, { - parent: { id: 'mySpanIdD' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 6161 }, - name: 'Api::ProductsController#index', - id: 'mySpanIdA', - }, - timestamp: { us: 1549324795824504 }, - } as Span, + 'parent.id': ['mySpanIdD'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [6161], + 'span.name': ['Api::ProductsController#index'], + 'span.id': ['mySpanIdA'], + 'timestamp.us': [1549324795824504], + } as unknown as WaterfallSpan, { - parent: { id: 'mySpanIdD' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-ruby' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 532 }, - name: 'SELECT FROM product', - id: 'mySpanIdC', - }, - timestamp: { us: 1549324795827905 }, - } as Span, + 'parent.id': ['mySpanIdD'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-ruby'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [532], + 'span.name': ['SELECT FROM product'], + 'span.id': ['mySpanIdC'], + 'timestamp.us': [1549324795827905], + } as unknown as WaterfallSpan, { - parent: { id: 'myTransactionId1' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 47557 }, - name: 'GET opbeans-ruby:3000/api/products', - id: 'mySpanIdD', - }, - timestamp: { us: 1549324795785760 }, - } as Span, + 'parent.id': ['myTransactionId1'], + 'processor.event': ['span'], + ' trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [47557], + 'span.name': ['GET opbeans-ruby:3000/api/products'], + 'span.id': ['mySpanIdD'], + 'timestamp.us': [1549324795785760], + } as unknown as WaterfallSpan, ]; const waterfall = getWaterfall({ @@ -452,17 +409,13 @@ describe('waterfall_helpers', () => { { docType: 'span', doc: { - parent: { id: 'c' }, - service: { name: 'opbeans-java' }, - transaction: { - id: 'c', - }, - timestamp: { us: 1536763736371000 }, - span: { - id: 'd', - name: 'SELECT', - }, - } as Span, + 'parent.id': ['c'], + 'service.name': ['opbeans-java'], + 'transaction.id': ['c'], + 'timestamp.us': [1536763736371000], + 'span.id': ['d'], + 'span.name': ['SELECT'], + } as WaterfallSpan, id: 'd', parentId: 'c', duration: 210, @@ -478,17 +431,13 @@ describe('waterfall_helpers', () => { { docType: 'span', doc: { - parent: { id: 'a' }, - service: { name: 'opbeans-java' }, - transaction: { - id: 'a', - }, - timestamp: { us: 1536763736368000 }, - span: { - id: 'b', - name: 'GET [0:0:0:0:0:0:0:1]', - }, - } as Span, + 'parent.id': ['a'], + 'service.name': ['opbeans-java'], + 'transaction.id': ['a'], + 'timestamp.us': [1536763736368000], + 'span.id': ['b'], + 'span.name': ['GET [0:0:0:0:0:0:0:1]'], + } as WaterfallSpan, id: 'b', parentId: 'a', duration: 4694, @@ -504,17 +453,13 @@ describe('waterfall_helpers', () => { { docType: 'span', doc: { - parent: { id: 'a' }, - service: { name: 'opbeans-java' }, - transaction: { - id: 'a', - }, - timestamp: { us: 1536763736367000 }, - span: { - id: 'b2', - name: 'GET [0:0:0:0:0:0:0:1]', - }, - } as Span, + 'parent.id': ['a'], + 'service.name': ['opbeans-java'], + 'transaction.id': ['a'], + 'timestamp.us': [1536763736367000], + 'span.id': ['b2'], + 'span.name': ['GET [0:0:0:0:0:0:0:1]'], + } as WaterfallSpan, id: 'b2', parentId: 'a', duration: 4694, @@ -530,11 +475,12 @@ describe('waterfall_helpers', () => { { docType: 'transaction', doc: { - parent: { id: 'b' }, - service: { name: 'opbeans-java' }, - timestamp: { us: 1536763736369000 }, - transaction: { id: 'c', name: 'APIRestController#productsRemote' }, - } as Transaction, + 'parent.id': ['b'], + 'service.name': ['opbeans-java'], + 'timestamp.us': [1536763736369000], + 'transaction.id': ['c'], + 'transaction.name': ['APIRestController#productsRemote'], + } as WaterfallTransaction, id: 'c', parentId: 'b', duration: 3581, @@ -550,13 +496,11 @@ describe('waterfall_helpers', () => { { docType: 'transaction', doc: { - service: { name: 'opbeans-java' }, - timestamp: { us: 1536763736366000 }, - transaction: { - id: 'a', - name: 'APIRestController#products', - }, - } as Transaction, + 'service.name': ['opbeans-java'], + 'timestamp.us': [1536763736366000], + 'transaction.id': ['a'], + 'transaction.name': ['APIRestController#products'], + } as WaterfallTransaction, id: 'a', duration: 9480, offset: 0, @@ -582,8 +526,8 @@ describe('waterfall_helpers', () => { docType: 'transaction', id: 'a', doc: { - transaction: { id: 'a' }, - timestamp: { us: 10 }, + 'transaction.id': ['a'], + 'timestamp.us': [10], } as unknown as WaterfallTransaction, } as IWaterfallSpanOrTransaction, { @@ -591,11 +535,9 @@ describe('waterfall_helpers', () => { id: 'b', parentId: 'a', doc: { - span: { - id: 'b', - }, - parent: { id: 'a' }, - timestamp: { us: 20 }, + 'span.id': ['b'], + 'parent.id': ['a'], + 'timestamp.us': [20], } as unknown as WaterfallSpan, } as IWaterfallSpanOrTransaction, ]; @@ -610,7 +552,7 @@ describe('waterfall_helpers', () => { const child = { docType: 'transaction', doc: { - timestamp: { us: 0 }, + 'timestamp.us': [0], }, duration: 50, } as IWaterfallSpanOrTransaction; @@ -618,7 +560,7 @@ describe('waterfall_helpers', () => { const parent = { docType: 'transaction', doc: { - timestamp: { us: 100 }, + 'timestamp.us': [100], }, duration: 100, skew: 5, @@ -631,7 +573,7 @@ describe('waterfall_helpers', () => { const child = { docType: 'transaction', doc: { - timestamp: { us: 250 }, + 'timestamp.us': [250], }, duration: 50, } as IWaterfallSpanOrTransaction; @@ -639,7 +581,7 @@ describe('waterfall_helpers', () => { const parent = { docType: 'transaction', doc: { - timestamp: { us: 100 }, + 'timestamp.us': [100], }, duration: 100, skew: 5, @@ -652,7 +594,7 @@ describe('waterfall_helpers', () => { const child = { docType: 'transaction', doc: { - timestamp: { us: 150 }, + 'timestamp.us': [150], }, duration: 50, } as IWaterfallSpanOrTransaction; @@ -660,7 +602,7 @@ describe('waterfall_helpers', () => { const parent = { docType: 'transaction', doc: { - timestamp: { us: 100 }, + 'timestamp.us': [100], }, duration: 100, skew: 5, @@ -677,7 +619,7 @@ describe('waterfall_helpers', () => { const parent = { docType: 'span', doc: { - timestamp: { us: 100 }, + 'timestamp.us': [100], }, duration: 100, skew: 5, @@ -694,7 +636,7 @@ describe('waterfall_helpers', () => { const parent = { docType: 'transaction', doc: { - timestamp: { us: 100 }, + 'timestamp.us': [100], }, duration: 100, skew: 5, @@ -716,24 +658,18 @@ describe('waterfall_helpers', () => { describe('getOrphanTraceItemsCount', () => { const myTransactionItem = { - processor: { event: 'transaction' }, - trace: { id: 'myTrace' }, - transaction: { - id: 'myTransactionId1', - }, + 'processor.event': ['transaction'], + 'trace.id': ['myTrace'], + 'transaction.id': ['myTransactionId1'], } as WaterfallTransaction; it('should return missing items count: 0 if there are no orphan items', () => { const traceItems: Array = [ myTransactionItem, { - processor: { event: 'span' }, - span: { - id: 'mySpanId', - }, - parent: { - id: 'myTransactionId1', - }, + 'processor.event': ['span'], + 'span.id': ['mySpanId'], + 'parent.id': ['myTransactionId1'], } as WaterfallSpan, ]; expect(getOrphanTraceItemsCount(traceItems)).toBe(0); @@ -743,13 +679,9 @@ describe('waterfall_helpers', () => { const traceItems: Array = [ myTransactionItem, { - processor: { event: 'span' }, - span: { - id: 'myOrphanSpanId', - }, - parent: { - id: 'myNotExistingTransactionId1', - }, + 'processor.event': ['span'], + 'span.id': ['myOrphanSpanId'], + 'parent.id': ['myNotExistingTransactionId1'], } as WaterfallSpan, ]; expect(getOrphanTraceItemsCount(traceItems)).toBe(1); @@ -784,17 +716,15 @@ describe('waterfall_helpers', () => { item: { docType: 'transaction', doc: { - agent: { name: 'nodejs' }, - processor: { event: 'transaction' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { - duration: { us: 49660 }, - name: 'GET /api', - id: 'myTransactionId1', - type: 'request', - }, - timestamp: { us: 1549324795784006 }, + 'agent.name': ['nodejs'], + 'processor.event': ['transaction'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.duration.us': [49660], + 'transaction.name': ['GET /api'], + 'transaction.id': ['myTransactionId1'], + 'transaction.type': ['request'], + 'timestamp.us': [1549324795784006], }, id: 'myTransactionId1', duration: 49660, @@ -810,19 +740,17 @@ describe('waterfall_helpers', () => { item: { docType: 'span', doc: { - agent: { name: 'nodejs' }, - parent: { id: 'myTransactionId1' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 47557 }, - name: 'GET opbeans-ruby:3000/api/products', - id: 'mySpanIdD', - type: 'request', - }, - timestamp: { us: 1549324795785760 }, + 'agent.name': ['nodejs'], + 'parent.id': ['myTransactionId1'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [47557], + 'span.name': ['GET opbeans-ruby:3000/api/products'], + 'span.id': ['mySpanIdD'], + 'span.type': ['request'], + 'timestamp.us': [1549324795785760], }, id: 'mySpanIdD', parentId: 'myTransactionId1', @@ -912,19 +840,17 @@ describe('waterfall_helpers', () => { item: { docType: 'span', doc: { - agent: { name: 'nodejs' }, - parent: { id: 'myTransactionId1' }, - processor: { event: 'span' }, - trace: { id: 'myTraceId' }, - service: { name: 'opbeans-node' }, - transaction: { id: 'myTransactionId1' }, - span: { - duration: { us: 47557 }, - name: 'GET opbeans-ruby:3000/api/products', - id: 'mySpanIdD', - type: 'request', - }, - timestamp: { us: 1549324795785760 }, + 'agent.name': ['nodejs'], + 'parent.id': ['myTransactionId1'], + 'processor.event': ['span'], + 'trace.id': ['myTraceId'], + 'service.name': ['opbeans-node'], + 'transaction.id': ['myTransactionId1'], + 'span.duration.us': [47557], + 'span.name': ['GET opbeans-ruby:3000/api/products'], + 'span.id': ['mySpanIdD'], + 'span.type': ['request'], + 'timestamp.us': [1549324795785760], }, id: 'mySpanIdD', parentId: 'myTransactionId1', diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts index b9a8f1d8cd15c..718c9843ac9ec 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts @@ -8,6 +8,8 @@ import { euiPaletteColorBlind } from '@elastic/eui'; import { Dictionary, first, flatten, groupBy, isEmpty, sortBy, uniq } from 'lodash'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { dedot } from '@kbn/apm-synthtrace-client'; +import { SpanLink } from '@kbn/apm-types'; import { CriticalPathSegment } from '../../../../../../../../common/critical_path/types'; import type { APIReturnType } from '../../../../../../../services/rest/create_call_apm_api'; import type { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; @@ -16,7 +18,22 @@ import { WaterfallSpan, WaterfallTransaction, } from '../../../../../../../../common/waterfall/typings'; - +import { + PARENT_ID, + TIMESTAMP, + ERROR_ID, + TRANSACTION_ID, + TRANSACTION_DURATION, + SERVICE_NAME, + SPAN_LINKS_SPAN_ID, + SPAN_LINKS_TRACE_ID, + SPAN_ID, + SPAN_TYPE, + CHILD_ID, + SPAN_SUBTYPE, + PROCESSOR_EVENT, + SPAN_DURATION, +} from '../../../../../../../../common/es_fields/apm'; type TraceAPIResponse = APIReturnType<'GET /internal/apm/traces/{traceId}'>; const ROOT_ID = 'root'; @@ -113,11 +130,11 @@ export type IWaterfallNodeFlatten = Omit; function getLegendValues(transactionOrSpan: WaterfallTransaction | WaterfallSpan) { return { - [WaterfallLegendType.ServiceName]: transactionOrSpan.service.name, + [WaterfallLegendType.ServiceName]: transactionOrSpan[SERVICE_NAME]?.[0], [WaterfallLegendType.SpanType]: - transactionOrSpan.processor.event === ProcessorEvent.span - ? (transactionOrSpan as WaterfallSpan).span.subtype || - (transactionOrSpan as WaterfallSpan).span.type + transactionOrSpan[PROCESSOR_EVENT][0] === ProcessorEvent.span + ? (transactionOrSpan as WaterfallSpan)[SPAN_SUBTYPE]?.[0] || + (transactionOrSpan as WaterfallSpan)[SPAN_TYPE]?.[0] : '', }; } @@ -126,36 +143,58 @@ function getTransactionItem( transaction: WaterfallTransaction, linkedChildrenCount: number = 0 ): IWaterfallTransaction { + const spanLinks: SpanLink[] = []; + for (let i = 0; i < (transaction[SPAN_LINKS_TRACE_ID]?.length ?? 0); i++) { + spanLinks.push( + dedot( + { + 'trace.id': transaction[SPAN_LINKS_TRACE_ID]?.[i], + 'span.id': transaction[SPAN_LINKS_SPAN_ID]?.[i], + }, + {} + ) as SpanLink + ); + } return { docType: 'transaction', doc: transaction, - id: transaction.transaction.id, - parentId: transaction.parent?.id, - duration: transaction.transaction.duration.us, + id: transaction[TRANSACTION_ID][0], + parentId: transaction[PARENT_ID]?.[0], + duration: transaction[TRANSACTION_DURATION][0], offset: 0, skew: 0, legendValues: getLegendValues(transaction), color: '', spanLinksCount: { - linkedParents: transaction.span?.links?.length ?? 0, + linkedParents: spanLinks?.length ?? 0, linkedChildren: linkedChildrenCount, }, }; } function getSpanItem(span: WaterfallSpan, linkedChildrenCount: number = 0): IWaterfallSpan { + const spanLinks: SpanLink[] = []; + for (let i = 0; i < (span[SPAN_LINKS_TRACE_ID]?.length ?? 0); i++) { + spanLinks.push( + dedot( + { 'trace.id': span[SPAN_LINKS_TRACE_ID]?.[i], 'span.id': span[SPAN_LINKS_SPAN_ID]?.[i] }, + {} + ) as SpanLink + ); + } + return { docType: 'span', doc: span, - id: span.span.id, - parentId: span.parent?.id, - duration: span.span.duration.us, + id: span[SPAN_ID][0], + parentId: span[PARENT_ID]?.[0], + duration: span[SPAN_DURATION][0], offset: 0, skew: 0, legendValues: getLegendValues(span), color: '', spanLinksCount: { - linkedParents: span.span.links?.length ?? 0, + linkedParents: spanLinks?.length ?? 0, linkedChildren: linkedChildrenCount, }, }; @@ -166,22 +205,21 @@ function getErrorItem( items: IWaterfallItem[], entryWaterfallTransaction?: IWaterfallTransaction ): IWaterfallError { - const entryTimestamp = entryWaterfallTransaction?.doc.timestamp.us ?? 0; - const parent = items.find((waterfallItem) => waterfallItem.id === error.parent?.id) as + const entryTimestamp = entryWaterfallTransaction?.doc[TIMESTAMP][0] ?? 0; + const parent = items.find((waterfallItem) => waterfallItem.id === error[PARENT_ID]?.[0]) as | IWaterfallSpanOrTransaction | undefined; const errorItem: IWaterfallError = { docType: 'error', doc: error, - id: error.error.id, + id: error[ERROR_ID][0] as string, parent, parentId: parent?.id, - offset: error.timestamp.us - entryTimestamp, + offset: error[TIMESTAMP][0] - entryTimestamp, skew: 0, color: '', }; - return { ...errorItem, skew: getClockSkew(errorItem, parent), @@ -202,15 +240,14 @@ export function getClockSkew( return parentItem.skew; // transaction is the initial entry in a service. Calculate skew for this, and it will be propagated to all child spans case 'transaction': { - const parentStart = parentItem.doc.timestamp.us + parentItem.skew; + const parentStart = parentItem.doc[TIMESTAMP][0] + parentItem.skew; // determine if child starts before the parent - const offsetStart = parentStart - item.doc.timestamp.us; + const offsetStart = parentStart - item.doc[TIMESTAMP][0]; if (offsetStart > 0) { const latency = Math.max(parentItem.duration - item.duration, 0) / 2; return offsetStart + latency; } - // child transaction starts after parent thus no adjustment is needed return 0; } @@ -224,7 +261,8 @@ export function getOrderedWaterfallItems( if (!entryWaterfallTransaction) { return []; } - const entryTimestamp = entryWaterfallTransaction.doc.timestamp.us; + + const entryTimestamp = entryWaterfallTransaction.doc[TIMESTAMP][0]; const visitedWaterfallItemSet = new Set(); function getSortedChildren( @@ -236,11 +274,11 @@ export function getOrderedWaterfallItems( } visitedWaterfallItemSet.add(item); - const children = sortBy(childrenByParentId[item.id] || [], 'doc.timestamp.us'); + const children = sortBy(childrenByParentId[item.id] || [], (obj) => obj.doc['timestamp.us'][0]); item.parent = parentItem; // get offset from the beginning of trace - item.offset = item.doc.timestamp.us - entryTimestamp; + item.offset = item.doc[TIMESTAMP][0] - entryTimestamp; // move the item to the right if it starts before its parent item.skew = getClockSkew(item, parentItem); @@ -297,15 +335,15 @@ const getWaterfallItems = ( spanLinksCountById: TraceAPIResponse['traceItems']['spanLinksCountById'] ) => items.map((item) => { - const docType = item.processor.event; + const docType = item[PROCESSOR_EVENT][0]; switch (docType) { case 'span': { const span = item as WaterfallSpan; - return getSpanItem(span, spanLinksCountById[span.span.id]); + return getSpanItem(span, spanLinksCountById[span[SPAN_ID]?.[0]]); } case 'transaction': const transaction = item as WaterfallTransaction; - return getTransactionItem(transaction, spanLinksCountById[transaction.transaction.id]); + return getTransactionItem(transaction, spanLinksCountById[transaction[TRANSACTION_ID][0]]); } }); @@ -315,7 +353,7 @@ function reparentSpans(waterfallItems: IWaterfallSpanOrTransaction[]) { flatten( waterfallItems.map((waterfallItem) => { if (waterfallItem.docType === 'span') { - const childIds = waterfallItem.doc.child?.id ?? []; + const childIds = waterfallItem.doc[CHILD_ID] ?? []; return childIds.map((id) => [id, waterfallItem.id]); } return []; @@ -374,6 +412,7 @@ function getWaterfallErrors( if (!entryWaterfallTransaction) { return errorItems; } + const parentIdLookup = [...items, ...errorItems].reduce((map, { id, parentId }) => { map.set(id, parentId ?? ROOT_ID); return map; @@ -389,7 +428,7 @@ function getWaterfallErrors( */ function getErrorCountByParentId(errorDocs: TraceAPIResponse['traceItems']['errorDocs']) { return errorDocs.reduce>((acc, doc) => { - const parentId = doc.parent?.id; + const parentId = doc['parent.id']?.[0]; if (!parentId) { return acc; @@ -406,15 +445,15 @@ export const getOrphanTraceItemsCount = ( ) => { const waterfallItemsIds = new Set( traceDocs.map((doc) => - doc.processor.event === 'span' - ? (doc?.span as WaterfallSpan['span']).id - : doc?.transaction?.id + doc[PROCESSOR_EVENT][0] === 'span' + ? (doc as WaterfallSpan)[SPAN_ID][0] + : doc?.[TRANSACTION_ID]?.[0] ) ); let missingTraceItemsCounter = 0; traceDocs.some((item) => { - if (item.parent?.id && !waterfallItemsIds.has(item.parent.id)) { + if (item[PARENT_ID]?.[0] && !waterfallItemsIds.has(item[PARENT_ID]?.[0])) { missingTraceItemsCounter++; } }); @@ -438,14 +477,12 @@ export function getWaterfall(apiResponse: TraceAPIResponse): IWaterfall { orphanTraceItemsCount: 0, }; } - const errorCountByParentId = getErrorCountByParentId(traceItems.errorDocs); const waterfallItems: IWaterfallSpanOrTransaction[] = getWaterfallItems( traceItems.traceDocs, traceItems.spanLinksCountById ); - const childrenByParentId = getChildrenGroupedByParentId(reparentSpans(waterfallItems)); const entryWaterfallTransaction = getEntryWaterfallTransaction( diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx index 11d0f9bba9298..f6caebe5374b5 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx @@ -9,9 +9,29 @@ import { EuiBadge, EuiIcon, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { ReactNode, useRef, useEffect, useState } from 'react'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { EventOutcome } from '@kbn/apm-types'; import { useTheme } from '../../../../../../hooks/use_theme'; import { isMobileAgentName, isRumAgentName } from '../../../../../../../common/agent_name'; -import { TRACE_ID, TRANSACTION_ID } from '../../../../../../../common/es_fields/apm'; +import { + AGENT_NAME, + SPAN_COMPOSITE_COMPRESSION_STRATEGY, + SPAN_COMPOSITE_COUNT, + SPAN_COMPOSITE_SUM, + SPAN_DURATION, + SPAN_SYNC, + TRACE_ID, + SERVICE_NAME, + SPAN_NAME, + SPAN_SUBTYPE, + SPAN_TYPE, + SPAN_ACTION, + TRANSACTION_TYPE, + TRANSACTION_RESULT, + TRANSACTION_NAME, + TRANSACTION_ID, + FAAS_COLDSTART, + EVENT_OUTCOME, +} from '../../../../../../../common/es_fields/apm'; import { asDuration } from '../../../../../../../common/utils/formatters'; import { Margins } from '../../../../../shared/charts/timeline'; import { TruncateWithTooltip } from '../../../../../shared/truncate_with_tooltip'; @@ -126,7 +146,7 @@ interface IWaterfallItemProps { function PrefixIcon({ item }: { item: IWaterfallSpanOrTransaction }) { switch (item.docType) { case 'span': { - const spanType = item.doc.span.type || ''; + const spanType = item.doc[SPAN_TYPE]?.[0] || ''; // icon for database spans const isDbType = spanType.startsWith('db'); @@ -139,7 +159,7 @@ function PrefixIcon({ item }: { item: IWaterfallSpanOrTransaction }) { } case 'transaction': { // icon for RUM agent transactions - if (isRumAgentName(item.doc.agent.name)) { + if (isRumAgentName(item.doc[AGENT_NAME][0])) { return ; } @@ -159,7 +179,7 @@ interface SpanActionToolTipProps { function SpanActionToolTip({ item, children }: SpanActionToolTipProps) { if (item?.docType === 'span') { return ( - + <>{children} ); @@ -178,8 +198,8 @@ function Duration({ item }: { item: IWaterfallSpanOrTransaction }) { function HttpStatusCode({ item }: { item: IWaterfallSpanOrTransaction }) { // http status code for transactions of type 'request' const httpStatusCode = - item.docType === 'transaction' && item.doc.transaction.type === 'request' - ? item.doc.transaction.result + item.docType === 'transaction' && item.doc[TRANSACTION_TYPE][0] === 'request' + ? item.doc[TRANSACTION_RESULT] : undefined; if (!httpStatusCode) { @@ -192,11 +212,11 @@ function HttpStatusCode({ item }: { item: IWaterfallSpanOrTransaction }) { function NameLabel({ item }: { item: IWaterfallSpanOrTransaction }) { switch (item.docType) { case 'span': - let name = item.doc.span.name; - if (item.doc.span.composite) { + let name = item.doc[SPAN_NAME][0]; + if (item.doc[SPAN_COMPOSITE_COUNT]?.[0]) { const compositePrefix = - item.doc.span.composite.compression_strategy === 'exact_match' ? 'x' : ''; - name = `${item.doc.span.composite.count}${compositePrefix} ${name}`; + item.doc[SPAN_COMPOSITE_COMPRESSION_STRATEGY]?.[0] === 'exact_match' ? 'x' : ''; + name = `${item.doc[SPAN_COMPOSITE_COUNT][0]}${compositePrefix} ${name}`; } return ( @@ -206,7 +226,7 @@ function NameLabel({ item }: { item: IWaterfallSpanOrTransaction }) { case 'transaction': return ( -
{item.doc.transaction.name}
+
{item.doc[TRANSACTION_NAME][0]}
); } @@ -238,12 +258,11 @@ export function WaterfallItem({ const width = (item.duration / totalDuration) * widthFactor * 100; const left = (((item.offset + item.skew) / totalDuration) * widthFactor - widthFactor + 1) * 100; - - const isCompositeSpan = item.docType === 'span' && item.doc.span.composite; + const isCompositeSpan = item.docType === 'span' && item.doc[SPAN_COMPOSITE_COUNT]?.[0]; const itemBarStyle = getItemBarStyle(item, color, width, left); - const isServerlessColdstart = item.docType === 'transaction' && item.doc.faas?.coldstart; + const isServerlessColdstart = item.docType === 'transaction' && item.doc[FAAS_COLDSTART]?.[0]; const waterfallItemFlyoutTab = 'metadata'; @@ -289,7 +308,7 @@ export function WaterfallItem({ {item.docType === 'span' && ( - + )} e.stopPropagation()}> @@ -361,7 +380,7 @@ function RelatedErrors({ ); } - return ; + return ; } function getItemBarStyle( @@ -372,9 +391,14 @@ function getItemBarStyle( ): React.CSSProperties { let itemBarStyle = { left: `${left}%`, width: `${width}%` }; - if (item.docType === 'span' && item.doc.span.composite) { - const percNumItems = 100.0 / item.doc.span.composite.count; - const spanSumRatio = item.doc.span.composite.sum.us / item.doc.span.duration.us; + if ( + item.docType === 'span' && + item.doc[SPAN_COMPOSITE_COUNT]?.[0] && + item.doc[SPAN_COMPOSITE_SUM]?.[0] && + item.doc[SPAN_DURATION]?.[0] + ) { + const percNumItems = 100.0 / item.doc[SPAN_COMPOSITE_COUNT][0]; + const spanSumRatio = item.doc[SPAN_COMPOSITE_SUM]?.[0] / item.doc[SPAN_DURATION]?.[0]; const percDuration = percNumItems * spanSumRatio; itemBarStyle = { diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall_container.stories.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall_container.stories.tsx index bdc6382272dec..6e570e1abef3e 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall_container.stories.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall_container.stories.tsx @@ -71,21 +71,61 @@ export const Example: Story = () => { return doc['processor.event'] === ProcessorEvent.error; }); - const errorDocs = events.splice(errorEventId, 1); + const flatten = (obj: Record) => { + const _flatten = (o: Record, path: string[] = []): unknown[] => { + return Object.keys(o) + .map((k: string) => { + if (typeof o[k] === 'object' && o[k] !== null && !Array.isArray(o[k])) { + return _flatten(o[k] as Record, [...path, k]); + } else { + const key = [...path, k].join('.'); + return { [key]: o[k] }; + } + }) + .flat(); + }; + return Object.assign({}, ..._flatten(obj)); + }; + + const errorDocs = events.splice(errorEventId, 1).map((event: any) => { + if (event['error.exception']) { + event['error.exception'] = event['error.exception'][0]; + } + + event = flatten(event); + + Object.keys(event).forEach((key) => { + const item = event[key]; + if (!Array.isArray(item)) { + event[key] = [item]; + } + }); + return event as WaterfallError; + }); + + const entryTransaction = dedot(events[0]!, {}) as Transaction; const traceDocs = events .filter((event) => event['processor.event'] !== 'metric') - .map((event) => dedot(event, {}) as WaterfallTransaction | WaterfallSpan); + .map((event: any) => { + Object.keys(event).forEach((key) => { + const item = event[key]; + if (!Array.isArray(item)) { + event[key] = [item]; + } + }); + return event as WaterfallSpan | WaterfallTransaction; + }); + const traceItems = { exceedsMax: false, traceDocs, - errorDocs: errorDocs.map((error) => dedot(error, {}) as WaterfallError), + errorDocs, spanLinksCountById: {}, traceDocsTotal: traceDocs.length, maxTraceItems: 5000, }; - const entryTransaction = dedot(traceDocs[0]!, {}) as Transaction; const waterfall = getWaterfall({ traceItems, entryTransaction }); return ( diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.test.tsx index d71562e425e99..05271082531b7 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.test.tsx @@ -29,16 +29,13 @@ describe('ErrorMarker', () => { type: 'errorMark', verticalLine: true, error: { - trace: { id: '123' }, - transaction: { id: '456' }, - error: { - grouping_key: '123', - log: { - message: - "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.", - }, - }, - service: { name: 'bar' }, + 'trace.id': ['123'], + 'transaction.id': ['456'], + 'error.grouping_key': ['123'], + 'error.log.message': [ + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.", + ], + 'service.name': ['bar'], }, serviceColor: '#fff', } as unknown as ErrorMark; @@ -65,7 +62,7 @@ describe('ErrorMarker', () => { ); }); it('renders link with trace', () => { - const { transaction, ...withoutTransaction } = mark.error; + const { 'transaction.id': transaction, ...withoutTransaction } = mark.error; const newMark = { ...mark, error: withoutTransaction, @@ -75,7 +72,7 @@ describe('ErrorMarker', () => { expect(getKueryDecoded(errorLink.search)).toEqual('kuery=trace.id : "123"'); }); it('renders link with transaction', () => { - const { trace, ...withoutTrace } = mark.error; + const { 'trace.id': trace, ...withoutTrace } = mark.error; const newMark = { ...mark, error: withoutTrace, @@ -85,7 +82,11 @@ describe('ErrorMarker', () => { expect(getKueryDecoded(errorLink.search)).toEqual('kuery=transaction.id : "456"'); }); it('renders link without trance and transaction', () => { - const { trace, transaction, ...withoutTraceAndTransaction } = mark.error; + const { + 'trace.id': trace, + 'transaction.id': transaction, + ...withoutTraceAndTransaction + } = mark.error; const newMark = { ...mark, error: withoutTraceAndTransaction, @@ -95,7 +96,11 @@ describe('ErrorMarker', () => { expect(getKueryDecoded(errorLink.search)).toEqual('kuery='); }); it('truncates the error message text', () => { - const { trace, transaction, ...withoutTraceAndTransaction } = mark.error; + const { + 'trace.id': trace, + 'transaction.id': transaction, + ...withoutTraceAndTransaction + } = mark.error; const newMark = { ...mark, error: withoutTraceAndTransaction, @@ -111,12 +116,8 @@ describe('ErrorMarker', () => { ...mark, error: { ...mark.error, - error: { - grouping_key: '123', - log: { - message: 'Blah.', - }, - }, + 'error.grouping_key': ['123'], + 'error.log.message': ['Blah.'], }, } as unknown as ErrorMark; const component = openPopover(newMark); diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.tsx index faff0a073fe6b..dd2521ff7614d 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.tsx @@ -73,14 +73,16 @@ export function ErrorMarker({ mark }: Props) { const query = { kuery: [ - ...(error.trace?.id ? [`${TRACE_ID} : "${error.trace?.id}"`] : []), - ...(error.transaction?.id ? [`${TRANSACTION_ID} : "${error.transaction?.id}"`] : []), + ...(error['trace.id']?.[0] ? [`${TRACE_ID} : "${error['trace.id']?.[0]}"`] : []), + ...(error['transaction.id']?.[0] + ? [`${TRANSACTION_ID} : "${error['transaction.id']?.[0]}"`] + : []), ].join(' and '), rangeFrom, rangeTo, }; - const errorMessage = error.error.log?.message || error.error.exception?.[0]?.message; + const errorMessage = error['error.log.message']?.[0] || error['error.exception.message']?.[0]; const truncatedErrorMessage = truncateMessage(errorMessage); return ( @@ -99,14 +101,14 @@ export function ErrorMarker({ mark }: Props) { } /> diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/index.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/index.test.tsx index cadf1078937c6..3e439a9fcd1af 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/index.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/index.test.tsx @@ -30,10 +30,10 @@ describe('Marker', () => { type: 'errorMark', verticalLine: true, error: { - trace: { id: '123' }, - transaction: { id: '456' }, - error: { grouping_key: '123' }, - service: { name: 'bar' }, + 'trace.id': ['123'], + 'transaction.id': ['456'], + 'error.grouping_key': ['123'], + 'service.name': ['bar'], }, serviceColor: '#fff', } as ErrorMark; diff --git a/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts b/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts index 319582f61b664..3b91a73e9edcc 100644 --- a/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts +++ b/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts @@ -101,7 +101,7 @@ describe('data telemetry collection tasks', () => { // a fixed date range. .mockReturnValueOnce({ hits: { - hits: [{ _source: { '@timestamp': new Date().toISOString() } }], + hits: [{ fields: { '@timestamp': [new Date().toISOString()] } }], }, total: { value: 1, @@ -314,7 +314,7 @@ describe('data telemetry collection tasks', () => { ? { hits: { total: { value: 1 } } } : { hits: { - hits: [{ _source: { '@timestamp': 1 } }], + hits: [{ fields: { '@timestamp': [1] } }], }, } ); diff --git a/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts index db6a6a918177a..33c72eab31714 100644 --- a/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts +++ b/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts @@ -184,6 +184,8 @@ export const tasks: TelemetryTask[] = [ await telemetryClient.search({ index: indices.transaction, body: { + _source: false, + fields: ['@timestamp'], timeout, query: { bool: { @@ -197,13 +199,13 @@ export const tasks: TelemetryTask[] = [ }, }, }) - ).hits.hits[0] as { _source: { '@timestamp': string } }; + ).hits.hits[0] as unknown as { fields: { '@timestamp': string[] } }; if (!lastTransaction) { return {}; } - const end = new Date(lastTransaction._source['@timestamp']).getTime() - 5 * 60 * 1000; + const end = new Date(lastTransaction.fields['@timestamp'][0]).getTime() - 5 * 60 * 1000; const start = end - 60 * 1000; @@ -514,14 +516,15 @@ export const tasks: TelemetryTask[] = [ sort: { '@timestamp': 'asc', }, - _source: ['@timestamp'], + _source: false, + fields: ['@timestamp'], }, }) : null; - const event = retainmentResponse?.hits.hits[0]?._source as + const event = retainmentResponse?.hits.hits[0]?.fields as | { - '@timestamp': number; + '@timestamp': number[]; } | undefined; @@ -535,7 +538,7 @@ export const tasks: TelemetryTask[] = [ ? { retainment: { [processorEvent]: { - ms: new Date().getTime() - new Date(event['@timestamp']).getTime(), + ms: new Date().getTime() - new Date(event['@timestamp'][0]).getTime(), }, }, } diff --git a/x-pack/plugins/observability_solution/apm/server/routes/dependencies/get_top_dependency_spans.ts b/x-pack/plugins/observability_solution/apm/server/routes/dependencies/get_top_dependency_spans.ts index 1c8448579806f..2f3d64bf8dbd8 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/dependencies/get_top_dependency_spans.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/dependencies/get_top_dependency_spans.ts @@ -98,7 +98,7 @@ export async function getTopDependencySpans({ ], }, }, - _source: [ + fields: [ SPAN_ID, TRACE_ID, TRANSACTION_ID, @@ -116,7 +116,7 @@ export async function getTopDependencySpans({ const transactionIds = spans.map((span) => span.transaction!.id); - const transactions = ( + const transactions: Partial<{ [key: string]: any }> = ( await apmEventClient.search('get_transactions_for_dependency_spans', { apm: { events: [ProcessorEvent.transaction], @@ -129,19 +129,17 @@ export async function getTopDependencySpans({ filter: [...termsQuery(TRANSACTION_ID, ...transactionIds)], }, }, - _source: [TRANSACTION_ID, TRANSACTION_TYPE, TRANSACTION_NAME], + fields: [TRANSACTION_ID, TRANSACTION_TYPE, TRANSACTION_NAME], sort: { '@timestamp': 'desc', }, }, }) - ).hits.hits.map((hit) => hit._source); - - const transactionsById = keyBy(transactions, (transaction) => transaction.transaction.id); + ).hits.hits.map((hit) => hit.fields); + const transactionsById = keyBy(transactions, (transaction) => transaction?.['transaction.id']); return spans.map((span): DependencySpan => { - const transaction = maybe(transactionsById[span.transaction!.id]); - + const transaction: Partial> = maybe(transactionsById[span.transaction!.id]); return { '@timestamp': new Date(span['@timestamp']).getTime(), spanId: span.span.id, @@ -152,8 +150,8 @@ export async function getTopDependencySpans({ traceId: span.trace.id, outcome: (span.event?.outcome || EventOutcome.unknown) as EventOutcome, transactionId: span.transaction!.id, - transactionType: transaction?.transaction.type, - transactionName: transaction?.transaction.name, + transactionType: (transaction?.['transaction.type'])[0], + transactionName: (transaction?.['transaction.name'])[0], }; }); } diff --git a/x-pack/plugins/observability_solution/apm/server/routes/services/annotations/get_derived_service_annotations.ts b/x-pack/plugins/observability_solution/apm/server/routes/services/annotations/get_derived_service_annotations.ts index e766d56c44ae4..b10627346e57f 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/services/annotations/get_derived_service_annotations.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/services/annotations/get_derived_service_annotations.ts @@ -73,6 +73,8 @@ export async function getDerivedServiceAnnotations({ events: [getProcessorEventForTransactions(searchAggregatedTransactions)], }, body: { + _source: false, + fields: ['@timestamp'], track_total_hits: false, size: 1, query: { @@ -86,7 +88,9 @@ export async function getDerivedServiceAnnotations({ }, }); - const firstSeen = new Date(response.hits.hits[0]._source['@timestamp']).getTime(); + const firstSeen = new Date( + response.hits.hits[0].fields['@timestamp']?.[0] as string + ).getTime(); if (!isFiniteNumber(firstSeen)) { throw new Error('First seen for version was unexpectedly undefined or null.'); diff --git a/x-pack/plugins/observability_solution/apm/server/routes/traces/__snapshots__/queries.test.ts.snap b/x-pack/plugins/observability_solution/apm/server/routes/traces/__snapshots__/queries.test.ts.snap index d64c33a421e19..69897541fb890 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/traces/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/observability_solution/apm/server/routes/traces/__snapshots__/queries.test.ts.snap @@ -11,8 +11,9 @@ Object { ], }, "body": Object { - "_source": Array [ - "timestamp.us", + "_source": false, + "fields": Array [ + "@timestamp", "trace.id", "transaction.id", "parent.id", diff --git a/x-pack/plugins/observability_solution/apm/server/routes/traces/get_trace_items.ts b/x-pack/plugins/observability_solution/apm/server/routes/traces/get_trace_items.ts index d38a49745653a..ee016a715fe22 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/traces/get_trace_items.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/traces/get_trace_items.ts @@ -32,7 +32,8 @@ import { SPAN_COMPOSITE_SUM, SPAN_DURATION, SPAN_ID, - SPAN_LINKS, + SPAN_LINKS_SPAN_ID, + SPAN_LINKS_TRACE_ID, SPAN_NAME, SPAN_SUBTYPE, SPAN_SYNC, @@ -94,10 +95,11 @@ export async function getTraceItems({ ], }, body: { + _source: false, track_total_hits: false, size: 1000, - _source: [ - TIMESTAMP, + fields: [ + '@timestamp', TRACE_ID, TRANSACTION_ID, PARENT_ID, @@ -133,8 +135,8 @@ export async function getTraceItems({ const traceDocsTotal = traceResponse.total; const exceedsMax = traceDocsTotal > maxTraceItems; - const traceDocs = traceResponse.hits.map((hit) => hit._source); - const errorDocs = errorResponse.hits.hits.map((hit) => hit._source); + const traceDocs = traceResponse.hits.map((hit: any) => hit.fields); + const errorDocs: WaterfallError[] = errorResponse.hits.hits.map((hit: any) => hit.fields); return { exceedsMax, @@ -227,7 +229,7 @@ async function getTraceDocsPerPage({ track_total_hits: true, size, search_after: searchAfter, - _source: [ + fields: [ TIMESTAMP, TRACE_ID, PARENT_ID, @@ -248,7 +250,8 @@ async function getTraceDocsPerPage({ SPAN_ACTION, SPAN_NAME, SPAN_DURATION, - SPAN_LINKS, + SPAN_LINKS_TRACE_ID, + SPAN_LINKS_SPAN_ID, SPAN_COMPOSITE_COUNT, SPAN_COMPOSITE_COMPRESSION_STRATEGY, SPAN_COMPOSITE_SUM, @@ -289,7 +292,6 @@ async function getTraceDocsPerPage({ }, body, }); - return { hits: res.hits.hits, total: res.hits.total.value, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap b/x-pack/plugins/observability_solution/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap index deb1dec096f08..03f95333988a7 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/observability_solution/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap @@ -300,17 +300,18 @@ Object { exports[`transaction queries fetches transaction trace samples 1`] = ` Object { - "_source": Array [ - "transaction.id", - "trace.id", - "@timestamp", - ], "apm": Object { "events": Array [ "transaction", ], }, "body": Object { + "_source": false, + "fields": Array [ + "transaction.id", + "trace.id", + "@timestamp", + ], "query": Object { "bool": Object { "filter": Array [ diff --git a/x-pack/plugins/observability_solution/apm/server/routes/transactions/trace_samples/index.ts b/x-pack/plugins/observability_solution/apm/server/routes/transactions/trace_samples/index.ts index 191250d3781ee..5695dce42fce3 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/transactions/trace_samples/index.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/transactions/trace_samples/index.ts @@ -81,8 +81,9 @@ export async function getTraceSamples({ apm: { events: [ProcessorEvent.transaction], }, - _source: [TRANSACTION_ID, TRACE_ID, '@timestamp'], body: { + _source: false, + fields: [TRANSACTION_ID, TRACE_ID, '@timestamp'], track_total_hits: false, query: { bool: { @@ -111,9 +112,9 @@ export async function getTraceSamples({ const traceSamples = response.hits.hits.map((hit) => ({ score: hit._score, - timestamp: hit._source['@timestamp'], - transactionId: hit._source.transaction.id, - traceId: hit._source.trace.id, + timestamp: hit.fields['@timestamp']?.[0] as string, + transactionId: hit.fields[TRANSACTION_ID]?.[0] as string, + traceId: hit.fields[TRACE_ID]?.[0] as string, })); return { traceSamples }; diff --git a/x-pack/test/apm_api_integration/tests/traces/find_traces.spec.ts b/x-pack/test/apm_api_integration/tests/traces/find_traces.spec.ts index 369490ae06d44..b1f578da2cabc 100644 --- a/x-pack/test/apm_api_integration/tests/traces/find_traces.spec.ts +++ b/x-pack/test/apm_api_integration/tests/traces/find_traces.spec.ts @@ -184,8 +184,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { const mapped = traces.map((traceDocs) => { return sortBy(traceDocs, '@timestamp') - .filter((doc) => doc.processor.event === 'transaction') - .map((doc) => doc.service.name); + .filter((doc) => doc['processor.event']?.[0] === 'transaction') + .map((doc) => doc['service.name']?.[0]); }); expect(mapped).to.eql([ diff --git a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts index de07f3664104c..bbb2ae6237cc1 100644 --- a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts +++ b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts @@ -116,7 +116,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns some errors', () => { expect(traces.traceItems.errorDocs.length).to.be.greaterThan(0); - expect(traces.traceItems.errorDocs[0].error.exception?.[0].message).to.eql( + expect(traces.traceItems.errorDocs[0]['error.exception.message']?.[0]).to.eql( '[ResponseError] index_not_found_exception' ); }); @@ -125,11 +125,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(traces.traceItems.traceDocs.length).to.be.greaterThan(0); expect( traces.traceItems.traceDocs.map((item) => { - if (item.span && 'name' in item.span) { - return item.span.name; + if (item['span.name']) { + return item['span.name']?.[0]; } - if (item.transaction && 'name' in item.transaction) { - return item.transaction.name; + if (item['transaction.name']?.[0]) { + return item['transaction.name']?.[0]; } }) ).to.eql(['GET /apple 🍏', 'get_green_apple_🍏']);