From 21003c143b69ee08b04c0a2d2a5f684721146129 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:26:31 -0400 Subject: [PATCH] [8.9] [APM] Add range query to transaction/span GETs (#161643) (#161899) # Backport This will backport the following commits from `main` to `8.9`: - [[APM] Add range query to transaction/span GETs (#161643)](https://github.com/elastic/kibana/pull/161643) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) Co-authored-by: Dario Gieselaar --- .../components/app/trace_link/index.tsx | 12 +++- .../waterfall/span_flyout/index.tsx | 11 +++- .../span_flyout/span_flyout.stories.tsx | 2 + .../waterfall/transaction_flyout/index.tsx | 8 ++- .../transaction_flyout.stories.tsx | 2 + .../waterfall/waterfall_flyout.tsx | 9 ++- .../components/app/transaction_link/index.tsx | 12 +++- .../settings/agent_configuration/route.ts | 5 +- .../plugins/apm/server/routes/traces/route.ts | 55 +++++++++++++++---- .../__snapshots__/queries.test.ts.snap | 10 ++++ .../routes/transactions/get_span/index.ts | 10 +++- .../transactions/get_transaction/index.ts | 7 ++- .../get_transaction_by_trace/index.ts | 22 ++++++-- x-pack/plugins/apm/server/routes/typings.ts | 2 - .../tests/traces/span_details.spec.ts | 6 +- .../tests/traces/transaction_details.spec.ts | 9 ++- 16 files changed, 149 insertions(+), 33 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/trace_link/index.tsx b/x-pack/plugins/apm/public/components/app/trace_link/index.tsx index 689531e912829..187d060524242 100644 --- a/x-pack/plugins/apm/public/components/app/trace_link/index.tsx +++ b/x-pack/plugins/apm/public/components/app/trace_link/index.tsx @@ -13,6 +13,7 @@ import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { getRedirectToTransactionDetailPageUrl } from './get_redirect_to_transaction_detail_page_url'; import { getRedirectToTracePageUrl } from './get_redirect_to_trace_page_url'; import { useApmParams } from '../../../hooks/use_apm_params'; +import { useTimeRange } from '../../../hooks/use_time_range'; const CentralizedContainer = euiStyled.div` height: 100%; @@ -25,6 +26,11 @@ export function TraceLink() { query: { rangeFrom, rangeTo }, } = useApmParams('/link-to/trace/{traceId}'); + const { start, end } = useTimeRange({ + rangeFrom: rangeFrom || new Date(0).toISOString(), + rangeTo: rangeTo || new Date().toISOString(), + }); + const { data = { transaction: null }, status } = useFetcher( (callApmApi) => { if (traceId) { @@ -35,12 +41,16 @@ export function TraceLink() { path: { traceId, }, + query: { + start, + end, + }, }, } ); } }, - [traceId] + [traceId, start, end] ); if (traceId && status === FETCH_STATUS.SUCCESS) { const to = data.transaction 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 790bba5f61cc4..77a3f7d00955f 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 @@ -94,6 +94,8 @@ interface Props { spanLinksCount: SpanLinksCount; flyoutDetailTab?: string; onClose: () => void; + start: string; + end: string; } const INITIAL_DATA = { @@ -109,14 +111,19 @@ export function SpanFlyout({ onClose, spanLinksCount, flyoutDetailTab, + start, + end, }: Props) { const { data = INITIAL_DATA, status } = useFetcher( (callApmApi) => { return callApmApi('GET /internal/apm/traces/{traceId}/spans/{spanId}', { - params: { path: { traceId, spanId }, query: { parentTransactionId } }, + params: { + path: { traceId, spanId }, + query: { parentTransactionId, start, end }, + }, }); }, - [traceId, spanId, parentTransactionId] + [traceId, spanId, parentTransactionId, start, end] ); const { span, parentTransaction } = data; diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/span_flyout.stories.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/span_flyout.stories.tsx index 2cb49d58c5a34..9ef03fa61dcf4 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/span_flyout.stories.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/span_flyout.stories.tsx @@ -101,6 +101,8 @@ export const TransactionSpan: Story = () => { spanLinksCount={{ linkedChildren: 0, linkedParents: 0 }} parentTransactionId={data.spanEvent['parent.id']} onClose={() => {}} + start="fake-time" + end="fake-time" /> ); }; diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/transaction_flyout/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/transaction_flyout/index.tsx index 263fe8b3414f2..012d3006f79ac 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/transaction_flyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/transaction_flyout/index.tsx @@ -39,6 +39,8 @@ interface Props { rootTransactionDuration?: number; spanLinksCount: SpanLinksCount; flyoutDetailTab?: string; + start: string; + end: string; } export function TransactionFlyout({ @@ -49,15 +51,17 @@ export function TransactionFlyout({ rootTransactionDuration, spanLinksCount, flyoutDetailTab, + start, + end, }: Props) { const { data: transaction, status } = useFetcher( (callApmApi) => { return callApmApi( 'GET /internal/apm/traces/{traceId}/transactions/{transactionId}', - { params: { path: { traceId, transactionId } } } + { params: { path: { traceId, transactionId }, query: { start, end } } } ); }, - [traceId, transactionId] + [traceId, transactionId, start, end] ); const isLoading = isPending(status); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/transaction_flyout/transaction_flyout.stories.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/transaction_flyout/transaction_flyout.stories.tsx index 131df94a4ad8c..60114f506eb01 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/transaction_flyout/transaction_flyout.stories.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/transaction_flyout/transaction_flyout.stories.tsx @@ -84,6 +84,8 @@ export const Example: Story = () => { transactionId={data.transactionEvent['transaction.id']!} traceId={data.transactionEvent['trace.id']!} spanLinksCount={{ linkedChildren: 0, linkedParents: 0 }} + start="fake-time" + end="fake-time" /> ); }; 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 29521134ff076..57c6ade4c886d 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 @@ -9,6 +9,7 @@ import { History } from 'history'; import React from 'react'; import { useHistory } from 'react-router-dom'; import { useAnyOfApmParams } from '../../../../../../hooks/use_apm_params'; +import { useTimeRange } from '../../../../../../hooks/use_time_range'; import { SpanFlyout } from './span_flyout'; import { TransactionFlyout } from './transaction_flyout'; import { IWaterfall } from './waterfall_helpers/waterfall_helpers'; @@ -32,7 +33,7 @@ export function WaterfallFlyout({ }: Props) { const history = useHistory(); const { - query: { flyoutDetailTab }, + query: { flyoutDetailTab, rangeFrom, rangeTo }, } = useAnyOfApmParams( '/services/{serviceName}/transactions/view', '/mobile-services/{serviceName}/transactions/view', @@ -43,6 +44,8 @@ export function WaterfallFlyout({ (item) => item.id === waterfallItemId ); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + if (!currentItem) { return null; } @@ -63,6 +66,8 @@ export function WaterfallFlyout({ onClose={() => toggleFlyout({ history })} spanLinksCount={currentItem.spanLinksCount} flyoutDetailTab={flyoutDetailTab} + start={start} + end={end} /> ); case 'transaction': @@ -75,6 +80,8 @@ export function WaterfallFlyout({ errorCount={waterfall.getErrorCount(currentItem.id)} spanLinksCount={currentItem.spanLinksCount} flyoutDetailTab={flyoutDetailTab} + start={start} + end={end} /> ); default: diff --git a/x-pack/plugins/apm/public/components/app/transaction_link/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_link/index.tsx index 720d3feee581a..0cd5799cc7bc9 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_link/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_link/index.tsx @@ -12,6 +12,7 @@ import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { getRedirectToTransactionDetailPageUrl } from '../trace_link/get_redirect_to_transaction_detail_page_url'; import { useApmParams } from '../../../hooks/use_apm_params'; +import { useTimeRange } from '../../../hooks/use_time_range'; const CentralizedContainer = euiStyled.div` height: 100%; @@ -24,6 +25,11 @@ export function TransactionLink() { query: { rangeFrom, rangeTo, waterfallItemId }, } = useApmParams('/link-to/transaction/{transactionId}'); + const { start, end } = useTimeRange({ + rangeFrom: rangeFrom || new Date(0).toISOString(), + rangeTo: rangeTo || new Date().toISOString(), + }); + const { data = { transaction: null }, status } = useFetcher( (callApmApi) => { if (transactionId) { @@ -32,11 +38,15 @@ export function TransactionLink() { path: { transactionId, }, + query: { + start, + end, + }, }, }); } }, - [transactionId] + [transactionId, start, end] ); if (transactionId && status === FETCH_STATUS.SUCCESS) { if (data.transaction) { diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts index 64e580fab30ec..ffadf970dc414 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts @@ -343,14 +343,13 @@ const listAgentConfigurationEnvironmentsRoute = createApmServerRoute({ ]); const coreContext = await context.core; - const { serviceName, start, end } = params.query; + const { serviceName } = params.query; const searchAggregatedTransactions = await getSearchTransactionsEvents({ apmEventClient, config, kuery: '', - start, - end, }); + const size = await coreContext.uiSettings.client.get( maxSuggestions ); diff --git a/x-pack/plugins/apm/server/routes/traces/route.ts b/x-pack/plugins/apm/server/routes/traces/route.ts index 77e9e336966e2..70b242534d3da 100644 --- a/x-pack/plugins/apm/server/routes/traces/route.ts +++ b/x-pack/plugins/apm/server/routes/traces/route.ts @@ -103,6 +103,8 @@ const tracesByIdRoute = createApmServerRoute({ transactionId: entryTransactionId, traceId, apmEventClient, + start, + end, }), ]); return { @@ -118,6 +120,7 @@ const rootTransactionByTraceIdRoute = createApmServerRoute({ path: t.type({ traceId: t.string, }), + query: rangeRt, }), options: { tags: ['access:apm'] }, handler: async ( @@ -125,10 +128,16 @@ const rootTransactionByTraceIdRoute = createApmServerRoute({ ): Promise<{ transaction: Transaction; }> => { - const { params } = resources; - const { traceId } = params.path; + const { + params: { + path: { traceId }, + query: { start, end }, + }, + } = resources; + const apmEventClient = await getApmEventClient(resources); - return getRootTransactionByTraceId(traceId, apmEventClient); + + return getRootTransactionByTraceId({ traceId, apmEventClient, start, end }); }, }); @@ -138,6 +147,7 @@ const transactionByIdRoute = createApmServerRoute({ path: t.type({ transactionId: t.string, }), + query: rangeRt, }), options: { tags: ['access:apm'] }, handler: async ( @@ -145,11 +155,21 @@ const transactionByIdRoute = createApmServerRoute({ ): Promise<{ transaction: Transaction; }> => { - const { params } = resources; - const { transactionId } = params.path; + const { + params: { + path: { transactionId }, + query: { start, end }, + }, + } = resources; + const apmEventClient = await getApmEventClient(resources); return { - transaction: await getTransaction({ transactionId, apmEventClient }), + transaction: await getTransaction({ + transactionId, + apmEventClient, + start, + end, + }), }; }, }); @@ -239,16 +259,23 @@ const transactionFromTraceByIdRoute = createApmServerRoute({ traceId: t.string, transactionId: t.string, }), + query: rangeRt, }), options: { tags: ['access:apm'] }, handler: async (resources): Promise => { const { params } = resources; - const { transactionId, traceId } = params.path; + const { + path: { transactionId, traceId }, + query: { start, end }, + } = params; + const apmEventClient = await getApmEventClient(resources); return await getTransaction({ transactionId, traceId, apmEventClient, + start, + end, }); }, }); @@ -260,7 +287,10 @@ const spanFromTraceByIdRoute = createApmServerRoute({ traceId: t.string, spanId: t.string, }), - query: t.union([t.partial({ parentTransactionId: t.string }), t.undefined]), + query: t.intersection([ + rangeRt, + t.union([t.partial({ parentTransactionId: t.string }), t.undefined]), + ]), }), options: { tags: ['access:apm'] }, handler: async ( @@ -270,14 +300,19 @@ const spanFromTraceByIdRoute = createApmServerRoute({ parentTransaction?: Transaction; }> => { const { params } = resources; - const { spanId, traceId } = params.path; - const { parentTransactionId } = params.query; + const { + path: { spanId, traceId }, + query: { start, end, parentTransactionId }, + } = params; + const apmEventClient = await getApmEventClient(resources); return await getSpan({ spanId, parentTransactionId, traceId, apmEventClient, + start, + end, }); }, }); diff --git a/x-pack/plugins/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap index e02f473f93be9..4ff86970a611a 100644 --- a/x-pack/plugins/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap @@ -21,10 +21,20 @@ Object { "trace.id": "bar", }, }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 0, + "lte": 50000, + }, + }, + }, ], }, }, "size": 1, + "terminate_after": 1, "track_total_hits": false, }, } diff --git a/x-pack/plugins/apm/server/routes/transactions/get_span/index.ts b/x-pack/plugins/apm/server/routes/transactions/get_span/index.ts index 5d46bb9a02fd1..4e1b7020a98a6 100644 --- a/x-pack/plugins/apm/server/routes/transactions/get_span/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/get_span/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { termQuery } from '@kbn/observability-plugin/server'; +import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { SPAN_ID, TRACE_ID } from '../../../../common/es_fields/apm'; import { asMutableArray } from '../../../../common/utils/as_mutable_array'; @@ -19,11 +19,15 @@ export async function getSpan({ traceId, parentTransactionId, apmEventClient, + start, + end, }: { spanId: string; traceId: string; parentTransactionId?: string; apmEventClient: APMEventClient; + start: number; + end: number; }): Promise<{ span?: Span; parentTransaction?: Transaction }> { const [spanResp, parentTransaction] = await Promise.all([ apmEventClient.search('get_span', { @@ -33,11 +37,13 @@ export async function getSpan({ body: { track_total_hits: false, size: 1, + terminate_after: 1, query: { bool: { filter: asMutableArray([ { term: { [SPAN_ID]: spanId } }, ...termQuery(TRACE_ID, traceId), + ...rangeQuery(start, end), ]), }, }, @@ -48,6 +54,8 @@ export async function getSpan({ apmEventClient, transactionId: parentTransactionId, traceId, + start, + end, }) : undefined, ]); diff --git a/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts b/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts index 2ec622ef4c723..77935244361b6 100644 --- a/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts @@ -21,8 +21,8 @@ export async function getTransaction({ transactionId: string; traceId?: string; apmEventClient: APMEventClient; - start?: number; - end?: number; + start: number; + end: number; }) { const resp = await apmEventClient.search('get_transaction', { apm: { @@ -31,12 +31,13 @@ export async function getTransaction({ body: { track_total_hits: false, size: 1, + terminate_after: 1, query: { bool: { filter: asMutableArray([ { term: { [TRANSACTION_ID]: transactionId } }, ...termQuery(TRACE_ID, traceId), - ...(start && end ? rangeQuery(start, end) : []), + ...rangeQuery(start, end), ]), }, }, diff --git a/x-pack/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts b/x-pack/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts index 807c4ef75b58c..350f3eb55385c 100644 --- a/x-pack/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts @@ -6,13 +6,21 @@ */ import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { rangeQuery } from '@kbn/observability-plugin/server'; import { TRACE_ID, PARENT_ID } from '../../../../common/es_fields/apm'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; -export async function getRootTransactionByTraceId( - traceId: string, - apmEventClient: APMEventClient -) { +export async function getRootTransactionByTraceId({ + traceId, + apmEventClient, + start, + end, +}: { + traceId: string; + apmEventClient: APMEventClient; + start: number; + end: number; +}) { const params = { apm: { events: [ProcessorEvent.transaction as const], @@ -20,6 +28,7 @@ export async function getRootTransactionByTraceId( body: { track_total_hits: false, size: 1, + terminate_after: 1, query: { bool: { should: [ @@ -33,7 +42,10 @@ export async function getRootTransactionByTraceId( }, }, ], - filter: [{ term: { [TRACE_ID]: traceId } }], + filter: [ + { term: { [TRACE_ID]: traceId } }, + ...rangeQuery(start, end), + ], }, }, }, diff --git a/x-pack/plugins/apm/server/routes/typings.ts b/x-pack/plugins/apm/server/routes/typings.ts index 36611a7559d75..5aea419b75c45 100644 --- a/x-pack/plugins/apm/server/routes/typings.ts +++ b/x-pack/plugins/apm/server/routes/typings.ts @@ -59,8 +59,6 @@ export interface APMRouteHandlerResources { params: { query: { _inspect: boolean; - start?: number; - end?: number; }; }; config: APMConfig; diff --git a/x-pack/test/apm_api_integration/tests/traces/span_details.spec.ts b/x-pack/test/apm_api_integration/tests/traces/span_details.spec.ts index 3361106423ccd..70988f731016e 100644 --- a/x-pack/test/apm_api_integration/tests/traces/span_details.spec.ts +++ b/x-pack/test/apm_api_integration/tests/traces/span_details.spec.ts @@ -30,7 +30,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { endpoint: `GET /internal/apm/traces/{traceId}/spans/{spanId}`, params: { path: { traceId, spanId }, - query: { parentTransactionId }, + query: { + parentTransactionId, + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + }, }, }); } diff --git a/x-pack/test/apm_api_integration/tests/traces/transaction_details.spec.ts b/x-pack/test/apm_api_integration/tests/traces/transaction_details.spec.ts index 532d286c5b3be..8bce601e921ee 100644 --- a/x-pack/test/apm_api_integration/tests/traces/transaction_details.spec.ts +++ b/x-pack/test/apm_api_integration/tests/traces/transaction_details.spec.ts @@ -27,7 +27,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { return await apmApiClient.readUser({ endpoint: `GET /internal/apm/traces/{traceId}/transactions/{transactionId}`, params: { - path: { traceId, transactionId }, + path: { + traceId, + transactionId, + }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + }, }, }); }