diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx index acd8c5f4d57d3c..daebcdd8078cdc 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx @@ -73,11 +73,7 @@ export function TransactionDistribution({ const { urlParams } = useUrlParams(); - const { - waterfall, - exceedsMax, - status: waterfallStatus, - } = useWaterfallFetcher(); + const { waterfall, status: waterfallStatus } = useWaterfallFetcher(); const markerCurrentTransaction = waterfall.entryWaterfallTransaction?.doc.transaction.duration.us; @@ -215,7 +211,6 @@ export function TransactionDistribution({ urlParams={urlParams} waterfall={waterfall} isLoading={waterfallStatus === FETCH_STATUS.LOADING} - exceedsMax={exceedsMax} traceSamples={traceSamples} /> diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts b/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts index 6bde8edcc250a4..c015051b3c9557 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts @@ -13,9 +13,9 @@ import { useTimeRange } from '../../../hooks/use_time_range'; import { getWaterfall } from './waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers'; const INITIAL_DATA = { - root: undefined, - trace: { items: [], exceedsMax: false, errorDocs: [] }, - errorsPerTransaction: {}, + errorDocs: [], + traceDocs: [], + exceedsMax: false, }; export function useWaterfallFetcher() { @@ -51,5 +51,5 @@ export function useWaterfallFetcher() { transactionId, ]); - return { waterfall, status, error, exceedsMax: data.trace.exceedsMax }; + return { waterfall, status, error }; } diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/ErrorCount.test.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/ErrorCount.test.tsx deleted file mode 100644 index b8476200abfe3e..00000000000000 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/ErrorCount.test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { fireEvent, render } from '@testing-library/react'; -import React from 'react'; -import { expectTextsInDocument } from '../../../../utils/testHelpers'; -import { ErrorCount } from './ErrorCount'; - -describe('ErrorCount', () => { - it('shows singular error message', () => { - const component = render(); - expectTextsInDocument(component, ['1 Error']); - }); - it('shows plural error message', () => { - const component = render(); - expectTextsInDocument(component, ['2 Errors']); - }); - it('prevents click propagation', () => { - const mock = jest.fn(); - const { getByText } = render( - - ); - fireEvent( - getByText('1 Error'), - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }) - ); - expect(mock).not.toHaveBeenCalled(); - }); -}); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/ErrorCount.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/ErrorCount.tsx deleted file mode 100644 index c66cff89eb0c1d..00000000000000 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/ErrorCount.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiText, EuiTextColor } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; - -interface Props { - count: number; -} - -export function ErrorCount({ count }: Props) { - return ( - -

- { - e.stopPropagation(); - }} - > - {i18n.translate('xpack.apm.transactionDetails.errorCount', { - defaultMessage: - '{errorCount, number} {errorCount, plural, one {Error} other {Errors}}', - values: { errorCount: count }, - })} - -

-
- ); -} diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/TransactionTabs.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/TransactionTabs.tsx index d402a2b19b5a93..0e01c44b3fb5a5 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/TransactionTabs.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/TransactionTabs.tsx @@ -21,15 +21,9 @@ interface Props { transaction: Transaction; urlParams: ApmUrlParams; waterfall: IWaterfall; - exceedsMax: boolean; } -export function TransactionTabs({ - transaction, - urlParams, - waterfall, - exceedsMax, -}: Props) { +export function TransactionTabs({ transaction, urlParams, waterfall }: Props) { const history = useHistory(); const tabs = [timelineTab, metadataTab, logsTab]; const currentTab = @@ -65,7 +59,6 @@ export function TransactionTabs({ @@ -99,19 +92,11 @@ const logsTab = { function TimelineTabContent({ urlParams, waterfall, - exceedsMax, }: { urlParams: ApmUrlParams; waterfall: IWaterfall; - exceedsMax: boolean; }) { - return ( - - ); + return ; } function MetadataTabContent({ transaction }: { transaction: Transaction }) { diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx index b7feb917d2184f..df3d7750a8dda2 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx @@ -30,7 +30,6 @@ import { useApmParams } from '../../../../hooks/use_apm_params'; interface Props { urlParams: ApmUrlParams; waterfall: IWaterfall; - exceedsMax: boolean; isLoading: boolean; traceSamples: TraceSample[]; } @@ -38,7 +37,6 @@ interface Props { export function WaterfallWithSummary({ urlParams, waterfall, - exceedsMax, isLoading, traceSamples, }: Props) { @@ -125,7 +123,7 @@ export function WaterfallWithSummary({ @@ -135,7 +133,6 @@ export function WaterfallWithSummary({ transaction={entryTransaction} urlParams={urlParams} waterfall={waterfall} - exceedsMax={exceedsMax} /> ); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/accordion_waterfall.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/accordion_waterfall.tsx index 1935d373caf797..e4a851b890a7c5 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/accordion_waterfall.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/accordion_waterfall.tsx @@ -22,8 +22,7 @@ interface AccordionWaterfallProps { level: number; duration: IWaterfall['duration']; waterfallItemId?: string; - errorsPerTransaction: IWaterfall['errorsPerTransaction']; - childrenByParentId: Record; + waterfall: IWaterfall; onToggleEntryTransaction?: () => void; timelineMargins: Margins; onClickWaterfallItem: (item: IWaterfallSpanOrTransaction) => void; @@ -96,9 +95,8 @@ export function AccordionWaterfall(props: AccordionWaterfallProps) { item, level, duration, - childrenByParentId, + waterfall, waterfallItemId, - errorsPerTransaction, timelineMargins, onClickWaterfallItem, onToggleEntryTransaction, @@ -106,12 +104,8 @@ export function AccordionWaterfall(props: AccordionWaterfallProps) { const nextLevel = level + 1; - const errorCount = - item.docType === 'transaction' - ? errorsPerTransaction[item.doc.transaction.id] - : 0; - - const children = childrenByParentId[item.id] || []; + const children = waterfall.childrenByParentId[item.id] || []; + const errorCount = waterfall.getErrorCount(item.id); // To indent the items creating the parent/child tree const marginLeftLevel = 8 * level; @@ -121,7 +115,7 @@ export function AccordionWaterfall(props: AccordionWaterfallProps) { buttonClassName={`button_${item.id}`} key={item.id} id={item.id} - hasError={errorCount > 0} + hasError={item.doc.event?.outcome === 'failure'} marginLeftLevel={marginLeftLevel} childrenCount={children.length} buttonContent={ @@ -152,16 +146,11 @@ export function AccordionWaterfall(props: AccordionWaterfallProps) { > {children.map((child) => ( ))} diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/failure_badge.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/failure_badge.tsx new file mode 100644 index 00000000000000..0aaf4b4a10a681 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/failure_badge.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiBadge, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useTheme } from '../../../../../../hooks/use_theme'; + +import { euiStyled } from '../../../../../../../../../../src/plugins/kibana_react/common'; + +const ResetLineHeight = euiStyled.span` + line-height: initial; +`; + +export function FailureBadge({ outcome }: { outcome?: 'success' | 'failure' }) { + const theme = useTheme(); + + if (outcome !== 'failure') { + return null; + } + + return ( + + + failure + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/index.tsx index d31af783e08c23..3932a02c9d974d 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/index.tsx @@ -21,7 +21,6 @@ import { WaterfallFlyout } from './waterfall_flyout'; import { IWaterfall, IWaterfallItem, - IWaterfallSpanOrTransaction, } from './waterfall_helpers/waterfall_helpers'; const Container = euiStyled.div` @@ -61,9 +60,8 @@ const WaterfallItemsContainer = euiStyled.div` interface Props { waterfallItemId?: string; waterfall: IWaterfall; - exceedsMax: boolean; } -export function Waterfall({ waterfall, exceedsMax, waterfallItemId }: Props) { +export function Waterfall({ waterfall, waterfallItemId }: Props) { const history = useHistory(); const [isAccordionOpen, setIsAccordionOpen] = useState(true); const itemContainerHeight = 58; // TODO: This is a nasty way to calculate the height of the svg element. A better approach should be found @@ -74,37 +72,10 @@ export function Waterfall({ waterfall, exceedsMax, waterfallItemId }: Props) { const agentMarks = getAgentMarks(waterfall.entryWaterfallTransaction?.doc); const errorMarks = getErrorMarks(waterfall.errorItems); - function renderItems( - childrenByParentId: Record - ) { - const { entryWaterfallTransaction } = waterfall; - if (!entryWaterfallTransaction) { - return null; - } - return ( - - toggleFlyout({ history, item }) - } - onToggleEntryTransaction={() => setIsAccordionOpen((isOpen) => !isOpen)} - /> - ); - } - return ( - {exceedsMax && ( + {waterfall.apiResponse.exceedsMax && ( - {renderItems(waterfall.childrenByParentId)} + {!waterfall.entryWaterfallTransaction ? null : ( + + toggleFlyout({ history, item }) + } + onToggleEntryTransaction={() => + setIsAccordionOpen((isOpen) => !isOpen) + } + /> + )} diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/span_flyout/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/span_flyout/index.tsx index 50fc56dff7f85a..4921dfe0606c37 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/span_flyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/span_flyout/index.tsx @@ -35,8 +35,9 @@ import { HttpInfoSummaryItem } from '../../../../../../shared/Summary/http_info_ import { TimestampTooltip } from '../../../../../../shared/TimestampTooltip'; import { ResponsiveFlyout } from '../ResponsiveFlyout'; import { SyncBadge } from '../sync_badge'; -import { DatabaseContext } from './database_context'; +import { SpanDatabase } from './span_db'; import { StickySpanProperties } from './sticky_span_properties'; +import { FailureBadge } from '../failure_badge'; function formatType(type: string) { switch (type) { @@ -73,13 +74,11 @@ function getSpanTypes(span: Span) { }; } -const SpanBadge = euiStyled(EuiBadge)` - display: inline-block; - margin-right: ${({ theme }) => theme.eui.euiSizeXS}; -`; - -const HttpInfoContainer = euiStyled('div')` - margin-right: ${({ theme }) => theme.eui.euiSizeXS}; +const ContainerWithMarginRight = euiStyled.div` + /* add margin to all direct descendants */ + & > * { + margin-right: ${({ theme }) => theme.eui.euiSizeXS}; + } `; interface Props { @@ -101,7 +100,7 @@ export function SpanFlyout({ const stackframes = span.span.stacktrace; const codeLanguage = parentTransaction?.service.language?.name; - const dbContext = span.span.db; + const spanDb = span.span.db; const httpContext = span.span.http; const spanTypes = getSpanTypes(span); const spanHttpStatusCode = httpContext?.response?.status_code; @@ -173,15 +172,13 @@ export function SpanFlyout({ /> )} , - <> + {spanHttpUrl && ( - - - + )} - {spanTypes.spanType} + {spanTypes.spanType} {spanTypes.spanSubtype && ( - - {spanTypes.spanSubtype} - + {spanTypes.spanSubtype} )} {spanTypes.spanAction && ( @@ -210,15 +205,18 @@ export function SpanFlyout({ { defaultMessage: 'Action' } )} > - {spanTypes.spanAction} + {spanTypes.spanAction} )} + + + - , + , ]} /> - + ['db']; + spanDb?: NonNullable['db']; } -export function DatabaseContext({ dbContext }: Props) { +export function SpanDatabase({ spanDb }: Props) { const theme = useTheme(); const dbSyntaxLineHeight = theme.eui.euiSizeL; const previewHeight = 240; // 10 * dbSyntaxLineHeight - if (!dbContext || !dbContext.statement) { + if (!spanDb || !spanDb.statement) { return null; } - if (dbContext.type !== 'sql') { - return {dbContext.statement}; + if (spanDb.type !== 'sql') { + return {spanDb.statement}; } return ( @@ -73,7 +73,7 @@ export function DatabaseContext({ dbContext }: Props) { overflowX: 'scroll', }} > - {dbContext.statement} + {spanDb.statement} diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/sync_badge.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/sync_badge.tsx index cfc369fa12a269..fe74f3d51c8bc3 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/sync_badge.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/sync_badge.tsx @@ -8,12 +8,6 @@ import { EuiBadge } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { euiStyled } from '../../../../../../../../../../src/plugins/kibana_react/common'; - -const SpanBadge = euiStyled(EuiBadge)` - display: inline-block; - margin-right: ${({ theme }) => theme.eui.euiSizeXS}; -`; export interface SyncBadgeProps { /** @@ -26,19 +20,19 @@ export function SyncBadge({ sync }: SyncBadgeProps) { switch (sync) { case true: return ( - + {i18n.translate('xpack.apm.transactionDetails.syncBadgeBlocking', { defaultMessage: 'blocking', })} - + ); case false: return ( - + {i18n.translate('xpack.apm.transactionDetails.syncBadgeAsync', { defaultMessage: 'async', })} - + ); default: return null; diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_flyout.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_flyout.tsx index 4163388db1ec00..948f790848e8f5 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_flyout.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_flyout.tsx @@ -55,7 +55,7 @@ export function WaterfallFlyout({ rootTransactionDuration={ waterfall.rootTransaction?.transaction.duration.us } - errorCount={waterfall.errorsPerTransaction[currentItem.id]} + errorCount={waterfall.getErrorCount(currentItem.id)} /> ); default: diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap index 8905162daada29..b1ea74c3eb0c0d 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap @@ -912,11 +912,7 @@ Object { "skew": 0, }, ], - "errorsCount": 1, - "errorsPerTransaction": Object { - "myTransactionId1": 2, - "myTransactionId2": 3, - }, + "getErrorCount": [Function], "items": Array [ Object { "color": "", @@ -2188,11 +2184,7 @@ Object { "skew": 0, }, "errorItems": Array [], - "errorsCount": 0, - "errorsPerTransaction": Object { - "myTransactionId1": 2, - "myTransactionId2": 3, - }, + "getErrorCount": [Function], "items": Array [ Object { "color": "", diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.test.ts b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.test.ts index 34933a3a6f8ecf..3e0c5034f37a24 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.test.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.test.ts @@ -129,44 +129,39 @@ describe('waterfall_helpers', () => { it('should return full waterfall', () => { const entryTransactionId = 'myTransactionId1'; - const errorsPerTransaction = { - myTransactionId1: 2, - myTransactionId2: 3, + const apiResp = { + traceDocs: hits, + errorDocs, + exceedsMax: false, }; - const waterfall = getWaterfall( - { - trace: { items: hits, errorDocs, exceedsMax: false }, - errorsPerTransaction, - }, - entryTransactionId - ); + const waterfall = getWaterfall(apiResp, entryTransactionId); + const { apiResponse, ...waterfallRest } = waterfall; expect(waterfall.items.length).toBe(6); expect(waterfall.items[0].id).toBe('myTransactionId1'); expect(waterfall.errorItems.length).toBe(1); - expect(waterfall.errorsCount).toEqual(1); - expect(waterfall).toMatchSnapshot(); + expect(waterfall.getErrorCount('myTransactionId1')).toEqual(1); + expect(waterfallRest).toMatchSnapshot(); + expect(apiResponse).toEqual(apiResp); }); it('should return partial waterfall', () => { const entryTransactionId = 'myTransactionId2'; - const errorsPerTransaction = { - myTransactionId1: 2, - myTransactionId2: 3, + const apiResp = { + traceDocs: hits, + errorDocs, + exceedsMax: false, }; - const waterfall = getWaterfall( - { - trace: { items: hits, errorDocs, exceedsMax: false }, - errorsPerTransaction, - }, - entryTransactionId - ); + const waterfall = getWaterfall(apiResp, entryTransactionId); + + const { apiResponse, ...waterfallRest } = waterfall; expect(waterfall.items.length).toBe(4); expect(waterfall.items[0].id).toBe('myTransactionId2'); expect(waterfall.errorItems.length).toBe(0); - expect(waterfall.errorsCount).toEqual(0); - expect(waterfall).toMatchSnapshot(); + expect(waterfall.getErrorCount('myTransactionId2')).toEqual(0); + expect(waterfallRest).toMatchSnapshot(); + expect(apiResponse).toEqual(apiResp); }); it('should reparent spans', () => { const traceItems = [ @@ -238,8 +233,9 @@ describe('waterfall_helpers', () => { const entryTransactionId = 'myTransactionId1'; const waterfall = getWaterfall( { - trace: { items: traceItems, errorDocs: [], exceedsMax: false }, - errorsPerTransaction: {}, + traceDocs: traceItems, + errorDocs: [], + exceedsMax: false, }, entryTransactionId ); @@ -247,6 +243,7 @@ describe('waterfall_helpers', () => { id: item.id, parentId: item.parent?.id, }); + expect(waterfall.items.length).toBe(5); expect(getIdAndParentId(waterfall.items[0])).toEqual({ id: 'myTransactionId1', @@ -269,8 +266,9 @@ describe('waterfall_helpers', () => { parentId: 'mySpanIdB', }); expect(waterfall.errorItems.length).toBe(0); - expect(waterfall.errorsCount).toEqual(0); + expect(waterfall.getErrorCount('myTransactionId1')).toEqual(0); }); + it("shouldn't reparent spans when child id isn't found", () => { const traceItems = [ { @@ -341,8 +339,9 @@ describe('waterfall_helpers', () => { const entryTransactionId = 'myTransactionId1'; const waterfall = getWaterfall( { - trace: { items: traceItems, errorDocs: [], exceedsMax: false }, - errorsPerTransaction: {}, + traceDocs: traceItems, + errorDocs: [], + exceedsMax: false, }, entryTransactionId ); @@ -372,7 +371,7 @@ describe('waterfall_helpers', () => { parentId: 'mySpanIdB', }); expect(waterfall.errorItems.length).toBe(0); - expect(waterfall.errorsCount).toEqual(0); + expect(waterfall.getErrorCount('myTransactionId1')).toEqual(0); }); }); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.ts index b6e427e8cc0a10..9501ad1839d46a 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.ts @@ -6,7 +6,7 @@ */ import { euiPaletteColorBlind } from '@elastic/eui'; -import { first, flatten, groupBy, isEmpty, sortBy, sum, uniq } from 'lodash'; +import { first, flatten, groupBy, isEmpty, sortBy, uniq } from 'lodash'; import { APIReturnType } from '../../../../../../../services/rest/createCallApmApi'; import { APMError } from '../../../../../../../../typings/es_schemas/ui/apm_error'; import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; @@ -35,10 +35,10 @@ export interface IWaterfall { duration: number; items: IWaterfallItem[]; childrenByParentId: Record; - errorsPerTransaction: TraceAPIResponse['errorsPerTransaction']; - errorsCount: number; + getErrorCount: (parentId: string) => number; legends: IWaterfallLegend[]; errorItems: IWaterfallError[]; + apiResponse: TraceAPIResponse; } interface IWaterfallSpanItemBase @@ -80,7 +80,8 @@ export type IWaterfallSpanOrTransaction = | IWaterfallTransaction | IWaterfallSpan; -export type IWaterfallItem = IWaterfallSpanOrTransaction | IWaterfallError; +// export type IWaterfallItem = IWaterfallSpanOrTransaction | IWaterfallError; +export type IWaterfallItem = IWaterfallSpanOrTransaction; export interface IWaterfallLegend { type: WaterfallLegendType; @@ -264,7 +265,7 @@ const getWaterfallDuration = (waterfallItems: IWaterfallItem[]) => 0 ); -const getWaterfallItems = (items: TraceAPIResponse['trace']['items']) => +const getWaterfallItems = (items: TraceAPIResponse['traceDocs']) => items.map((item) => { const docType = item.processor.event; switch (docType) { @@ -332,7 +333,7 @@ function isInEntryTransaction( } function getWaterfallErrors( - errorDocs: TraceAPIResponse['trace']['errorDocs'], + errorDocs: TraceAPIResponse['errorDocs'], items: IWaterfallItem[], entryWaterfallTransaction?: IWaterfallTransaction ) { @@ -358,24 +359,44 @@ function getWaterfallErrors( ); } +// map parent.id to the number of errors +/* + { 'parentId': 2 } + */ +function getErrorCountByParentId(errorDocs: TraceAPIResponse['errorDocs']) { + return errorDocs.reduce>((acc, doc) => { + const parentId = doc.parent?.id; + + if (!parentId) { + return acc; + } + + acc[parentId] = (acc[parentId] ?? 0) + 1; + + return acc; + }, {}); +} + export function getWaterfall( - { trace, errorsPerTransaction }: TraceAPIResponse, + apiResponse: TraceAPIResponse, entryTransactionId?: Transaction['transaction']['id'] ): IWaterfall { - if (isEmpty(trace.items) || !entryTransactionId) { + if (isEmpty(apiResponse.traceDocs) || !entryTransactionId) { return { + apiResponse, duration: 0, items: [], - errorsPerTransaction, - errorsCount: sum(Object.values(errorsPerTransaction)), legends: [], errorItems: [], childrenByParentId: {}, + getErrorCount: () => 0, }; } + const errorCountByParentId = getErrorCountByParentId(apiResponse.errorDocs); + const waterfallItems: IWaterfallSpanOrTransaction[] = getWaterfallItems( - trace.items + apiResponse.traceDocs ); const childrenByParentId = getChildrenGroupedByParentId( @@ -392,7 +413,7 @@ export function getWaterfall( entryWaterfallTransaction ); const errorItems = getWaterfallErrors( - trace.errorDocs, + apiResponse.errorDocs, items, entryWaterfallTransaction ); @@ -402,14 +423,14 @@ export function getWaterfall( const legends = getLegends(items); return { + apiResponse, entryWaterfallTransaction, rootTransaction, duration, items, - errorsPerTransaction, - errorsCount: errorItems.length, legends, errorItems, childrenByParentId: getChildrenGroupedByParentId(items), + getErrorCount: (parentId: string) => errorCountByParentId[parentId] ?? 0, }; } diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_item.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_item.tsx index 3af010fb30b864..1a4fa4f5fe8360 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_item.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_item.tsx @@ -5,18 +5,23 @@ * 2.0. */ -import { EuiIcon, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui'; +import { EuiBadge, EuiIcon, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { ReactNode } from 'react'; +import { useTheme } from '../../../../../../hooks/use_theme'; import { euiStyled } from '../../../../../../../../../../src/plugins/kibana_react/common'; import { isRumAgentName } from '../../../../../../../common/agent_name'; -import { TRACE_ID } from '../../../../../../../common/elasticsearch_fieldnames'; +import { + TRACE_ID, + TRANSACTION_ID, +} from '../../../../../../../common/elasticsearch_fieldnames'; import { asDuration } from '../../../../../../../common/utils/formatters'; import { Margins } from '../../../../../shared/charts/Timeline'; -import { ErrorOverviewLink } from '../../../../../shared/Links/apm/ErrorOverviewLink'; -import { ErrorCount } from '../../ErrorCount'; import { SyncBadge } from './sync_badge'; import { IWaterfallSpanOrTransaction } from './waterfall_helpers/waterfall_helpers'; +import { FailureBadge } from './failure_badge'; +import { useApmRouter } from '../../../../../../hooks/use_apm_router'; +import { useApmParams } from '../../../../../../hooks/use_apm_params'; type ItemType = 'transaction' | 'span' | 'error'; @@ -181,15 +186,6 @@ export function WaterfallItem({ const width = (item.duration / totalDuration) * 100; const left = ((item.offset + item.skew) / totalDuration) * 100; - const tooltipContent = i18n.translate( - 'xpack.apm.transactionDetails.errorsOverviewLinkTooltip', - { - values: { errorCount }, - defaultMessage: - '{errorCount, plural, one {View 1 related error} other {View # related errors}}', - } - ); - const isCompositeSpan = item.docType === 'span' && item.doc.span.composite; const itemBarStyle = getItemBarStyle(item, color, width, left); @@ -216,27 +212,56 @@ export function WaterfallItem({ - {errorCount > 0 && item.docType === 'transaction' ? ( - - - - - - ) : null} + + {item.docType === 'span' && } ); } +function RelatedErrors({ + item, + errorCount, +}: { + item: IWaterfallSpanOrTransaction; + errorCount: number; +}) { + const apmRouter = useApmRouter(); + const theme = useTheme(); + const { query } = useApmParams('/services/:serviceName/transactions/view'); + + const href = apmRouter.link(`/services/:serviceName/errors`, { + path: { serviceName: item.doc.service.name }, + query: { + ...query, + kuery: `${TRACE_ID} : "${item.doc.trace.id}" and ${TRANSACTION_ID} : "${item.doc.transaction?.id}"`, + }, + }); + + if (errorCount > 0) { + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events +
e.stopPropagation()}> + + {i18n.translate('xpack.apm.waterfall.errorCount', { + defaultMessage: + '{errorCount, plural, one {View related error} other {View # related errors}}', + values: { errorCount }, + })} + +
+ ); + } + + return ; +} + function getItemBarStyle( item: IWaterfallSpanOrTransaction, color: string, diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/WaterfallContainer.stories.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/WaterfallContainer.stories.tsx index f8abff2c9609ce..a03b7b29f96662 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/WaterfallContainer.stories.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/WaterfallContainer.stories.tsx @@ -8,7 +8,6 @@ import React, { ComponentType } from 'react'; import { MemoryRouter } from 'react-router-dom'; import { MockApmPluginContextWrapper } from '../../../../../context/apm_plugin/mock_apm_plugin_context'; -import { APIReturnType } from '../../../../../services/rest/createCallApmApi'; import { WaterfallContainer } from './index'; import { getWaterfall } from './Waterfall/waterfall_helpers/waterfall_helpers'; import { @@ -19,8 +18,6 @@ import { urlParams, } from './waterfallContainer.stories.data'; -type TraceAPIResponse = APIReturnType<'GET /api/apm/traces/{traceId}'>; - export default { title: 'app/TransactionDetails/Waterfall', component: WaterfallContainer, @@ -36,57 +33,24 @@ export default { }; export function Example() { - const waterfall = getWaterfall( - simpleTrace as TraceAPIResponse, - '975c8d5bfd1dd20b' - ); - return ( - - ); + const waterfall = getWaterfall(simpleTrace, '975c8d5bfd1dd20b'); + return ; } export function WithErrors() { - const waterfall = getWaterfall( - (traceWithErrors as unknown) as TraceAPIResponse, - '975c8d5bfd1dd20b' - ); - return ( - - ); + const waterfall = getWaterfall(traceWithErrors, '975c8d5bfd1dd20b'); + return ; } export function ChildStartsBeforeParent() { const waterfall = getWaterfall( - traceChildStartBeforeParent as TraceAPIResponse, + traceChildStartBeforeParent, '975c8d5bfd1dd20b' ); - return ( - - ); + return ; } export function InferredSpans() { - const waterfall = getWaterfall( - inferredSpans as TraceAPIResponse, - 'f2387d37260d00bd' - ); - return ( - - ); + const waterfall = getWaterfall(inferredSpans, 'f2387d37260d00bd'); + return ; } diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/index.tsx index f3949fcfb03d5b..6ef7651a1e4048 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/index.tsx @@ -19,14 +19,9 @@ import { useApmServiceContext } from '../../../../../context/apm_service/use_apm interface Props { urlParams: ApmUrlParams; waterfall: IWaterfall; - exceedsMax: boolean; } -export function WaterfallContainer({ - urlParams, - waterfall, - exceedsMax, -}: Props) { +export function WaterfallContainer({ urlParams, waterfall }: Props) { const { serviceName } = useApmServiceContext(); if (!waterfall) { @@ -83,7 +78,6 @@ export function WaterfallContainer({ ); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfallContainer.stories.data.ts b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfallContainer.stories.data.ts index 80ae2978498b31..1e58c1bd00a281 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfallContainer.stories.data.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfallContainer.stories.data.ts @@ -7,6 +7,7 @@ import type { Location } from 'history'; import type { ApmUrlParams } from '../../../../../context/url_params_context/types'; +import { APIReturnType } from '../../../../../services/rest/createCallApmApi'; export const location = { pathname: '/services/opbeans-go/transactions/view', @@ -15,6 +16,8 @@ export const location = { hash: '', } as Location; +type TraceAPIResponse = APIReturnType<'GET /api/apm/traces/{traceId}'>; + export const urlParams = { start: '2020-03-22T15:16:38.742Z', end: '2020-03-23T15:16:38.742Z', @@ -32,2296 +35,2265 @@ export const urlParams = { } as ApmUrlParams; export const simpleTrace = { - trace: { - items: [ - { - container: { - id: + traceDocs: [ + { + container: { + id: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + process: { + pid: 6, + title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', + ppid: 1, + }, + agent: { + name: 'java', + ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', + version: '1.14.1-SNAPSHOT', + }, + internal: { + sampler: { + value: 46, + }, + }, + source: { + ip: '172.19.0.13', + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: '172.19.0.9', + full: 'http://172.19.0.9:3000/api/orders', + }, + observer: { + hostname: 'f37f48d8b60b', + id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', + ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', + type: 'apm-server', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.785Z', + ecs: { + version: '1.4.0', + }, + service: { + node: { + name: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', }, - process: { - pid: 6, - title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', - ppid: 1, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '10.0.2', }, - agent: { - name: 'java', - ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', - version: '1.14.1-SNAPSHOT', + language: { + name: 'Java', + version: '10.0.2', }, - internal: { - sampler: { - value: 46, - }, + version: 'None', + }, + host: { + hostname: '4cf84d094553', + os: { + platform: 'Linux', + }, + ip: '172.19.0.9', + name: '4cf84d094553', + architecture: 'amd64', + }, + http: { + request: { + headers: { + Accept: ['*/*'], + 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], + Host: ['172.19.0.9:3000'], + 'Accept-Encoding': ['gzip, deflate'], + }, + method: 'get', + socket: { + encrypted: false, + remote_address: '172.19.0.13', + }, + body: { + original: '[REDACTED]', + }, + }, + response: { + headers: { + 'Transfer-Encoding': ['chunked'], + Date: ['Mon, 23 Mar 2020 15:04:28 GMT'], + 'Content-Type': ['application/json;charset=ISO-8859-1'], + }, + status_code: 200, + finished: true, + headers_sent: true, + }, + version: '1.1', + }, + client: { + ip: '172.19.0.13', + }, + transaction: { + duration: { + us: 18842, + }, + result: 'HTTP 2xx', + name: 'DispatcherServlet#doGet', + id: '49809ad3c26adf74', + span_count: { + dropped: 0, + started: 1, + }, + type: 'request', + sampled: true, + }, + user_agent: { + original: 'Python/3.7 aiohttp/3.3.2', + name: 'Other', + device: { + name: 'Other', }, - source: { - ip: '172.19.0.13', - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: '172.19.0.9', - full: 'http://172.19.0.9:3000/api/orders', - }, - observer: { - hostname: 'f37f48d8b60b', - id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', - ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.785Z', - ecs: { - version: '1.4.0', - }, - service: { - node: { - name: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '10.0.2', - }, - language: { - name: 'Java', - version: '10.0.2', - }, - version: 'None', + }, + timestamp: { + us: 1584975868785000, + }, + }, + { + parent: { + id: 'fc107f7b556eb49b', + }, + agent: { + name: 'go', + version: '1.7.2', + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: 'opbeans-go', + full: 'http://opbeans-go:3000/api/orders', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.787Z', + service: { + node: { + name: + 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', + }, + environment: 'production', + framework: { + name: 'gin', + version: 'v1.4.0', + }, + name: 'opbeans-go', + runtime: { + name: 'gc', + version: 'go1.14.1', + }, + language: { + name: 'go', + version: 'go1.14.1', }, - host: { - hostname: '4cf84d094553', - os: { - platform: 'Linux', - }, - ip: '172.19.0.9', - name: '4cf84d094553', - architecture: 'amd64', + version: 'None', + }, + transaction: { + duration: { + us: 16597, + }, + result: 'HTTP 2xx', + name: 'GET /api/orders', + id: '975c8d5bfd1dd20b', + span_count: { + dropped: 0, + started: 1, + }, + type: 'request', + sampled: true, + }, + timestamp: { + us: 1584975868787052, + }, + }, + { + parent: { + id: 'daae24d83c269918', + }, + agent: { + name: 'python', + version: '5.5.2', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + timestamp: { + us: 1584975868788603, + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: 'opbeans-go', + full: 'http://opbeans-go:3000/api/orders', + }, + '@timestamp': '2020-03-23T15:04:28.788Z', + service: { + node: { + name: + 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', }, - http: { - request: { - headers: { - Accept: ['*/*'], - 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], - Host: ['172.19.0.9:3000'], - 'Accept-Encoding': ['gzip, deflate'], - }, - method: 'get', - socket: { - encrypted: false, - remote_address: '172.19.0.13', - }, - body: { - original: '[REDACTED]', - }, - }, - response: { - headers: { - 'Transfer-Encoding': ['chunked'], - Date: ['Mon, 23 Mar 2020 15:04:28 GMT'], - 'Content-Type': ['application/json;charset=ISO-8859-1'], - }, - status_code: 200, - finished: true, - headers_sent: true, - }, - version: '1.1', + environment: 'production', + framework: { + name: 'django', + version: '2.1.13', }, - client: { - ip: '172.19.0.13', + name: 'opbeans-python', + runtime: { + name: 'CPython', + version: '3.6.10', }, - transaction: { - duration: { - us: 18842, - }, - result: 'HTTP 2xx', - name: 'DispatcherServlet#doGet', - id: '49809ad3c26adf74', - span_count: { - dropped: 0, - started: 1, - }, - type: 'request', - sampled: true, + language: { + name: 'python', + version: '3.6.10', }, - user_agent: { - original: 'Python/3.7 aiohttp/3.3.2', - name: 'Other', - device: { - name: 'Other', - }, + version: 'None', + }, + transaction: { + result: 'HTTP 2xx', + duration: { + us: 14648, + }, + name: 'GET opbeans.views.orders', + span_count: { + dropped: 0, + started: 1, + }, + id: '6fb0ff7365b87298', + type: 'request', + sampled: true, + }, + }, + { + container: { + id: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + parent: { + id: '49809ad3c26adf74', + }, + process: { + pid: 6, + title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', + ppid: 1, + }, + agent: { + name: 'java', + ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', + version: '1.14.1-SNAPSHOT', + }, + internal: { + sampler: { + value: 44, + }, + }, + destination: { + address: 'opbeans-go', + port: 3000, + }, + processor: { + name: 'transaction', + event: 'span', + }, + observer: { + hostname: 'f37f48d8b60b', + id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', + type: 'apm-server', + ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.785Z', + ecs: { + version: '1.4.0', + }, + service: { + node: { + name: + '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '10.0.2', }, - timestamp: { - us: 1584975868785000, + language: { + name: 'Java', + version: '10.0.2', }, + version: 'None', + }, + host: { + hostname: '4cf84d094553', + os: { + platform: 'Linux', + }, + ip: '172.19.0.9', + name: '4cf84d094553', + architecture: 'amd64', + }, + connection: { + hash: + "{service.environment:'production'}/{service.name:'opbeans-java'}/{span.subtype:'http'}/{destination.address:'opbeans-go'}/{span.type:'external'}", }, - { - parent: { - id: 'fc107f7b556eb49b', + transaction: { + id: '49809ad3c26adf74', + }, + timestamp: { + us: 1584975868785273, + }, + span: { + duration: { + us: 17530, }, - agent: { - name: 'go', - version: '1.7.2', - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: 'opbeans-go', - full: 'http://opbeans-go:3000/api/orders', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.787Z', - service: { - node: { - name: - 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', - }, - environment: 'production', - framework: { - name: 'gin', - version: 'v1.4.0', - }, - name: 'opbeans-go', - runtime: { - name: 'gc', - version: 'go1.14.1', - }, - language: { - name: 'go', - version: 'go1.14.1', + subtype: 'http', + name: 'GET opbeans-go', + destination: { + service: { + resource: 'opbeans-go:3000', + name: 'http://opbeans-go:3000', + type: 'external', }, - version: 'None', }, - transaction: { - duration: { - us: 16597, + http: { + response: { + status_code: 200, }, - result: 'HTTP 2xx', - name: 'GET /api/orders', - id: '975c8d5bfd1dd20b', - span_count: { - dropped: 0, - started: 1, + url: { + original: 'http://opbeans-go:3000/api/orders', }, - type: 'request', - sampled: true, }, - timestamp: { - us: 1584975868787052, + id: 'fc107f7b556eb49b', + type: 'external', + }, + }, + { + parent: { + id: '975c8d5bfd1dd20b', + }, + agent: { + name: 'go', + version: '1.7.2', + }, + processor: { + name: 'transaction', + event: 'span', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.787Z', + service: { + node: { + name: + 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', + }, + environment: 'production', + name: 'opbeans-go', + runtime: { + name: 'gc', + version: 'go1.14.1', + }, + language: { + name: 'go', + version: 'go1.14.1', }, + version: 'None', }, - { - parent: { - id: 'daae24d83c269918', + transaction: { + id: '975c8d5bfd1dd20b', + }, + timestamp: { + us: 1584975868787174, + }, + span: { + duration: { + us: 16250, }, - agent: { - name: 'python', - version: '5.5.2', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - timestamp: { - us: 1584975868788603, - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: 'opbeans-go', - full: 'http://opbeans-go:3000/api/orders', - }, - '@timestamp': '2020-03-23T15:04:28.788Z', - service: { - node: { - name: - 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', - }, - environment: 'production', - framework: { - name: 'django', - version: '2.1.13', - }, - name: 'opbeans-python', - runtime: { - name: 'CPython', - version: '3.6.10', - }, - language: { - name: 'python', - version: '3.6.10', + subtype: 'http', + destination: { + service: { + resource: 'opbeans-python:3000', + name: 'http://opbeans-python:3000', + type: 'external', }, - version: 'None', }, - transaction: { - result: 'HTTP 2xx', - duration: { - us: 14648, + name: 'GET opbeans-python:3000', + http: { + response: { + status_code: 200, }, - name: 'GET opbeans.views.orders', - span_count: { - dropped: 0, - started: 1, + url: { + original: 'http://opbeans-python:3000/api/orders', }, - id: '6fb0ff7365b87298', - type: 'request', - sampled: true, }, + id: 'daae24d83c269918', + type: 'external', }, - { - container: { - id: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + { + container: { + id: 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', + }, + parent: { + id: '6fb0ff7365b87298', + }, + agent: { + name: 'python', + version: '5.5.2', + }, + processor: { + name: 'transaction', + event: 'span', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.790Z', + service: { + node: { + name: + 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', }, - parent: { - id: '49809ad3c26adf74', + environment: 'production', + framework: { + name: 'django', + version: '2.1.13', }, - process: { - pid: 6, - title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', - ppid: 1, + name: 'opbeans-python', + runtime: { + name: 'CPython', + version: '3.6.10', }, - agent: { - name: 'java', - ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', - version: '1.14.1-SNAPSHOT', + language: { + name: 'python', + version: '3.6.10', }, - internal: { - sampler: { - value: 44, - }, + version: 'None', + }, + transaction: { + id: '6fb0ff7365b87298', + }, + timestamp: { + us: 1584975868790080, + }, + span: { + duration: { + us: 2519, }, + subtype: 'postgresql', + name: 'SELECT FROM opbeans_order', destination: { - address: 'opbeans-go', - port: 3000, - }, - processor: { - name: 'transaction', - event: 'span', - }, - observer: { - hostname: 'f37f48d8b60b', - id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', - type: 'apm-server', - ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.785Z', - ecs: { - version: '1.4.0', - }, - service: { - node: { - name: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '10.0.2', - }, - language: { - name: 'Java', - version: '10.0.2', + service: { + resource: 'postgresql', + name: 'postgresql', + type: 'db', }, - version: 'None', }, - host: { - hostname: '4cf84d094553', - os: { - platform: 'Linux', - }, - ip: '172.19.0.9', - name: '4cf84d094553', - architecture: 'amd64', + action: 'query', + id: 'c9407abb4d08ead1', + type: 'db', + sync: true, + db: { + statement: + 'SELECT "opbeans_order"."id", "opbeans_order"."customer_id", "opbeans_customer"."full_name", "opbeans_order"."created_at" FROM "opbeans_order" INNER JOIN "opbeans_customer" ON ("opbeans_order"."customer_id" = "opbeans_customer"."id") LIMIT 1000', + type: 'sql', }, - connection: { - hash: - "{service.environment:'production'}/{service.name:'opbeans-java'}/{span.subtype:'http'}/{destination.address:'opbeans-go'}/{span.type:'external'}", + }, + }, + ], + exceedsMax: false, + errorDocs: [], +} as TraceAPIResponse; + +export const traceWithErrors = ({ + traceDocs: [ + { + container: { + id: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + process: { + pid: 6, + title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', + ppid: 1, + }, + agent: { + name: 'java', + ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', + version: '1.14.1-SNAPSHOT', + }, + internal: { + sampler: { + value: 46, }, - transaction: { - id: '49809ad3c26adf74', + }, + source: { + ip: '172.19.0.13', + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: '172.19.0.9', + full: 'http://172.19.0.9:3000/api/orders', + }, + observer: { + hostname: 'f37f48d8b60b', + id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', + ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', + type: 'apm-server', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.785Z', + ecs: { + version: '1.4.0', + }, + service: { + node: { + name: + '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', }, - timestamp: { - us: 1584975868785273, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '10.0.2', }, - span: { - duration: { - us: 17530, - }, - subtype: 'http', - name: 'GET opbeans-go', - destination: { - service: { - resource: 'opbeans-go:3000', - name: 'http://opbeans-go:3000', - type: 'external', - }, - }, - http: { - response: { - status_code: 200, - }, - url: { - original: 'http://opbeans-go:3000/api/orders', - }, - }, - id: 'fc107f7b556eb49b', - type: 'external', + language: { + name: 'Java', + version: '10.0.2', }, + version: 'None', + }, + host: { + hostname: '4cf84d094553', + os: { + platform: 'Linux', + }, + ip: '172.19.0.9', + name: '4cf84d094553', + architecture: 'amd64', + }, + http: { + request: { + headers: { + Accept: ['*/*'], + 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], + Host: ['172.19.0.9:3000'], + 'Accept-Encoding': ['gzip, deflate'], + }, + method: 'get', + socket: { + encrypted: false, + remote_address: '172.19.0.13', + }, + body: { + original: '[REDACTED]', + }, + }, + response: { + headers: { + 'Transfer-Encoding': ['chunked'], + Date: ['Mon, 23 Mar 2020 15:04:28 GMT'], + 'Content-Type': ['application/json;charset=ISO-8859-1'], + }, + status_code: 200, + finished: true, + headers_sent: true, + }, + version: '1.1', + }, + client: { + ip: '172.19.0.13', + }, + transaction: { + duration: { + us: 18842, + }, + result: 'HTTP 2xx', + name: 'DispatcherServlet#doGet', + id: '49809ad3c26adf74', + span_count: { + dropped: 0, + started: 1, + }, + type: 'request', + sampled: true, }, - { - parent: { - id: '975c8d5bfd1dd20b', + user_agent: { + original: 'Python/3.7 aiohttp/3.3.2', + name: 'Other', + device: { + name: 'Other', }, - agent: { + }, + timestamp: { + us: 1584975868785000, + }, + }, + { + parent: { + id: 'fc107f7b556eb49b', + }, + agent: { + name: 'go', + version: '1.7.2', + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: 'opbeans-go', + full: 'http://opbeans-go:3000/api/orders', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.787Z', + service: { + node: { + name: + 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', + }, + environment: 'production', + framework: { + name: 'gin', + version: 'v1.4.0', + }, + name: 'opbeans-go', + runtime: { + name: 'gc', + version: 'go1.14.1', + }, + language: { name: 'go', - version: '1.7.2', - }, - processor: { - name: 'transaction', - event: 'span', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.787Z', - service: { - node: { - name: - 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', - }, - environment: 'production', - name: 'opbeans-go', - runtime: { - name: 'gc', - version: 'go1.14.1', - }, - language: { - name: 'go', - version: 'go1.14.1', - }, - version: 'None', - }, - transaction: { - id: '975c8d5bfd1dd20b', - }, - timestamp: { - us: 1584975868787174, - }, - span: { - duration: { - us: 16250, - }, - subtype: 'http', - destination: { - service: { - resource: 'opbeans-python:3000', - name: 'http://opbeans-python:3000', - type: 'external', - }, - }, - name: 'GET opbeans-python:3000', - http: { - response: { - status_code: 200, - }, - url: { - original: 'http://opbeans-python:3000/api/orders', - }, - }, - id: 'daae24d83c269918', - type: 'external', + version: 'go1.14.1', }, + version: 'None', + }, + transaction: { + duration: { + us: 16597, + }, + result: 'HTTP 2xx', + name: 'GET /api/orders', + id: '975c8d5bfd1dd20b', + span_count: { + dropped: 0, + started: 1, + }, + type: 'request', + sampled: true, }, - { - container: { - id: + timestamp: { + us: 1584975868787052, + }, + }, + { + parent: { + id: 'daae24d83c269918', + }, + agent: { + name: 'python', + version: '5.5.2', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + timestamp: { + us: 1584975868788603, + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: 'opbeans-go', + full: 'http://opbeans-go:3000/api/orders', + }, + '@timestamp': '2020-03-23T15:04:28.788Z', + service: { + node: { + name: 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', }, - parent: { - id: '6fb0ff7365b87298', - }, - agent: { - name: 'python', - version: '5.5.2', - }, - processor: { - name: 'transaction', - event: 'span', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.790Z', - service: { - node: { - name: - 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', - }, - environment: 'production', - framework: { - name: 'django', - version: '2.1.13', - }, - name: 'opbeans-python', - runtime: { - name: 'CPython', - version: '3.6.10', - }, - language: { - name: 'python', - version: '3.6.10', - }, - version: 'None', + environment: 'production', + framework: { + name: 'django', + version: '2.1.13', }, - transaction: { - id: '6fb0ff7365b87298', + name: 'opbeans-python', + runtime: { + name: 'CPython', + version: '3.6.10', }, - timestamp: { - us: 1584975868790080, + language: { + name: 'python', + version: '3.6.10', }, - span: { - duration: { - us: 2519, - }, - subtype: 'postgresql', - name: 'SELECT FROM opbeans_order', - destination: { - service: { - resource: 'postgresql', - name: 'postgresql', - type: 'db', - }, - }, - action: 'query', - id: 'c9407abb4d08ead1', - type: 'db', - sync: true, - db: { - statement: - 'SELECT "opbeans_order"."id", "opbeans_order"."customer_id", "opbeans_customer"."full_name", "opbeans_order"."created_at" FROM "opbeans_order" INNER JOIN "opbeans_customer" ON ("opbeans_order"."customer_id" = "opbeans_customer"."id") LIMIT 1000', - type: 'sql', - }, + version: 'None', + }, + transaction: { + result: 'HTTP 2xx', + duration: { + us: 14648, + }, + name: 'GET opbeans.views.orders', + span_count: { + dropped: 0, + started: 1, + }, + id: '6fb0ff7365b87298', + type: 'request', + sampled: true, + }, + }, + { + container: { + id: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + parent: { + id: '49809ad3c26adf74', + }, + process: { + pid: 6, + title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', + ppid: 1, + }, + agent: { + name: 'java', + ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', + version: '1.14.1-SNAPSHOT', + }, + internal: { + sampler: { + value: 44, }, }, - ], - exceedsMax: false, - errorDocs: [], - }, - errorsPerTransaction: {}, -}; - -export const traceWithErrors = { - trace: { - items: [ - { - container: { - id: + destination: { + address: 'opbeans-go', + port: 3000, + }, + processor: { + name: 'transaction', + event: 'span', + }, + observer: { + hostname: 'f37f48d8b60b', + id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', + type: 'apm-server', + ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.785Z', + ecs: { + version: '1.4.0', + }, + service: { + node: { + name: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', }, - process: { - pid: 6, - title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', - ppid: 1, - }, - agent: { - name: 'java', - ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', - version: '1.14.1-SNAPSHOT', + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '10.0.2', }, - internal: { - sampler: { - value: 46, - }, + language: { + name: 'Java', + version: '10.0.2', }, - source: { - ip: '172.19.0.13', - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: '172.19.0.9', - full: 'http://172.19.0.9:3000/api/orders', - }, - observer: { - hostname: 'f37f48d8b60b', - id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', - ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.785Z', - ecs: { - version: '1.4.0', - }, - service: { - node: { - name: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '10.0.2', - }, - language: { - name: 'Java', - version: '10.0.2', - }, - version: 'None', + version: 'None', + }, + host: { + hostname: '4cf84d094553', + os: { + platform: 'Linux', + }, + ip: '172.19.0.9', + name: '4cf84d094553', + architecture: 'amd64', + }, + connection: { + hash: + "{service.environment:'production'}/{service.name:'opbeans-java'}/{span.subtype:'http'}/{destination.address:'opbeans-go'}/{span.type:'external'}", + }, + transaction: { + id: '49809ad3c26adf74', + }, + timestamp: { + us: 1584975868785273, + }, + span: { + duration: { + us: 17530, }, - host: { - hostname: '4cf84d094553', - os: { - platform: 'Linux', + subtype: 'http', + name: 'GET opbeans-go', + destination: { + service: { + resource: 'opbeans-go:3000', + name: 'http://opbeans-go:3000', + type: 'external', }, - ip: '172.19.0.9', - name: '4cf84d094553', - architecture: 'amd64', }, http: { - request: { - headers: { - Accept: ['*/*'], - 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], - Host: ['172.19.0.9:3000'], - 'Accept-Encoding': ['gzip, deflate'], - }, - method: 'get', - socket: { - encrypted: false, - remote_address: '172.19.0.13', - }, - body: { - original: '[REDACTED]', - }, - }, response: { - headers: { - 'Transfer-Encoding': ['chunked'], - Date: ['Mon, 23 Mar 2020 15:04:28 GMT'], - 'Content-Type': ['application/json;charset=ISO-8859-1'], - }, status_code: 200, - finished: true, - headers_sent: true, - }, - version: '1.1', - }, - client: { - ip: '172.19.0.13', - }, - transaction: { - duration: { - us: 18842, }, - result: 'HTTP 2xx', - name: 'DispatcherServlet#doGet', - id: '49809ad3c26adf74', - span_count: { - dropped: 0, - started: 1, + url: { + original: 'http://opbeans-go:3000/api/orders', }, - type: 'request', - sampled: true, - }, - user_agent: { - original: 'Python/3.7 aiohttp/3.3.2', - name: 'Other', - device: { - name: 'Other', - }, - }, - timestamp: { - us: 1584975868785000, }, + id: 'fc107f7b556eb49b', + type: 'external', }, - { - parent: { - id: 'fc107f7b556eb49b', - }, - agent: { + }, + { + parent: { + id: '975c8d5bfd1dd20b', + }, + agent: { + name: 'go', + version: '1.7.2', + }, + processor: { + name: 'transaction', + event: 'span', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.787Z', + service: { + node: { + name: + 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', + }, + environment: 'production', + name: 'opbeans-go', + runtime: { + name: 'gc', + version: 'go1.14.1', + }, + language: { name: 'go', - version: '1.7.2', - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: 'opbeans-go', - full: 'http://opbeans-go:3000/api/orders', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.787Z', - service: { - node: { - name: - 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', - }, - environment: 'production', - framework: { - name: 'gin', - version: 'v1.4.0', - }, - name: 'opbeans-go', - runtime: { - name: 'gc', - version: 'go1.14.1', - }, - language: { - name: 'go', - version: 'go1.14.1', - }, - version: 'None', - }, - transaction: { - duration: { - us: 16597, - }, - result: 'HTTP 2xx', - name: 'GET /api/orders', - id: '975c8d5bfd1dd20b', - span_count: { - dropped: 0, - started: 1, - }, - type: 'request', - sampled: true, - }, - timestamp: { - us: 1584975868787052, + version: 'go1.14.1', }, + version: 'None', + }, + transaction: { + id: '975c8d5bfd1dd20b', }, - { - parent: { - id: 'daae24d83c269918', + timestamp: { + us: 1584975868787174, + }, + span: { + duration: { + us: 16250, }, - agent: { - name: 'python', - version: '5.5.2', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - timestamp: { - us: 1584975868788603, - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: 'opbeans-go', - full: 'http://opbeans-go:3000/api/orders', - }, - '@timestamp': '2020-03-23T15:04:28.788Z', - service: { - node: { - name: - 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', - }, - environment: 'production', - framework: { - name: 'django', - version: '2.1.13', - }, - name: 'opbeans-python', - runtime: { - name: 'CPython', - version: '3.6.10', - }, - language: { - name: 'python', - version: '3.6.10', + subtype: 'http', + destination: { + service: { + resource: 'opbeans-python:3000', + name: 'http://opbeans-python:3000', + type: 'external', }, - version: 'None', }, - transaction: { - result: 'HTTP 2xx', - duration: { - us: 14648, + name: 'GET opbeans-python:3000', + http: { + response: { + status_code: 200, }, - name: 'GET opbeans.views.orders', - span_count: { - dropped: 0, - started: 1, + url: { + original: 'http://opbeans-python:3000/api/orders', }, - id: '6fb0ff7365b87298', - type: 'request', - sampled: true, }, + id: 'daae24d83c269918', + type: 'external', }, - { - container: { - id: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + { + container: { + id: 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', + }, + parent: { + id: '6fb0ff7365b87298', + }, + agent: { + name: 'python', + version: '5.5.2', + }, + processor: { + name: 'transaction', + event: 'span', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.790Z', + service: { + node: { + name: + 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', }, - parent: { - id: '49809ad3c26adf74', + environment: 'production', + framework: { + name: 'django', + version: '2.1.13', }, - process: { - pid: 6, - title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', - ppid: 1, + name: 'opbeans-python', + runtime: { + name: 'CPython', + version: '3.6.10', }, - agent: { - name: 'java', - ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', - version: '1.14.1-SNAPSHOT', + language: { + name: 'python', + version: '3.6.10', }, - internal: { - sampler: { - value: 44, - }, + version: 'None', + }, + transaction: { + id: '6fb0ff7365b87298', + }, + timestamp: { + us: 1584975868790080, + }, + span: { + duration: { + us: 2519, }, + subtype: 'postgresql', + name: 'SELECT FROM opbeans_order', destination: { - address: 'opbeans-go', - port: 3000, - }, - processor: { - name: 'transaction', - event: 'span', - }, - observer: { - hostname: 'f37f48d8b60b', - id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', - type: 'apm-server', - ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.785Z', - ecs: { - version: '1.4.0', - }, - service: { - node: { - name: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '10.0.2', + service: { + resource: 'postgresql', + name: 'postgresql', + type: 'db', }, - language: { - name: 'Java', - version: '10.0.2', - }, - version: 'None', - }, - host: { - hostname: '4cf84d094553', - os: { - platform: 'Linux', - }, - ip: '172.19.0.9', - name: '4cf84d094553', - architecture: 'amd64', - }, - connection: { - hash: - "{service.environment:'production'}/{service.name:'opbeans-java'}/{span.subtype:'http'}/{destination.address:'opbeans-go'}/{span.type:'external'}", }, - transaction: { - id: '49809ad3c26adf74', - }, - timestamp: { - us: 1584975868785273, - }, - span: { - duration: { - us: 17530, - }, - subtype: 'http', - name: 'GET opbeans-go', - destination: { - service: { - resource: 'opbeans-go:3000', - name: 'http://opbeans-go:3000', - type: 'external', - }, - }, - http: { - response: { - status_code: 200, - }, - url: { - original: 'http://opbeans-go:3000/api/orders', - }, - }, - id: 'fc107f7b556eb49b', - type: 'external', + action: 'query', + id: 'c9407abb4d08ead1', + type: 'db', + sync: true, + db: { + statement: + 'SELECT "opbeans_order"."id", "opbeans_order"."customer_id", "opbeans_customer"."full_name", "opbeans_order"."created_at" FROM "opbeans_order" INNER JOIN "opbeans_customer" ON ("opbeans_order"."customer_id" = "opbeans_customer"."id") LIMIT 1000', + type: 'sql', }, }, - { - parent: { - id: '975c8d5bfd1dd20b', - }, - agent: { - name: 'go', - version: '1.7.2', - }, - processor: { - name: 'transaction', - event: 'span', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.787Z', - service: { - node: { - name: - 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', - }, - environment: 'production', - name: 'opbeans-go', - runtime: { - name: 'gc', - version: 'go1.14.1', - }, - language: { - name: 'go', - version: 'go1.14.1', - }, - version: 'None', - }, - transaction: { - id: '975c8d5bfd1dd20b', - }, - timestamp: { - us: 1584975868787174, - }, - span: { - duration: { - us: 16250, - }, - subtype: 'http', - destination: { - service: { - resource: 'opbeans-python:3000', - name: 'http://opbeans-python:3000', - type: 'external', - }, - }, - name: 'GET opbeans-python:3000', - http: { - response: { - status_code: 200, - }, - url: { - original: 'http://opbeans-python:3000/api/orders', - }, - }, - id: 'daae24d83c269918', - type: 'external', - }, + }, + ], + exceedsMax: false, + errorDocs: [ + { + parent: { + id: '975c8d5bfd1dd20b', }, - { - container: { - id: - 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', - }, - parent: { - id: '6fb0ff7365b87298', - }, - agent: { - name: 'python', - version: '5.5.2', - }, - processor: { - name: 'transaction', - event: 'span', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.790Z', - service: { - node: { - name: - 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', - }, - environment: 'production', - framework: { - name: 'django', - version: '2.1.13', - }, - name: 'opbeans-python', - runtime: { - name: 'CPython', - version: '3.6.10', - }, - language: { - name: 'python', - version: '3.6.10', - }, - version: 'None', - }, - transaction: { - id: '6fb0ff7365b87298', - }, - timestamp: { - us: 1584975868790080, - }, - span: { - duration: { - us: 2519, - }, - subtype: 'postgresql', - name: 'SELECT FROM opbeans_order', - destination: { - service: { - resource: 'postgresql', - name: 'postgresql', - type: 'db', - }, - }, - action: 'query', - id: 'c9407abb4d08ead1', - type: 'db', - sync: true, - db: { - statement: - 'SELECT "opbeans_order"."id", "opbeans_order"."customer_id", "opbeans_customer"."full_name", "opbeans_order"."created_at" FROM "opbeans_order" INNER JOIN "opbeans_customer" ON ("opbeans_order"."customer_id" = "opbeans_customer"."id") LIMIT 1000', - type: 'sql', - }, - }, + agent: { + name: 'go', + version: '1.7.2', }, - ], - exceedsMax: false, - errorDocs: [ - { - parent: { - id: '975c8d5bfd1dd20b', - }, - agent: { + error: { + culprit: 'logrusMiddleware', + log: { + level: 'error', + message: 'GET //api/products (502)', + }, + id: '1f3cb98206b5c54225cb7c8908a658da', + grouping_key: '4dba2ff58fe6c036a5dee2ce411e512a', + }, + processor: { + name: 'error', + event: 'error', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T16:04:28.787Z', + service: { + node: { + name: + 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', + }, + environment: 'production', + name: 'opbeans-go', + runtime: { + name: 'gc', + version: 'go1.14.1', + }, + language: { name: 'go', - version: '1.7.2', - }, - error: { - culprit: 'logrusMiddleware', - log: { - level: 'error', - message: 'GET //api/products (502)', - }, - id: '1f3cb98206b5c54225cb7c8908a658da', - grouping_key: '4dba2ff58fe6c036a5dee2ce411e512a', - }, - processor: { - name: 'error', - event: 'error', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T16:04:28.787Z', - service: { - node: { - name: - 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', - }, - environment: 'production', - name: 'opbeans-go', - runtime: { - name: 'gc', - version: 'go1.14.1', - }, - language: { - name: 'go', - version: 'go1.14.1', - }, - version: 'None', - }, - transaction: { - id: '975c8d5bfd1dd20b', - sampled: false, - }, - timestamp: { - us: 1584975868787052, + version: 'go1.14.1', }, + version: 'None', }, - { - parent: { - id: '6fb0ff7365b87298', - }, - agent: { - name: 'python', - version: '5.5.2', - }, - error: { - culprit: 'logrusMiddleware', - log: { - level: 'error', - message: 'GET //api/products (502)', - }, - id: '1f3cb98206b5c54225cb7c8908a658d2', - grouping_key: '4dba2ff58fe6c036a5dee2ce411e512a', - }, - processor: { - name: 'error', - event: 'error', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T16:04:28.790Z', - service: { - node: { - name: - 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', - }, - environment: 'production', - name: 'opbeans-python', - runtime: { - name: 'gc', - version: 'go1.14.1', - }, - version: 'None', - }, - transaction: { - id: '6fb0ff7365b87298', - sampled: false, - }, - timestamp: { - us: 1584975868790000, - }, + transaction: { + id: '975c8d5bfd1dd20b', + sampled: false, + }, + timestamp: { + us: 1584975868787052, }, - ], - }, - errorsPerTransaction: { - '975c8d5bfd1dd20b': 1, - '6fb0ff7365b87298': 1, - }, -}; + }, + { + parent: { + id: '6fb0ff7365b87298', + }, + agent: { + name: 'python', + version: '5.5.2', + }, + error: { + culprit: 'logrusMiddleware', + log: { + level: 'error', + message: 'GET //api/products (502)', + }, + id: '1f3cb98206b5c54225cb7c8908a658d2', + grouping_key: '4dba2ff58fe6c036a5dee2ce411e512a', + }, + processor: { + name: 'error', + event: 'error', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T16:04:28.790Z', + service: { + node: { + name: + 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', + }, + environment: 'production', + name: 'opbeans-python', + runtime: { + name: 'gc', + version: 'go1.14.1', + }, + version: 'None', + }, + transaction: { + id: '6fb0ff7365b87298', + sampled: false, + }, + timestamp: { + us: 1584975868790000, + }, + }, + ], +} as unknown) as TraceAPIResponse; export const traceChildStartBeforeParent = { - trace: { - items: [ - { - container: { - id: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', - }, - process: { - pid: 6, - title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', - ppid: 1, - }, - agent: { - name: 'java', - ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', - version: '1.14.1-SNAPSHOT', - }, - internal: { - sampler: { - value: 46, - }, - }, - source: { - ip: '172.19.0.13', - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: '172.19.0.9', - full: 'http://172.19.0.9:3000/api/orders', - }, - observer: { - hostname: 'f37f48d8b60b', - id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', - ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.785Z', - ecs: { - version: '1.4.0', - }, - service: { - node: { - name: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '10.0.2', - }, - language: { - name: 'Java', - version: '10.0.2', - }, - version: 'None', - }, - host: { - hostname: '4cf84d094553', - os: { - platform: 'Linux', - }, - ip: '172.19.0.9', - name: '4cf84d094553', - architecture: 'amd64', + traceDocs: [ + { + container: { + id: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + process: { + pid: 6, + title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', + ppid: 1, + }, + agent: { + name: 'java', + ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', + version: '1.14.1-SNAPSHOT', + }, + internal: { + sampler: { + value: 46, }, - http: { - request: { - headers: { - Accept: ['*/*'], - 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], - Host: ['172.19.0.9:3000'], - 'Accept-Encoding': ['gzip, deflate'], - }, - method: 'get', - socket: { - encrypted: false, - remote_address: '172.19.0.13', - }, - body: { - original: '[REDACTED]', - }, - }, - response: { - headers: { - 'Transfer-Encoding': ['chunked'], - Date: ['Mon, 23 Mar 2020 15:04:28 GMT'], - 'Content-Type': ['application/json;charset=ISO-8859-1'], - }, - status_code: 200, - finished: true, - headers_sent: true, - }, - version: '1.1', + }, + source: { + ip: '172.19.0.13', + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: '172.19.0.9', + full: 'http://172.19.0.9:3000/api/orders', + }, + observer: { + hostname: 'f37f48d8b60b', + id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', + ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', + type: 'apm-server', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.785Z', + ecs: { + version: '1.4.0', + }, + service: { + node: { + name: + '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', }, - client: { - ip: '172.19.0.13', + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '10.0.2', }, - transaction: { - duration: { - us: 18842, - }, - result: 'HTTP 2xx', - name: 'DispatcherServlet#doGet', - id: '49809ad3c26adf74', - span_count: { - dropped: 0, - started: 1, - }, - type: 'request', - sampled: true, + language: { + name: 'Java', + version: '10.0.2', }, - user_agent: { - original: 'Python/3.7 aiohttp/3.3.2', + version: 'None', + }, + host: { + hostname: '4cf84d094553', + os: { + platform: 'Linux', + }, + ip: '172.19.0.9', + name: '4cf84d094553', + architecture: 'amd64', + }, + http: { + request: { + headers: { + Accept: ['*/*'], + 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], + Host: ['172.19.0.9:3000'], + 'Accept-Encoding': ['gzip, deflate'], + }, + method: 'get', + socket: { + encrypted: false, + remote_address: '172.19.0.13', + }, + body: { + original: '[REDACTED]', + }, + }, + response: { + headers: { + 'Transfer-Encoding': ['chunked'], + Date: ['Mon, 23 Mar 2020 15:04:28 GMT'], + 'Content-Type': ['application/json;charset=ISO-8859-1'], + }, + status_code: 200, + finished: true, + headers_sent: true, + }, + version: '1.1', + }, + client: { + ip: '172.19.0.13', + }, + transaction: { + duration: { + us: 18842, + }, + result: 'HTTP 2xx', + name: 'DispatcherServlet#doGet', + id: '49809ad3c26adf74', + span_count: { + dropped: 0, + started: 1, + }, + type: 'request', + sampled: true, + }, + user_agent: { + original: 'Python/3.7 aiohttp/3.3.2', + name: 'Other', + device: { name: 'Other', - device: { - name: 'Other', - }, - }, - timestamp: { - us: 1584975868785000, }, }, - { - parent: { - id: 'fc107f7b556eb49b', - }, - agent: { + timestamp: { + us: 1584975868785000, + }, + }, + { + parent: { + id: 'fc107f7b556eb49b', + }, + agent: { + name: 'go', + version: '1.7.2', + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: 'opbeans-go', + full: 'http://opbeans-go:3000/api/orders', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.787Z', + service: { + node: { + name: + 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', + }, + environment: 'production', + framework: { + name: 'gin', + version: 'v1.4.0', + }, + name: 'opbeans-go', + runtime: { + name: 'gc', + version: 'go1.14.1', + }, + language: { name: 'go', - version: '1.7.2', - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: 'opbeans-go', - full: 'http://opbeans-go:3000/api/orders', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.787Z', - service: { - node: { - name: - 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', - }, - environment: 'production', - framework: { - name: 'gin', - version: 'v1.4.0', - }, - name: 'opbeans-go', - runtime: { - name: 'gc', - version: 'go1.14.1', - }, - language: { - name: 'go', - version: 'go1.14.1', - }, - version: 'None', + version: 'go1.14.1', }, - transaction: { - duration: { - us: 16597, - }, - result: 'HTTP 2xx', - name: 'GET /api/orders', - id: '975c8d5bfd1dd20b', - span_count: { - dropped: 0, - started: 1, - }, - type: 'request', - sampled: true, + version: 'None', + }, + transaction: { + duration: { + us: 16597, + }, + result: 'HTTP 2xx', + name: 'GET /api/orders', + id: '975c8d5bfd1dd20b', + span_count: { + dropped: 0, + started: 1, + }, + type: 'request', + sampled: true, + }, + timestamp: { + us: 1584975868787052, + }, + }, + { + parent: { + id: 'daae24d83c269918', + }, + agent: { + name: 'python', + version: '5.5.2', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + timestamp: { + us: 1584975868780000, + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/orders', + scheme: 'http', + port: 3000, + domain: 'opbeans-go', + full: 'http://opbeans-go:3000/api/orders', + }, + '@timestamp': '2020-03-23T15:04:28.788Z', + service: { + node: { + name: + 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', }, - timestamp: { - us: 1584975868787052, + environment: 'production', + framework: { + name: 'django', + version: '2.1.13', }, - }, - { - parent: { - id: 'daae24d83c269918', + name: 'opbeans-python', + runtime: { + name: 'CPython', + version: '3.6.10', }, - agent: { + language: { name: 'python', - version: '5.5.2', - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - timestamp: { - us: 1584975868780000, - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/orders', - scheme: 'http', - port: 3000, - domain: 'opbeans-go', - full: 'http://opbeans-go:3000/api/orders', - }, - '@timestamp': '2020-03-23T15:04:28.788Z', - service: { - node: { - name: - 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', - }, - environment: 'production', - framework: { - name: 'django', - version: '2.1.13', - }, - name: 'opbeans-python', - runtime: { - name: 'CPython', - version: '3.6.10', - }, - language: { - name: 'python', - version: '3.6.10', - }, - version: 'None', + version: '3.6.10', }, - transaction: { - result: 'HTTP 2xx', - duration: { - us: 1464, - }, - name: 'I started before my parent 😰', - span_count: { - dropped: 0, - started: 1, - }, - id: '6fb0ff7365b87298', - type: 'request', - sampled: true, + version: 'None', + }, + transaction: { + result: 'HTTP 2xx', + duration: { + us: 1464, + }, + name: 'I started before my parent 😰', + span_count: { + dropped: 0, + started: 1, + }, + id: '6fb0ff7365b87298', + type: 'request', + sampled: true, + }, + }, + { + container: { + id: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + }, + parent: { + id: '49809ad3c26adf74', + }, + process: { + pid: 6, + title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', + ppid: 1, + }, + agent: { + name: 'java', + ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', + version: '1.14.1-SNAPSHOT', + }, + internal: { + sampler: { + value: 44, }, }, - { - container: { - id: + destination: { + address: 'opbeans-go', + port: 3000, + }, + processor: { + name: 'transaction', + event: 'span', + }, + observer: { + hostname: 'f37f48d8b60b', + id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', + type: 'apm-server', + ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.785Z', + ecs: { + version: '1.4.0', + }, + service: { + node: { + name: '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', }, - parent: { - id: '49809ad3c26adf74', - }, - process: { - pid: 6, - title: '/usr/lib/jvm/java-10-openjdk-amd64/bin/java', - ppid: 1, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '10.0.2', }, - agent: { - name: 'java', - ephemeral_id: '99ce8403-5875-4945-b074-d37dc10563eb', - version: '1.14.1-SNAPSHOT', + language: { + name: 'Java', + version: '10.0.2', }, - internal: { - sampler: { - value: 44, - }, + version: 'None', + }, + host: { + hostname: '4cf84d094553', + os: { + platform: 'Linux', + }, + ip: '172.19.0.9', + name: '4cf84d094553', + architecture: 'amd64', + }, + connection: { + hash: + "{service.environment:'production'}/{service.name:'opbeans-java'}/{span.subtype:'http'}/{destination.address:'opbeans-go'}/{span.type:'external'}", + }, + transaction: { + id: '49809ad3c26adf74', + }, + timestamp: { + us: 1584975868785273, + }, + span: { + duration: { + us: 17530, }, + subtype: 'http', + name: 'GET opbeans-go', destination: { - address: 'opbeans-go', - port: 3000, - }, - processor: { - name: 'transaction', - event: 'span', - }, - observer: { - hostname: 'f37f48d8b60b', - id: 'd8522e1f-be8e-43c2-b290-ac6b6c0f171e', - type: 'apm-server', - ephemeral_id: '6ed88f14-170e-478d-a4f5-ea5e7f4b16b9', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', - }, - '@timestamp': '2020-03-23T15:04:28.785Z', - ecs: { - version: '1.4.0', - }, - service: { - node: { - name: - '4cf84d094553201997ddb7fea344b7c6ef18dcb8233eba39278946ee8449794e', + service: { + resource: 'opbeans-go:3000', + name: 'http://opbeans-go:3000', + type: 'external', }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '10.0.2', - }, - language: { - name: 'Java', - version: '10.0.2', - }, - version: 'None', - }, - host: { - hostname: '4cf84d094553', - os: { - platform: 'Linux', - }, - ip: '172.19.0.9', - name: '4cf84d094553', - architecture: 'amd64', - }, - connection: { - hash: - "{service.environment:'production'}/{service.name:'opbeans-java'}/{span.subtype:'http'}/{destination.address:'opbeans-go'}/{span.type:'external'}", - }, - transaction: { - id: '49809ad3c26adf74', }, - timestamp: { - us: 1584975868785273, - }, - span: { - duration: { - us: 17530, - }, - subtype: 'http', - name: 'GET opbeans-go', - destination: { - service: { - resource: 'opbeans-go:3000', - name: 'http://opbeans-go:3000', - type: 'external', - }, + http: { + response: { + status_code: 200, }, - http: { - response: { - status_code: 200, - }, - url: { - original: 'http://opbeans-go:3000/api/orders', - }, + url: { + original: 'http://opbeans-go:3000/api/orders', }, - id: 'fc107f7b556eb49b', - type: 'external', }, + id: 'fc107f7b556eb49b', + type: 'external', }, - { - parent: { - id: '975c8d5bfd1dd20b', - }, - agent: { + }, + { + parent: { + id: '975c8d5bfd1dd20b', + }, + agent: { + name: 'go', + version: '1.7.2', + }, + processor: { + name: 'transaction', + event: 'span', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.787Z', + service: { + node: { + name: + 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', + }, + environment: 'production', + name: 'opbeans-go', + runtime: { + name: 'gc', + version: 'go1.14.1', + }, + language: { name: 'go', - version: '1.7.2', - }, - processor: { - name: 'transaction', - event: 'span', + version: 'go1.14.1', }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', + version: 'None', + }, + transaction: { + id: '975c8d5bfd1dd20b', + }, + timestamp: { + us: 1584975868787174, + }, + span: { + duration: { + us: 16250, }, - '@timestamp': '2020-03-23T15:04:28.787Z', - service: { - node: { - name: - 'e948a08b8f5efe99b5da01f50da48c7d8aee3bbf4701f3da85ebe760c2ffef29', - }, - environment: 'production', - name: 'opbeans-go', - runtime: { - name: 'gc', - version: 'go1.14.1', - }, - language: { - name: 'go', - version: 'go1.14.1', + subtype: 'http', + destination: { + service: { + resource: 'opbeans-python:3000', + name: 'http://opbeans-python:3000', + type: 'external', }, - version: 'None', - }, - transaction: { - id: '975c8d5bfd1dd20b', }, - timestamp: { - us: 1584975868787174, - }, - span: { - duration: { - us: 16250, - }, - subtype: 'http', - destination: { - service: { - resource: 'opbeans-python:3000', - name: 'http://opbeans-python:3000', - type: 'external', - }, + name: 'I am his 👇🏻 parent 😡', + http: { + response: { + status_code: 200, }, - name: 'I am his 👇🏻 parent 😡', - http: { - response: { - status_code: 200, - }, - url: { - original: 'http://opbeans-python:3000/api/orders', - }, + url: { + original: 'http://opbeans-python:3000/api/orders', }, - id: 'daae24d83c269918', - type: 'external', }, + id: 'daae24d83c269918', + type: 'external', + }, + }, + { + container: { + id: 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', }, - { - container: { - id: + parent: { + id: '6fb0ff7365b87298', + }, + agent: { + name: 'python', + version: '5.5.2', + }, + processor: { + name: 'transaction', + event: 'span', + }, + trace: { + id: '513d33fafe99bbe6134749310c9b5322', + }, + '@timestamp': '2020-03-23T15:04:28.790Z', + service: { + node: { + name: 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', }, - parent: { - id: '6fb0ff7365b87298', + environment: 'production', + framework: { + name: 'django', + version: '2.1.13', }, - agent: { - name: 'python', - version: '5.5.2', + name: 'opbeans-python', + runtime: { + name: 'CPython', + version: '3.6.10', }, - processor: { - name: 'transaction', - event: 'span', + language: { + name: 'python', + version: '3.6.10', }, - trace: { - id: '513d33fafe99bbe6134749310c9b5322', + version: 'None', + }, + transaction: { + id: '6fb0ff7365b87298', + }, + timestamp: { + us: 1584975868781000, + }, + span: { + duration: { + us: 2519, }, - '@timestamp': '2020-03-23T15:04:28.790Z', - service: { - node: { - name: - 'a636915f1f6eec81ab44342b13a3ea9597ef03a24391e4e55f34ae2e20b30f51', - }, - environment: 'production', - framework: { - name: 'django', - version: '2.1.13', - }, - name: 'opbeans-python', - runtime: { - name: 'CPython', - version: '3.6.10', - }, - language: { - name: 'python', - version: '3.6.10', + subtype: 'postgresql', + name: 'I am using my parents skew 😇', + destination: { + service: { + resource: 'postgresql', + name: 'postgresql', + type: 'db', }, - version: 'None', - }, - transaction: { - id: '6fb0ff7365b87298', - }, - timestamp: { - us: 1584975868781000, }, - span: { - duration: { - us: 2519, - }, - subtype: 'postgresql', - name: 'I am using my parents skew 😇', - destination: { - service: { - resource: 'postgresql', - name: 'postgresql', - type: 'db', - }, - }, - action: 'query', - id: 'c9407abb4d08ead1', - type: 'db', - sync: true, - db: { - statement: - 'SELECT "opbeans_order"."id", "opbeans_order"."customer_id", "opbeans_customer"."full_name", "opbeans_order"."created_at" FROM "opbeans_order" INNER JOIN "opbeans_customer" ON ("opbeans_order"."customer_id" = "opbeans_customer"."id") LIMIT 1000', - type: 'sql', - }, + action: 'query', + id: 'c9407abb4d08ead1', + type: 'db', + sync: true, + db: { + statement: + 'SELECT "opbeans_order"."id", "opbeans_order"."customer_id", "opbeans_customer"."full_name", "opbeans_order"."created_at" FROM "opbeans_order" INNER JOIN "opbeans_customer" ON ("opbeans_order"."customer_id" = "opbeans_customer"."id") LIMIT 1000', + type: 'sql', }, }, - ], - exceedsMax: false, - errorDocs: [], - }, - errorsPerTransaction: {}, -}; + }, + ], + exceedsMax: false, + errorDocs: [], +} as TraceAPIResponse; export const inferredSpans = { - trace: { - items: [ - { - container: { - id: + traceDocs: [ + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT', + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1, + }, + source: { + ip: '172.18.0.8', + }, + processor: { + name: 'transaction', + event: 'transaction', + }, + url: { + path: '/api/products/2', + scheme: 'http', + port: 3000, + domain: '172.18.0.7', + full: 'http://172.18.0.7:3000/api/products/2', + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97', + }, + '@timestamp': '2020-04-09T11:36:00.786Z', + ecs: { + version: '1.5.0', + }, + service: { + node: { + name: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', }, - agent: { - name: 'java', - ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', - version: '1.15.1-SNAPSHOT', - }, - process: { - pid: 6, - title: '/opt/java/openjdk/bin/java', - ppid: 1, - }, - source: { - ip: '172.18.0.8', - }, - processor: { - name: 'transaction', - event: 'transaction', - }, - url: { - path: '/api/products/2', - scheme: 'http', - port: 3000, - domain: '172.18.0.7', - full: 'http://172.18.0.7:3000/api/products/2', - }, - observer: { - hostname: '7189f754b5a3', - id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', - ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '3b0dc77f3754e5bcb9da0e4c15e0db97', - }, - '@timestamp': '2020-04-09T11:36:00.786Z', - ecs: { - version: '1.5.0', - }, - service: { - node: { - name: - 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '11.0.6', - }, - language: { - name: 'Java', - version: '11.0.6', - }, - version: 'None', - }, - host: { - hostname: 'fc2ae281f56f', - os: { - platform: 'Linux', - }, - ip: '172.18.0.7', - name: 'fc2ae281f56f', - architecture: 'amd64', - }, - client: { - ip: '172.18.0.8', + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6', }, - http: { - request: { - headers: { - Accept: ['*/*'], - 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], - Host: ['172.18.0.7:3000'], - 'Accept-Encoding': ['gzip, deflate'], - }, - method: 'get', - socket: { - encrypted: false, - remote_address: '172.18.0.8', - }, - }, - response: { - headers: { - 'Transfer-Encoding': ['chunked'], - Date: ['Thu, 09 Apr 2020 11:36:01 GMT'], - 'Content-Type': ['application/json;charset=UTF-8'], - }, - status_code: 200, - finished: true, - headers_sent: true, - }, - version: '1.1', + language: { + name: 'Java', + version: '11.0.6', }, - user_agent: { - original: 'Python/3.7 aiohttp/3.3.2', + version: 'None', + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux', + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64', + }, + client: { + ip: '172.18.0.8', + }, + http: { + request: { + headers: { + Accept: ['*/*'], + 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], + Host: ['172.18.0.7:3000'], + 'Accept-Encoding': ['gzip, deflate'], + }, + method: 'get', + socket: { + encrypted: false, + remote_address: '172.18.0.8', + }, + }, + response: { + headers: { + 'Transfer-Encoding': ['chunked'], + Date: ['Thu, 09 Apr 2020 11:36:01 GMT'], + 'Content-Type': ['application/json;charset=UTF-8'], + }, + status_code: 200, + finished: true, + headers_sent: true, + }, + version: '1.1', + }, + user_agent: { + original: 'Python/3.7 aiohttp/3.3.2', + name: 'Other', + device: { name: 'Other', - device: { - name: 'Other', - }, - }, - transaction: { - duration: { - us: 237537, - }, - result: 'HTTP 2xx', - name: 'APIRestController#product', - span_count: { - dropped: 0, - started: 3, - }, - id: 'f2387d37260d00bd', - type: 'request', - sampled: true, - }, - timestamp: { - us: 1586432160786001, }, }, - { - container: { - id: + transaction: { + duration: { + us: 237537, + }, + result: 'HTTP 2xx', + name: 'APIRestController#product', + span_count: { + dropped: 0, + started: 3, + }, + id: 'f2387d37260d00bd', + type: 'request', + sampled: true, + }, + timestamp: { + us: 1586432160786001, + }, + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', + }, + parent: { + id: 'f2387d37260d00bd', + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT', + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1, + }, + processor: { + name: 'transaction', + event: 'span', + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97', + }, + '@timestamp': '2020-04-09T11:36:00.810Z', + ecs: { + version: '1.5.0', + }, + service: { + node: { + name: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', }, - parent: { - id: 'f2387d37260d00bd', - }, - agent: { - name: 'java', - ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', - version: '1.15.1-SNAPSHOT', - }, - process: { - pid: 6, - title: '/opt/java/openjdk/bin/java', - ppid: 1, - }, - processor: { - name: 'transaction', - event: 'span', - }, - observer: { - hostname: '7189f754b5a3', - id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', - ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '3b0dc77f3754e5bcb9da0e4c15e0db97', - }, - '@timestamp': '2020-04-09T11:36:00.810Z', - ecs: { - version: '1.5.0', - }, - service: { - node: { - name: - 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '11.0.6', - }, - language: { - name: 'Java', - version: '11.0.6', - }, - version: 'None', - }, - host: { - hostname: 'fc2ae281f56f', - os: { - platform: 'Linux', - }, - ip: '172.18.0.7', - name: 'fc2ae281f56f', - architecture: 'amd64', - }, - transaction: { - id: 'f2387d37260d00bd', - }, - span: { - duration: { - us: 204574, - }, - subtype: 'inferred', - name: 'ServletInvocableHandlerMethod#invokeAndHandle', - id: 'a5df600bd7bd5e38', - type: 'app', + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6', }, - timestamp: { - us: 1586432160810441, + language: { + name: 'Java', + version: '11.0.6', }, + version: 'None', + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux', + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64', + }, + transaction: { + id: 'f2387d37260d00bd', + }, + span: { + duration: { + us: 204574, + }, + subtype: 'inferred', + name: 'ServletInvocableHandlerMethod#invokeAndHandle', + id: 'a5df600bd7bd5e38', + type: 'app', }, - { - container: { - id: + timestamp: { + us: 1586432160810441, + }, + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', + }, + parent: { + id: 'a5df600bd7bd5e38', + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT', + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1, + }, + processor: { + name: 'transaction', + event: 'span', + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + type: 'apm-server', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97', + }, + '@timestamp': '2020-04-09T11:36:00.810Z', + ecs: { + version: '1.5.0', + }, + service: { + node: { + name: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', }, - parent: { - id: 'a5df600bd7bd5e38', - }, - agent: { - name: 'java', - ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', - version: '1.15.1-SNAPSHOT', - }, - process: { - pid: 6, - title: '/opt/java/openjdk/bin/java', - ppid: 1, - }, - processor: { - name: 'transaction', - event: 'span', - }, - observer: { - hostname: '7189f754b5a3', - id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', - type: 'apm-server', - ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '3b0dc77f3754e5bcb9da0e4c15e0db97', - }, - '@timestamp': '2020-04-09T11:36:00.810Z', - ecs: { - version: '1.5.0', - }, - service: { - node: { - name: - 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '11.0.6', - }, - language: { - name: 'Java', - version: '11.0.6', - }, - version: 'None', - }, - host: { - hostname: 'fc2ae281f56f', - os: { - platform: 'Linux', - }, - ip: '172.18.0.7', - name: 'fc2ae281f56f', - architecture: 'amd64', - }, - transaction: { - id: 'f2387d37260d00bd', + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6', }, - timestamp: { - us: 1586432160810441, + language: { + name: 'Java', + version: '11.0.6', }, - span: { - duration: { - us: 102993, - }, - stacktrace: [ - { - library_frame: true, - exclude_from_grouping: false, - filename: 'InvocableHandlerMethod.java', - line: { - number: -1, - }, - function: 'doInvoke', + version: 'None', + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux', + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64', + }, + transaction: { + id: 'f2387d37260d00bd', + }, + timestamp: { + us: 1586432160810441, + }, + span: { + duration: { + us: 102993, + }, + stacktrace: [ + { + library_frame: true, + exclude_from_grouping: false, + filename: 'InvocableHandlerMethod.java', + line: { + number: -1, }, - { - exclude_from_grouping: false, - library_frame: true, - filename: 'InvocableHandlerMethod.java', - line: { - number: -1, - }, - function: 'invokeForRequest', + function: 'doInvoke', + }, + { + exclude_from_grouping: false, + library_frame: true, + filename: 'InvocableHandlerMethod.java', + line: { + number: -1, }, - ], - subtype: 'inferred', - name: 'APIRestController#product', - id: '808dc34fc41ce522', - type: 'app', - }, + function: 'invokeForRequest', + }, + ], + subtype: 'inferred', + name: 'APIRestController#product', + id: '808dc34fc41ce522', + type: 'app', + }, + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', + }, + parent: { + id: 'f2387d37260d00bd', }, - { - container: { - id: + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT', + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1, + }, + processor: { + name: 'transaction', + event: 'span', + }, + labels: { + productId: '2', + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97', + }, + '@timestamp': '2020-04-09T11:36:00.832Z', + ecs: { + version: '1.5.0', + }, + service: { + node: { + name: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', }, - parent: { - id: 'f2387d37260d00bd', - }, - agent: { - name: 'java', - ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', - version: '1.15.1-SNAPSHOT', - }, - process: { - pid: 6, - title: '/opt/java/openjdk/bin/java', - ppid: 1, - }, - processor: { - name: 'transaction', - event: 'span', - }, - labels: { - productId: '2', - }, - observer: { - hostname: '7189f754b5a3', - id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', - ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '3b0dc77f3754e5bcb9da0e4c15e0db97', - }, - '@timestamp': '2020-04-09T11:36:00.832Z', - ecs: { - version: '1.5.0', - }, - service: { - node: { - name: - 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '11.0.6', - }, - language: { - name: 'Java', - version: '11.0.6', - }, - version: 'None', - }, - host: { - hostname: 'fc2ae281f56f', - os: { - platform: 'Linux', - }, - ip: '172.18.0.7', - name: 'fc2ae281f56f', - architecture: 'amd64', - }, - transaction: { - id: 'f2387d37260d00bd', + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6', }, - timestamp: { - us: 1586432160832300, + language: { + name: 'Java', + version: '11.0.6', }, - span: { - duration: { - us: 99295, - }, - name: 'OpenTracing product span', - id: '41226ae63af4f235', - type: 'unknown', + version: 'None', + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux', + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64', + }, + transaction: { + id: 'f2387d37260d00bd', + }, + timestamp: { + us: 1586432160832300, + }, + span: { + duration: { + us: 99295, }, - child: { id: ['8d80de06aa11a6fc'] }, + name: 'OpenTracing product span', + id: '41226ae63af4f235', + type: 'unknown', + }, + child: { id: ['8d80de06aa11a6fc'] }, + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', + }, + parent: { + id: '808dc34fc41ce522', + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1, + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT', + }, + processor: { + name: 'transaction', + event: 'span', + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8, }, - { - container: { - id: + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97', + }, + '@timestamp': '2020-04-09T11:36:00.859Z', + ecs: { + version: '1.5.0', + }, + service: { + node: { + name: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', }, - parent: { - id: '808dc34fc41ce522', - }, - process: { - pid: 6, - title: '/opt/java/openjdk/bin/java', - ppid: 1, - }, - agent: { - name: 'java', - ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', - version: '1.15.1-SNAPSHOT', - }, - processor: { - name: 'transaction', - event: 'span', - }, - observer: { - hostname: '7189f754b5a3', - id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', - ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '3b0dc77f3754e5bcb9da0e4c15e0db97', - }, - '@timestamp': '2020-04-09T11:36:00.859Z', - ecs: { - version: '1.5.0', - }, - service: { - node: { - name: - 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '11.0.6', - }, - language: { - name: 'Java', - version: '11.0.6', - }, - version: 'None', - }, - host: { - hostname: 'fc2ae281f56f', - os: { - platform: 'Linux', - }, - ip: '172.18.0.7', - name: 'fc2ae281f56f', - architecture: 'amd64', - }, - transaction: { - id: 'f2387d37260d00bd', - }, - timestamp: { - us: 1586432160859600, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6', }, - span: { - duration: { - us: 53835, - }, - subtype: 'inferred', - name: 'Loader#executeQueryStatement', - id: '8d80de06aa11a6fc', - type: 'app', + language: { + name: 'Java', + version: '11.0.6', }, + version: 'None', + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux', + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64', + }, + transaction: { + id: 'f2387d37260d00bd', }, - { - container: { - id: + timestamp: { + us: 1586432160859600, + }, + span: { + duration: { + us: 53835, + }, + subtype: 'inferred', + name: 'Loader#executeQueryStatement', + id: '8d80de06aa11a6fc', + type: 'app', + }, + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', + }, + parent: { + id: '41226ae63af4f235', + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT', + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1, + }, + destination: { + address: 'postgres', + port: 5432, + }, + processor: { + name: 'transaction', + event: 'span', + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97', + }, + '@timestamp': '2020-04-09T11:36:00.903Z', + ecs: { + version: '1.5.0', + }, + service: { + node: { + name: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', }, - parent: { - id: '41226ae63af4f235', + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6', }, - agent: { - name: 'java', - ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', - version: '1.15.1-SNAPSHOT', + language: { + name: 'Java', + version: '11.0.6', }, - process: { - pid: 6, - title: '/opt/java/openjdk/bin/java', - ppid: 1, + version: 'None', + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux', + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64', + }, + transaction: { + id: 'f2387d37260d00bd', + }, + timestamp: { + us: 1586432160903236, + }, + span: { + duration: { + us: 10211, }, + subtype: 'postgresql', destination: { - address: 'postgres', - port: 5432, - }, - processor: { - name: 'transaction', - event: 'span', - }, - observer: { - hostname: '7189f754b5a3', - id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', - ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '3b0dc77f3754e5bcb9da0e4c15e0db97', - }, - '@timestamp': '2020-04-09T11:36:00.903Z', - ecs: { - version: '1.5.0', - }, - service: { - node: { - name: - 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '11.0.6', - }, - language: { - name: 'Java', - version: '11.0.6', - }, - version: 'None', - }, - host: { - hostname: 'fc2ae281f56f', - os: { - platform: 'Linux', + service: { + resource: 'postgresql', + name: 'postgresql', + type: 'db', }, - ip: '172.18.0.7', - name: 'fc2ae281f56f', - architecture: 'amd64', - }, - transaction: { - id: 'f2387d37260d00bd', - }, - timestamp: { - us: 1586432160903236, }, - span: { - duration: { - us: 10211, - }, - subtype: 'postgresql', - destination: { - service: { - resource: 'postgresql', - name: 'postgresql', - type: 'db', - }, - }, - name: 'SELECT FROM products', - action: 'query', - id: '3708d5623658182f', - type: 'db', - db: { - statement: - 'select product0_.id as col_0_0_, product0_.sku as col_1_0_, product0_.name as col_2_0_, product0_.description as col_3_0_, product0_.cost as col_4_0_, product0_.selling_price as col_5_0_, product0_.stock as col_6_0_, producttyp1_.id as col_7_0_, producttyp1_.name as col_8_0_, (select sum(orderline2_.amount) from order_lines orderline2_ where orderline2_.product_id=product0_.id) as col_9_0_ from products product0_ left outer join product_types producttyp1_ on product0_.type_id=producttyp1_.id where product0_.id=?', - type: 'sql', - user: { - name: 'postgres', - }, + name: 'SELECT FROM products', + action: 'query', + id: '3708d5623658182f', + type: 'db', + db: { + statement: + 'select product0_.id as col_0_0_, product0_.sku as col_1_0_, product0_.name as col_2_0_, product0_.description as col_3_0_, product0_.cost as col_4_0_, product0_.selling_price as col_5_0_, product0_.stock as col_6_0_, producttyp1_.id as col_7_0_, producttyp1_.name as col_8_0_, (select sum(orderline2_.amount) from order_lines orderline2_ where orderline2_.product_id=product0_.id) as col_9_0_ from products product0_ left outer join product_types producttyp1_ on product0_.type_id=producttyp1_.id where product0_.id=?', + type: 'sql', + user: { + name: 'postgres', }, }, }, - { - container: { - id: + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', + }, + parent: { + id: '41226ae63af4f235', + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1, + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT', + }, + destination: { + address: 'postgres', + port: 5432, + }, + processor: { + name: 'transaction', + event: 'span', + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8, + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97', + }, + '@timestamp': '2020-04-09T11:36:00.859Z', + ecs: { + version: '1.5.0', + }, + service: { + node: { + name: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', }, - parent: { - id: '41226ae63af4f235', + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6', }, - process: { - pid: 6, - title: '/opt/java/openjdk/bin/java', - ppid: 1, + language: { + name: 'Java', + version: '11.0.6', }, - agent: { - name: 'java', - ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', - version: '1.15.1-SNAPSHOT', + version: 'None', + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux', + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64', + }, + transaction: { + id: 'f2387d37260d00bd', + }, + timestamp: { + us: 1586432160859508, + }, + span: { + duration: { + us: 4503, }, + subtype: 'postgresql', destination: { - address: 'postgres', - port: 5432, - }, - processor: { - name: 'transaction', - event: 'span', - }, - observer: { - hostname: '7189f754b5a3', - id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', - ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', - type: 'apm-server', - version: '8.0.0', - version_major: 8, - }, - trace: { - id: '3b0dc77f3754e5bcb9da0e4c15e0db97', - }, - '@timestamp': '2020-04-09T11:36:00.859Z', - ecs: { - version: '1.5.0', - }, - service: { - node: { - name: - 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad', - }, - environment: 'production', - name: 'opbeans-java', - runtime: { - name: 'Java', - version: '11.0.6', - }, - language: { - name: 'Java', - version: '11.0.6', - }, - version: 'None', - }, - host: { - hostname: 'fc2ae281f56f', - os: { - platform: 'Linux', + service: { + resource: 'postgresql', + name: 'postgresql', + type: 'db', }, - ip: '172.18.0.7', - name: 'fc2ae281f56f', - architecture: 'amd64', }, - transaction: { - id: 'f2387d37260d00bd', - }, - timestamp: { - us: 1586432160859508, - }, - span: { - duration: { - us: 4503, - }, - subtype: 'postgresql', - destination: { - service: { - resource: 'postgresql', - name: 'postgresql', - type: 'db', - }, - }, - name: 'empty query', - action: 'query', - id: '9871cfd612368932', - type: 'db', - db: { - rows_affected: 0, - statement: '(empty query)', - type: 'sql', - user: { - name: 'postgres', - }, + name: 'empty query', + action: 'query', + id: '9871cfd612368932', + type: 'db', + db: { + rows_affected: 0, + statement: '(empty query)', + type: 'sql', + user: { + name: 'postgres', }, }, }, - ], - exceedsMax: false, - errorDocs: [], - }, - errorsPerTransaction: {}, -}; + }, + ], + exceedsMax: false, + errorDocs: [], +} as TraceAPIResponse; diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx index 562cd255843bb0..b06de47472a110 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { pickKeys } from '../../../../../common/utils/pick_keys'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; import { APMQueryParams } from '../url_helpers'; -import { APMLink, APMLinkExtendProps, useAPMHref } from './APMLink'; +import { APMLink, APMLinkExtendProps } from './APMLink'; const persistedFilters: Array = [ 'host', @@ -18,13 +18,6 @@ const persistedFilters: Array = [ 'serviceVersion', ]; -export function useErrorOverviewHref(serviceName: string) { - return useAPMHref({ - path: `/services/${serviceName}/errors`, - persistedFilters, - }); -} - interface Props extends APMLinkExtendProps { serviceName: string; query?: APMQueryParams; diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts index 141a054a311c3f..f19aef8e0bd8ac 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts @@ -11,6 +11,7 @@ import { SERVICE, SPAN, LABELS, + EVENT, TRANSACTION, TRACE, MESSAGE_SPAN, @@ -20,6 +21,7 @@ export const SPAN_METADATA_SECTIONS: Section[] = [ LABELS, TRACE, TRANSACTION, + EVENT, SPAN, SERVICE, MESSAGE_SPAN, diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts index 59a2c88809cccc..2f4a3d32298572 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts @@ -9,6 +9,7 @@ import { Section, TRANSACTION, LABELS, + EVENT, HTTP, HOST, CLIENT, @@ -29,6 +30,7 @@ export const TRANSACTION_METADATA_SECTIONS: Section[] = [ { ...LABELS, required: true }, TRACE, TRANSACTION, + EVENT, HTTP, HOST, CLIENT, diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts index 3faccce8ea9558..efc2ef8bde66b4 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts @@ -21,6 +21,14 @@ export const LABELS: Section = { }), }; +export const EVENT: Section = { + key: 'event', + label: i18n.translate('xpack.apm.metadataTable.section.eventLabel', { + defaultMessage: 'event', + }), + properties: ['outcome'], +}; + export const HTTP: Section = { key: 'http', label: i18n.translate('xpack.apm.metadataTable.section.httpLabel', { diff --git a/x-pack/plugins/apm/public/services/rest/createCallApmApi.ts b/x-pack/plugins/apm/public/services/rest/createCallApmApi.ts index 35dbca1b0c955a..40713f93d3ee57 100644 --- a/x-pack/plugins/apm/public/services/rest/createCallApmApi.ts +++ b/x-pack/plugins/apm/public/services/rest/createCallApmApi.ts @@ -9,7 +9,6 @@ import { CoreSetup, CoreStart } from 'kibana/public'; import * as t from 'io-ts'; import type { ClientRequestParamsOf, - EndpointOf, formatRequest as formatRequestType, ReturnOf, RouteRepositoryClient, @@ -26,6 +25,7 @@ import { callApi } from './callApi'; import type { APMServerRouteRepository, APMRouteHandlerResources, + APIEndpoint, // eslint-disable-next-line @kbn/eslint/no-restricted-paths } from '../../../server'; import { InspectResponse } from '../../../typings/common'; @@ -47,16 +47,15 @@ export type AutoAbortedAPMClient = RouteRepositoryClient< Omit >; -export type APIReturnType< - TEndpoint extends EndpointOf -> = ReturnOf & { +export type APIReturnType = ReturnOf< + APMServerRouteRepository, + TEndpoint +> & { _inspect?: InspectResponse; }; -export type APIEndpoint = EndpointOf; - export type APIClientRequestParamsOf< - TEndpoint extends EndpointOf + TEndpoint extends APIEndpoint > = ClientRequestParamsOf; export type AbstractAPMRepository = ServerRouteRepository< diff --git a/x-pack/plugins/apm/scripts/create-apm-users-and-roles/create_apm_users_and_roles.ts b/x-pack/plugins/apm/scripts/create-apm-users-and-roles/create_apm_users_and_roles.ts index 6b67d8d80e7982..708a8b62287be8 100644 --- a/x-pack/plugins/apm/scripts/create-apm-users-and-roles/create_apm_users_and_roles.ts +++ b/x-pack/plugins/apm/scripts/create-apm-users-and-roles/create_apm_users_and_roles.ts @@ -28,6 +28,14 @@ export async function createApmUsersAndRoles({ kibana: Kibana; elasticsearch: Elasticsearch; }) { + const isCredentialsValid = await getIsCredentialsValid({ + elasticsearch, + kibana, + }); + if (!isCredentialsValid) { + throw new AbortError('Invalid username/password'); + } + const isSecurityEnabled = await getIsSecurityEnabled({ elasticsearch, kibana, @@ -86,3 +94,25 @@ async function getIsSecurityEnabled({ return false; } } + +async function getIsCredentialsValid({ + elasticsearch, + kibana, +}: { + elasticsearch: Elasticsearch; + kibana: Kibana; +}) { + try { + await callKibana({ + elasticsearch, + kibana, + options: { + validateStatus: (status) => status >= 200 && status < 400, + url: `/`, + }, + }); + return true; + } catch (err) { + return false; + } +} diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index db62cc7adae2b0..6ba412bd220291 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -125,7 +125,10 @@ export const plugin = (initContext: PluginInitializerContext) => export { APM_SERVER_FEATURE_ID } from '../common/alert_types'; export { APMPlugin } from './plugin'; export { APMPluginSetup } from './types'; -export { APMServerRouteRepository } from './routes/get_global_apm_server_route_repository'; +export { + APMServerRouteRepository, + APIEndpoint, +} from './routes/get_global_apm_server_route_repository'; export { APMRouteHandlerResources } from './routes/typings'; export type { ProcessorEvent } from '../common/processor_event'; diff --git a/x-pack/plugins/apm/server/lib/traces/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/traces/__snapshots__/queries.test.ts.snap index 3c521839b587ed..7691373ada8157 100644 --- a/x-pack/plugins/apm/server/lib/traces/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/traces/__snapshots__/queries.test.ts.snap @@ -8,15 +8,6 @@ Object { ], }, "body": Object { - "aggs": Object { - "by_transaction_id": Object { - "terms": Object { - "execution_hint": "map", - "field": "transaction.id", - "size": "myIndex", - }, - }, - }, "query": Object { "bool": Object { "filter": Array [ diff --git a/x-pack/plugins/apm/server/lib/traces/get_trace.ts b/x-pack/plugins/apm/server/lib/traces/get_trace.ts deleted file mode 100644 index a0cc6b7241d4e5..00000000000000 --- a/x-pack/plugins/apm/server/lib/traces/get_trace.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Setup, SetupTimeRange } from '../helpers/setup_request'; -import { getTraceItems } from './get_trace_items'; - -export async function getTrace(traceId: string, setup: Setup & SetupTimeRange) { - const { errorsPerTransaction, ...trace } = await getTraceItems( - traceId, - setup - ); - - return { - trace, - errorsPerTransaction, - }; -} diff --git a/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts b/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts index 6c957df3138667..6cc6713e156bc0 100644 --- a/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts +++ b/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts @@ -9,15 +9,13 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types'; import { ProcessorEvent } from '../../../common/processor_event'; import { TRACE_ID, - PARENT_ID, TRANSACTION_DURATION, SPAN_DURATION, - TRANSACTION_ID, + PARENT_ID, ERROR_LOG_LEVEL, } from '../../../common/elasticsearch_fieldnames'; import { rangeQuery } from '../../../../observability/server'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; -import { PromiseValueType } from '../../../typings/common'; export async function getTraceItems( traceId: string, @@ -27,7 +25,7 @@ export async function getTraceItems( const maxTraceItems = config['xpack.apm.ui.maxTraceItems']; const excludedLogLevels = ['debug', 'info', 'warning']; - const errorResponsePromise = apmEventClient.search('get_trace_items', { + const errorResponsePromise = apmEventClient.search('get_errors_docs', { apm: { events: [ProcessorEvent.error], }, @@ -42,20 +40,10 @@ export async function getTraceItems( must_not: { terms: { [ERROR_LOG_LEVEL]: excludedLogLevels } }, }, }, - aggs: { - by_transaction_id: { - terms: { - field: TRANSACTION_ID, - size: maxTraceItems, - // high cardinality - execution_hint: 'map' as const, - }, - }, - }, }, }); - const traceResponsePromise = apmEventClient.search('get_trace_span_items', { + const traceResponsePromise = apmEventClient.search('get_trace_docs', { apm: { events: [ProcessorEvent.span, ProcessorEvent.transaction], }, @@ -81,33 +69,18 @@ export async function getTraceItems( }, }); - const [errorResponse, traceResponse]: [ - // explicit intermediary types to avoid TS "excessively deep" error - PromiseValueType, - PromiseValueType - ] = (await Promise.all([errorResponsePromise, traceResponsePromise])) as any; + const [errorResponse, traceResponse] = await Promise.all([ + errorResponsePromise, + traceResponsePromise, + ]); const exceedsMax = traceResponse.hits.total.value > maxTraceItems; - - const items = traceResponse.hits.hits.map((hit) => hit._source); - - const errorFrequencies = { - errorDocs: errorResponse.hits.hits.map(({ _source }) => _source), - errorsPerTransaction: - errorResponse.aggregations?.by_transaction_id.buckets.reduce( - (acc, current) => { - return { - ...acc, - [current.key]: current.doc_count, - }; - }, - {} as Record - ) ?? {}, - }; + const traceDocs = traceResponse.hits.hits.map((hit) => hit._source); + const errorDocs = errorResponse.hits.hits.map((hit) => hit._source); return { - items, exceedsMax, - ...errorFrequencies, + traceDocs, + errorDocs, }; } diff --git a/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts b/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts index b66daf80bd7634..941eb796d3ab3d 100644 --- a/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts +++ b/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts @@ -72,10 +72,10 @@ export type APMServerRouteRepository = ReturnType< // Ensure no APIs return arrays (or, by proxy, the any type), // to guarantee compatibility with _inspect. -type CompositeEndpoint = EndpointOf; +export type APIEndpoint = EndpointOf; type EndpointReturnTypes = { - [Endpoint in CompositeEndpoint]: ReturnOf; + [Endpoint in APIEndpoint]: ReturnOf; }; type ArrayLikeReturnTypes = PickByValue; diff --git a/x-pack/plugins/apm/server/routes/traces.ts b/x-pack/plugins/apm/server/routes/traces.ts index 11747c847fcbdd..c5273b7650e56c 100644 --- a/x-pack/plugins/apm/server/routes/traces.ts +++ b/x-pack/plugins/apm/server/routes/traces.ts @@ -7,7 +7,7 @@ import * as t from 'io-ts'; import { setupRequest } from '../lib/helpers/setup_request'; -import { getTrace } from '../lib/traces/get_trace'; +import { getTraceItems } from '../lib/traces/get_trace_items'; import { getTopTransactionGroupList } from '../lib/transaction_groups'; import { createApmServerRoute } from './create_apm_server_route'; import { environmentRt, kueryRt, rangeRt } from './default_api_types'; @@ -52,7 +52,7 @@ const tracesByIdRoute = createApmServerRoute({ const { params } = resources; const { traceId } = params.path; - return getTrace(traceId, setup); + return getTraceItems(traceId, setup); }, }); diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts index 4865396cae7b24..1de497f2c7cd74 100644 --- a/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts +++ b/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts @@ -17,6 +17,7 @@ interface Processor { export interface SpanRaw extends APMBaseDoc { processor: Processor; trace: { id: string }; // trace is required + event?: { outcome?: 'success' | 'failure' }; service: { name: string; environment?: string; diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts index cefff756963efc..d6154d7ad4d236 100644 --- a/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts +++ b/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts @@ -28,6 +28,7 @@ export interface TransactionRaw extends APMBaseDoc { processor: Processor; timestamp: TimestampUs; trace: { id: string }; // trace is required + event?: { outcome?: 'success' | 'failure' }; transaction: { duration: { us: number }; id: string; diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d5022fb43da04c..2d30e0dcbbd8c5 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7140,7 +7140,6 @@ "xpack.apm.transactionDetails.distribution.panelTitle": "延迟分布", "xpack.apm.transactionDetails.emptySelectionText": "单击并拖动以选择范围", "xpack.apm.transactionDetails.errorCount": "{errorCount, number} 个 {errorCount, plural, other {错误}}", - "xpack.apm.transactionDetails.errorsOverviewLinkTooltip": "{errorCount, plural, one {查看 1 个相关错误} other {查看 # 个相关错误}}", "xpack.apm.transactionDetails.noTraceParentButtonTooltip": "找不到上级追溯", "xpack.apm.transactionDetails.percentOfTraceLabelExplanation": "{parentType, select, transaction {事务} trace {追溯} }的百分比超过 100%,因为此{childType, select, span {跨度} transaction {事务} }比根事务花费更长的时间。", "xpack.apm.transactionDetails.requestMethodLabel": "请求方法", diff --git a/x-pack/test/apm_api_integration/common/apm_api_supertest.ts b/x-pack/test/apm_api_integration/common/apm_api_supertest.ts index f930cab3b0568c..b9470f39b507f6 100644 --- a/x-pack/test/apm_api_integration/common/apm_api_supertest.ts +++ b/x-pack/test/apm_api_integration/common/apm_api_supertest.ts @@ -11,11 +11,11 @@ import request from 'superagent'; import { parseEndpoint } from '../../../plugins/apm/common/apm_api/parse_endpoint'; import type { APIReturnType, - APIEndpoint, APIClientRequestParamsOf, } from '../../../plugins/apm/public/services/rest/createCallApmApi'; +import type { APIEndpoint } from '../../../plugins/apm/server'; -export function createSupertestClient(st: supertest.SuperTest) { +export function createApmApiClient(st: supertest.SuperTest) { return async ( options: { endpoint: TEndpoint; @@ -41,7 +41,7 @@ export function createSupertestClient(st: supertest.SuperTest) { }; } -export type ApmApiSupertest = ReturnType; +export type ApmApiSupertest = ReturnType; export class ApmApiError extends Error { res: request.Response; diff --git a/x-pack/test/apm_api_integration/common/config.ts b/x-pack/test/apm_api_integration/common/config.ts index e8d777814402f8..a8c5c433df45ee 100644 --- a/x-pack/test/apm_api_integration/common/config.ts +++ b/x-pack/test/apm_api_integration/common/config.ts @@ -13,7 +13,7 @@ import { InheritedFtrProviderContext, InheritedServices } from './ftr_provider_c import { PromiseReturnType } from '../../../plugins/observability/typings/common'; import { createApmUser, APM_TEST_PASSWORD, ApmUser } from './authentication'; import { APMFtrConfigName } from '../configs'; -import { createSupertestClient } from './apm_api_supertest'; +import { createApmApiClient } from './apm_api_supertest'; import { registry } from './registry'; interface Config { @@ -52,7 +52,7 @@ async function getApmApiClient( auth: `${apmUser}:${APM_TEST_PASSWORD}`, }); - return createSupertestClient(supertest(url)); + return createApmApiClient(supertest(url)); } export type CreateTestConfig = ReturnType; diff --git a/x-pack/test/apm_api_integration/tests/index.ts b/x-pack/test/apm_api_integration/tests/index.ts index c8a57bc613a929..c0690fd2f82606 100644 --- a/x-pack/test/apm_api_integration/tests/index.ts +++ b/x-pack/test/apm_api_integration/tests/index.ts @@ -157,6 +157,9 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte describe('traces/top_traces', function () { loadTestFile(require.resolve('./traces/top_traces')); }); + describe('/api/apm/traces/{traceId}', function () { + loadTestFile(require.resolve('./traces/trace_by_id')); + }); // transactions describe('transactions/breakdown', function () { diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts b/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts index 40bfbbb699e655..0fa64f25520d49 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts @@ -11,13 +11,13 @@ import archives from '../../common/fixtures/es_archiver/archives_metadata'; import { registry } from '../../common/registry'; import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; import { getServiceNodeIds } from './get_service_node_ids'; -import { createSupertestClient } from '../../common/apm_api_supertest'; +import { createApmApiClient } from '../../common/apm_api_supertest'; type ServiceOverviewInstanceDetails = APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); - const apmApiSupertest = createSupertestClient(supertest); + const apmApiSupertest = createApmApiClient(supertest); const archiveName = 'apm_8.0.0'; const { start, end } = archives[archiveName]; diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.ts b/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.ts index ffadb7fcf78016..1ad272bafaa808 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.ts @@ -14,12 +14,12 @@ import { APIReturnType } from '../../../../plugins/apm/public/services/rest/crea import { FtrProviderContext } from '../../common/ftr_provider_context'; import archives from '../../common/fixtures/es_archiver/archives_metadata'; import { registry } from '../../common/registry'; -import { createSupertestClient } from '../../common/apm_api_supertest'; +import { createApmApiClient } from '../../common/apm_api_supertest'; import { getServiceNodeIds } from './get_service_node_ids'; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); - const apmApiSupertest = createSupertestClient(supertest); + const apmApiSupertest = createApmApiClient(supertest); const archiveName = 'apm_8.0.0'; const { start, end } = archives[archiveName]; diff --git a/x-pack/test/apm_api_integration/tests/services/error_groups_detailed_statistics.ts b/x-pack/test/apm_api_integration/tests/services/error_groups_detailed_statistics.ts index 24507c1e427084..959e77397c37d6 100644 --- a/x-pack/test/apm_api_integration/tests/services/error_groups_detailed_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/services/error_groups_detailed_statistics.ts @@ -12,14 +12,14 @@ import archives_metadata from '../../common/fixtures/es_archiver/archives_metada import { FtrProviderContext } from '../../common/ftr_provider_context'; import { registry } from '../../common/registry'; import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; -import { createSupertestClient } from '../../common/apm_api_supertest'; +import { createApmApiClient } from '../../common/apm_api_supertest'; import { getErrorGroupIds } from './get_error_group_ids'; type ErrorGroupsDetailedStatistics = APIReturnType<'GET /api/apm/services/{serviceName}/error_groups/detailed_statistics'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); - const apmApiSupertest = createSupertestClient(supertest); + const apmApiSupertest = createApmApiClient(supertest); const archiveName = 'apm_8.0.0'; const metadata = archives_metadata[archiveName]; diff --git a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.tsx b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.tsx new file mode 100644 index 00000000000000..5b4ab5f45da497 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.tsx @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import archives_metadata from '../../common/fixtures/es_archiver/archives_metadata'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { registry } from '../../common/registry'; +import { createApmApiClient, SupertestReturnType } from '../../common/apm_api_supertest'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const apmApiSupertest = createApmApiClient(supertest); + + const archiveName = 'apm_8.0.0'; + const metadata = archives_metadata[archiveName]; + const { start, end } = metadata; + + registry.when('Trace does not exist', { config: 'basic', archives: [] }, () => { + it('handles empty state', async () => { + const response = await apmApiSupertest({ + endpoint: `GET /api/apm/traces/{traceId}`, + params: { + path: { traceId: 'foo' }, + query: { start, end }, + }, + }); + + expect(response.status).to.be(200); + expect(response.body).to.eql({ exceedsMax: false, traceDocs: [], errorDocs: [] }); + }); + }); + + registry.when('Trace exists', { config: 'basic', archives: [archiveName] }, () => { + let response: SupertestReturnType<`GET /api/apm/traces/{traceId}`>; + before(async () => { + response = await apmApiSupertest({ + endpoint: `GET /api/apm/traces/{traceId}`, + params: { + path: { traceId: '64d0014f7530df24e549dd17cc0a8895' }, + query: { start, end }, + }, + }); + }); + + it('returns the correct status code', async () => { + expect(response.status).to.be(200); + }); + + it('returns the correct number of buckets', async () => { + expectSnapshot(response.body.errorDocs.map((doc) => doc.error?.exception?.[0]?.message)) + .toMatchInline(` + Array [ + "Test CaptureError", + "Uncaught Error: Test Error in dashboard", + ] + `); + expectSnapshot( + response.body.traceDocs.map((doc) => + doc.processor.event === 'transaction' + ? // @ts-expect-error + `${doc.transaction.name} (transaction)` + : // @ts-expect-error + `${doc.span.name} (span)` + ) + ).toMatchInline(` + Array [ + "/dashboard (transaction)", + "GET /api/stats (transaction)", + "APIRestController#topProducts (transaction)", + "Parsing the document, executing sync. scripts (span)", + "GET /api/products/top (span)", + "GET /api/stats (span)", + "Requesting and receiving the document (span)", + "SELECT FROM customers (span)", + "SELECT FROM order_lines (span)", + "http://opbeans-frontend:3000/static/css/main.7bd7c5e8.css (span)", + "SELECT FROM products (span)", + "SELECT FROM orders (span)", + "SELECT FROM order_lines (span)", + "Making a connection to the server (span)", + "Fire \\"load\\" event (span)", + "empty query (span)", + ] + `); + expectSnapshot(response.body.exceedsMax).toMatchInline(`false`); + }); + }); +}