diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/ServiceLegends.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/ServiceLegends.tsx index 0ebadbe099e0..f511c9d93fec 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/ServiceLegends.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/ServiceLegends.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { EuiTitle } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; import { px, unit } from '../../../../../style/variables'; @@ -13,7 +14,7 @@ import Legend from '../../../../shared/charts/Legend'; const Legends = styled.div` display: flex; - div { + > * { margin-right: ${px(unit)}; &:last-child { margin-right: 0; @@ -30,6 +31,9 @@ interface Props { export function ServiceLegends({ serviceColors }: Props) { return ( + + Services + {Object.entries(serviceColors).map(([label, color]) => ( ))} diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts index 59b5cf7ba1d2..b8f169ff1635 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts @@ -4,7 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first, flatten, groupBy, indexBy, isEmpty, sortBy } from 'lodash'; +import { + first, + flatten, + groupBy, + indexBy, + isEmpty, + sortBy, + uniq +} from 'lodash'; import { Span } from '../../../../../../../../typings/Span'; import { Transaction } from '../../../../../../../../typings/Transaction'; @@ -124,16 +132,20 @@ export function getWaterfallItems( return getSortedChildren(entryTransactionItem); } -const getTraceRoot = (childrenByParentId: IWaterfallGroup) => { +function getTraceRoot(childrenByParentId: IWaterfallGroup) { const item = first(childrenByParentId.root); if (item && item.docType === 'transaction') { return item.transaction; } -}; +} + +function getServices(items: IWaterfallItem[]) { + const serviceNames = items.map(item => item.serviceName); + return uniq(serviceNames); +} export function getWaterfall( hits: Array, - services: string[], entryTransaction: Transaction ): IWaterfall { if (isEmpty(hits)) { @@ -186,7 +198,7 @@ export function getWaterfall( traceRoot, traceRootDuration: traceRoot && traceRoot.transaction.duration.us, duration: entryTransaction.transaction.duration.us, - services, + services: getServices(items), items, itemsById, getTransactionById diff --git a/x-pack/plugins/apm/public/components/shared/charts/Timeline/index.js b/x-pack/plugins/apm/public/components/shared/charts/Timeline/index.js index b018aee081db..711007341c50 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/Timeline/index.js +++ b/x-pack/plugins/apm/public/components/shared/charts/Timeline/index.js @@ -32,7 +32,7 @@ class Timeline extends PureComponent { Timeline.propTypes = { agentMarks: PropTypes.array, - duration: PropTypes.number.isRequired, + duration: PropTypes.number, height: PropTypes.number.isRequired, header: PropTypes.node, margins: PropTypes.object.isRequired, diff --git a/x-pack/plugins/apm/public/services/rest/apm.ts b/x-pack/plugins/apm/public/services/rest/apm.ts index 93980cbd5218..665a9cc7dfa9 100644 --- a/x-pack/plugins/apm/public/services/rest/apm.ts +++ b/x-pack/plugins/apm/public/services/rest/apm.ts @@ -180,7 +180,7 @@ export async function loadSpans({ } export async function loadTrace({ traceId, start, end }: IUrlParams) { - const result: WaterfallResponse = await callApi( + const hits: WaterfallResponse = await callApi( { pathname: `/api/apm/traces/${traceId}`, query: { @@ -193,8 +193,7 @@ export async function loadTrace({ traceId, start, end }: IUrlParams) { } ); - result.hits = result.hits.map(addVersion); - return result; + return hits.map(addVersion); } export async function loadTransaction({ diff --git a/x-pack/plugins/apm/public/store/reactReduxRequest/waterfall.tsx b/x-pack/plugins/apm/public/store/reactReduxRequest/waterfall.tsx index d291986e3bce..13038fdea15d 100644 --- a/x-pack/plugins/apm/public/store/reactReduxRequest/waterfall.tsx +++ b/x-pack/plugins/apm/public/store/reactReduxRequest/waterfall.tsx @@ -7,26 +7,18 @@ import React from 'react'; import { RRRRender } from 'react-redux-request'; import { Transaction } from 'x-pack/plugins/apm/typings/Transaction'; -import { WaterfallResponse } from 'x-pack/plugins/apm/typings/waterfall'; -import { - getWaterfall, - IWaterfall -} from '../../components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers'; +import { IWaterfall } from '../../components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers'; import { IUrlParams } from '../urlParams'; import { WaterfallV1Request } from './waterfallV1'; import { WaterfallV2Request } from './waterfallV2'; -interface WaterfallV1OrV2Props { +interface Props { urlParams: IUrlParams; transaction: Transaction; - render: RRRRender; + render: RRRRender; } -function WaterfallV1OrV2({ - urlParams, - transaction, - render -}: WaterfallV1OrV2Props) { +export function WaterfallRequest({ urlParams, transaction, render }: Props) { const hasTrace = transaction.hasOwnProperty('trace'); if (hasTrace) { return ( @@ -46,26 +38,3 @@ function WaterfallV1OrV2({ ); } } - -interface WaterfallRequestProps { - urlParams: IUrlParams; - transaction: Transaction; - render: RRRRender; -} - -export function WaterfallRequest({ - urlParams, - transaction, - render -}: WaterfallRequestProps) { - return ( - { - const waterfall = getWaterfall(data.hits, data.services, transaction); - return render({ status, args, data: waterfall }); - }} - /> - ); -} diff --git a/x-pack/plugins/apm/public/store/reactReduxRequest/waterfallV1.tsx b/x-pack/plugins/apm/public/store/reactReduxRequest/waterfallV1.tsx index 00b6709fc501..f04f37c5f60d 100644 --- a/x-pack/plugins/apm/public/store/reactReduxRequest/waterfallV1.tsx +++ b/x-pack/plugins/apm/public/store/reactReduxRequest/waterfallV1.tsx @@ -13,7 +13,10 @@ import { } from 'x-pack/plugins/apm/common/constants'; import { Span } from 'x-pack/plugins/apm/typings/Span'; import { Transaction } from 'x-pack/plugins/apm/typings/Transaction'; -import { WaterfallResponse } from 'x-pack/plugins/apm/typings/waterfall'; +import { + getWaterfall, + IWaterfall +} from '../../components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers'; import { loadSpans } from '../../services/rest/apm'; import { IUrlParams } from '../urlParams'; // @ts-ignore @@ -24,7 +27,7 @@ export const ID = 'waterfallV1'; interface Props { urlParams: IUrlParams; transaction: Transaction; - render: RRRRender; + render: RRRRender; } export function WaterfallV1Request({ urlParams, transaction, render }: Props) { @@ -42,12 +45,8 @@ export function WaterfallV1Request({ urlParams, transaction, render }: Props) { fn={loadSpans} args={[{ serviceName, start, end, transactionId }]} render={({ status, data = [], args }) => { - const res = { - hits: [transaction, ...data], - services: [serviceName] - }; - - return render({ status, data: res, args }); + const waterfall = getWaterfall([transaction, ...data], transaction); + return render({ status, data: waterfall, args }); }} /> ); diff --git a/x-pack/plugins/apm/public/store/reactReduxRequest/waterfallV2.tsx b/x-pack/plugins/apm/public/store/reactReduxRequest/waterfallV2.tsx index c5983f757409..43e4f65c91d4 100644 --- a/x-pack/plugins/apm/public/store/reactReduxRequest/waterfallV2.tsx +++ b/x-pack/plugins/apm/public/store/reactReduxRequest/waterfallV2.tsx @@ -10,6 +10,10 @@ import { Request, RRRRender } from 'react-redux-request'; import { TRACE_ID } from 'x-pack/plugins/apm/common/constants'; import { Transaction } from 'x-pack/plugins/apm/typings/Transaction'; import { WaterfallResponse } from 'x-pack/plugins/apm/typings/waterfall'; +import { + getWaterfall, + IWaterfall +} from '../../components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers'; import { loadTrace } from '../../services/rest/apm'; import { IUrlParams } from '../urlParams'; // @ts-ignore @@ -20,10 +24,9 @@ export const ID = 'waterfallV2'; interface Props { urlParams: IUrlParams; transaction: Transaction; - render: RRRRender; + render: RRRRender; } -const defaultData = { hits: [], services: [] }; export function WaterfallV2Request({ urlParams, transaction, render }: Props) { const { start, end } = urlParams; const traceId: string = get(transaction, TRACE_ID); @@ -37,9 +40,10 @@ export function WaterfallV2Request({ urlParams, transaction, render }: Props) { id={ID} fn={loadTrace} args={[{ traceId, start, end }]} - render={({ args, data = defaultData, status }) => - render({ args, data, status }) - } + render={({ args, data = [], status }) => { + const waterfall = getWaterfall(data, transaction); + return render({ args, data: waterfall, status }); + }} /> ); } diff --git a/x-pack/plugins/apm/server/lib/traces/get_trace.ts b/x-pack/plugins/apm/server/lib/traces/get_trace.ts index eb43e5a76185..b92e9e377e70 100644 --- a/x-pack/plugins/apm/server/lib/traces/get_trace.ts +++ b/x-pack/plugins/apm/server/lib/traces/get_trace.ts @@ -6,8 +6,7 @@ import { SearchParams, SearchResponse } from 'elasticsearch'; import { WaterfallResponse } from 'x-pack/plugins/apm/typings/waterfall'; -import { SERVICE_NAME, TRACE_ID } from '../../../common/constants'; -import { TermsAggsBucket } from '../../../typings/elasticsearch'; +import { TRACE_ID } from '../../../common/constants'; import { Span } from '../../../typings/Span'; import { Transaction } from '../../../typings/Transaction'; import { Setup } from '../helpers/setup_request'; @@ -37,14 +36,6 @@ export async function getTrace( } ] } - }, - aggs: { - services: { - terms: { - field: SERVICE_NAME, - size: 500 - } - } } } }; @@ -54,10 +45,5 @@ export async function getTrace( params ); - return { - services: (resp.aggregations.services.buckets as TermsAggsBucket[]).map( - bucket => bucket.key - ), - hits: resp.hits.hits.map(hit => hit._source) - }; + return resp.hits.hits.map(hit => hit._source); } diff --git a/x-pack/plugins/apm/typings/waterfall.ts b/x-pack/plugins/apm/typings/waterfall.ts index ad191907698d..d33cdcda65cc 100644 --- a/x-pack/plugins/apm/typings/waterfall.ts +++ b/x-pack/plugins/apm/typings/waterfall.ts @@ -7,7 +7,4 @@ import { Span } from './Span'; import { Transaction } from './Transaction'; -export interface WaterfallResponse { - services: string[]; - hits: Array; -} +export type WaterfallResponse = Array;