[APM] Add range query to transaction/span GETs (#161643)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Dario Gieselaar 2023-07-13 19:54:27 +02:00 committed by GitHub
parent 11cf01ea43
commit 6efac6268b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 149 additions and 33 deletions

View file

@ -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

View file

@ -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;

View file

@ -101,6 +101,8 @@ export const TransactionSpan: Story<Args> = () => {
spanLinksCount={{ linkedChildren: 0, linkedParents: 0 }}
parentTransactionId={data.spanEvent['parent.id']}
onClose={() => {}}
start="fake-time"
end="fake-time"
/>
);
};

View file

@ -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);

View file

@ -84,6 +84,8 @@ export const Example: Story<Args> = () => {
transactionId={data.transactionEvent['transaction.id']!}
traceId={data.transactionEvent['trace.id']!}
spanLinksCount={{ linkedChildren: 0, linkedParents: 0 }}
start="fake-time"
end="fake-time"
/>
);
};

View file

@ -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:

View file

@ -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) {

View file

@ -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<number>(
maxSuggestions
);

View file

@ -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<Transaction> => {
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,
});
},
});

View file

@ -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,
},
}

View file

@ -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,
]);

View file

@ -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),
]),
},
},

View file

@ -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),
],
},
},
},

View file

@ -60,8 +60,6 @@ export interface APMRouteHandlerResources {
params: {
query: {
_inspect: boolean;
start?: number;
end?: number;
};
};
config: APMConfig;

View file

@ -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(),
},
},
});
}

View file

@ -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(),
},
},
});
}