Skip to content

Commit a6bb528

Browse files
[9.2] [APM] Transaction routes to use accessKnownApmEventFields (elastic#243502) (elastic#243800)
# Backport This will backport the following commits from `main` to `9.2`: - [[APM] Transaction routes to use `accessKnownApmEventFields` (elastic#243502)](elastic#243502) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Gonçalo Rica Pais da Silva","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-11-21T12:22:48Z","message":"[APM] Transaction routes to use `accessKnownApmEventFields` (elastic#243502)\n\n## Summary\n\nCloses [elastic#243370](https://github.com/elastic/kibana/issues/243370)\n\nThe rest of the `transaction` routes in APM being updated to make use of\n`accessKnownApmEventFields`, along with removing some `lodash` usages\nwhere native JS equivalents are available.\n\n## How to test\n\n- Go to Discover on an Observability space, select a traces index (APM\nand/or OTEL) in either Classic or ES|QL.\n- Select a trace with either an event.outcome as failure or status.code\nas Error. On spans/transactions with an error attached to it, it should\nshow on both the focused and full trace waterfall without any issue.\n- Going through to the APM page via the trace.id link, the APM trace\nwaterfall should also show the same errors with no issue.\n- Clicking on a trace span should open up to show the Span details\nwithout issue/regression.\n- Trace samples should be available without issue/regression.","sha":"89afdb36bf577a7ec847e85e53cd85eef1283b6d","branchLabelMapping":{"^v9.3.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:obs-ux-infra_services","backport:version","v9.3.0","Team:obs-exploration","ci:beta-faster-pr-build","v8.19.8","v9.2.2","v9.1.8"],"title":"[APM] Transaction routes to use `accessKnownApmEventFields`","number":243502,"url":"https://github.com/elastic/kibana/pull/243502","mergeCommit":{"message":"[APM] Transaction routes to use `accessKnownApmEventFields` (elastic#243502)\n\n## Summary\n\nCloses [elastic#243370](https://github.com/elastic/kibana/issues/243370)\n\nThe rest of the `transaction` routes in APM being updated to make use of\n`accessKnownApmEventFields`, along with removing some `lodash` usages\nwhere native JS equivalents are available.\n\n## How to test\n\n- Go to Discover on an Observability space, select a traces index (APM\nand/or OTEL) in either Classic or ES|QL.\n- Select a trace with either an event.outcome as failure or status.code\nas Error. On spans/transactions with an error attached to it, it should\nshow on both the focused and full trace waterfall without any issue.\n- Going through to the APM page via the trace.id link, the APM trace\nwaterfall should also show the same errors with no issue.\n- Clicking on a trace span should open up to show the Span details\nwithout issue/regression.\n- Trace samples should be available without issue/regression.","sha":"89afdb36bf577a7ec847e85e53cd85eef1283b6d"}},"sourceBranch":"main","suggestedTargetBranches":["8.19","9.2","9.1"],"targetPullRequestStates":[{"branch":"main","label":"v9.3.0","branchLabelMappingKey":"^v9.3.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/243502","number":243502,"mergeCommit":{"message":"[APM] Transaction routes to use `accessKnownApmEventFields` (elastic#243502)\n\n## Summary\n\nCloses [elastic#243370](https://github.com/elastic/kibana/issues/243370)\n\nThe rest of the `transaction` routes in APM being updated to make use of\n`accessKnownApmEventFields`, along with removing some `lodash` usages\nwhere native JS equivalents are available.\n\n## How to test\n\n- Go to Discover on an Observability space, select a traces index (APM\nand/or OTEL) in either Classic or ES|QL.\n- Select a trace with either an event.outcome as failure or status.code\nas Error. On spans/transactions with an error attached to it, it should\nshow on both the focused and full trace waterfall without any issue.\n- Going through to the APM page via the trace.id link, the APM trace\nwaterfall should also show the same errors with no issue.\n- Clicking on a trace span should open up to show the Span details\nwithout issue/regression.\n- Trace samples should be available without issue/regression.","sha":"89afdb36bf577a7ec847e85e53cd85eef1283b6d"}},{"branch":"8.19","label":"v8.19.8","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.2","label":"v9.2.2","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.1","label":"v9.1.8","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Gonçalo Rica Pais da Silva <[email protected]>
1 parent a6a668b commit a6bb528

File tree

6 files changed

+44
-34
lines changed

6 files changed

+44
-34
lines changed

x-pack/solutions/observability/plugins/apm/server/routes/transactions/breakdown/index.ts

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 2.0.
66
*/
77

8-
import { flatten, orderBy, last, clamp, round } from 'lodash';
8+
import { orderBy, last, clamp, round } from 'lodash';
99
import { rangeQuery, kqlQuery } from '@kbn/observability-plugin/server';
1010
import { ProcessorEvent } from '@kbn/observability-plugin/common';
1111
import { asPercent } from '../../../../common/utils/formatters';
@@ -136,24 +136,21 @@ export async function getTransactionBreakdown({
136136
) => {
137137
const sumAllSelfTimes = aggs.sum_all_self_times.value || 0;
138138

139-
const breakdowns = flatten(
140-
aggs.types.buckets.map((bucket) => {
141-
const type = bucket.key as string;
142-
143-
return bucket.subtypes.buckets.map((subBucket) => {
144-
const percentageRaw =
145-
(subBucket.total_self_time_per_subtype.value || 0) / sumAllSelfTimes;
146-
// limit percentage from 0% to 100% and
147-
// round to 8 decimal points (results in 6 decimal points after converting to percentages) to prevent displaying scientific notation in charts
148-
const percentage = round(clamp(percentageRaw, 0, 1), 8);
149-
150-
return {
151-
name: (subBucket.key as string) || type,
152-
percentage,
153-
};
154-
});
155-
})
156-
);
139+
const breakdowns = aggs.types.buckets.flatMap((bucket) => {
140+
const type = bucket.key as string;
141+
142+
return bucket.subtypes.buckets.map((subBucket) => {
143+
const percentageRaw = (subBucket.total_self_time_per_subtype.value || 0) / sumAllSelfTimes;
144+
// limit percentage from 0% to 100% and
145+
// round to 8 decimal points (results in 6 decimal points after converting to percentages) to prevent displaying scientific notation in charts
146+
const percentage = round(clamp(percentageRaw, 0, 1), 8);
147+
148+
return {
149+
name: (subBucket.key as string) || type,
150+
percentage,
151+
};
152+
});
153+
});
157154

158155
return breakdowns;
159156
};

x-pack/solutions/observability/plugins/apm/server/routes/transactions/get_span/index.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
import { rangeQuery, termQuery } from '@kbn/observability-plugin/server';
99
import { ProcessorEvent } from '@kbn/observability-plugin/common';
10-
import { unflattenKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
10+
import { accessKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
1111
import type { FlattenedApmEvent } from '@kbn/apm-data-access-plugin/server/utils/utility_types';
12-
import { merge, omit } from 'lodash';
12+
import { merge } from 'lodash';
1313
import { maybe } from '../../../../common/utils/maybe';
1414
import { SPAN_ID, SPAN_STACKTRACE, TRACE_ID } from '../../../../common/es_fields/apm';
1515
import { asMutableArray } from '../../../../common/utils/as_mutable_array';
@@ -67,11 +67,16 @@ export async function getSpan({
6767
const hit = maybe(spanResp.hits.hits[0]);
6868
const spanFromSource = hit && 'span' in hit._source ? hit._source : undefined;
6969

70-
const event = unflattenKnownApmEventFields(hit?.fields as undefined | FlattenedApmEvent);
70+
const { span, ...event } =
71+
(hit?.fields &&
72+
accessKnownApmEventFields(hit.fields as Partial<FlattenedApmEvent>).unflatten()) ??
73+
{};
74+
75+
const { links, ...rest } = span ?? {};
7176

7277
return {
73-
span: event
74-
? merge({}, omit(event, 'span.links'), spanFromSource, {
78+
span: hit
79+
? merge(event, { span: rest }, spanFromSource, {
7580
processor: { event: 'span' as const, name: 'transaction' as const },
7681
})
7782
: undefined,

x-pack/solutions/observability/plugins/apm/server/routes/transactions/get_transaction_by_name/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { rangeQuery } from '@kbn/observability-plugin/server';
9-
import { unflattenKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
9+
import { accessKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
1010
import { maybe } from '../../../../common/utils/maybe';
1111
import { ApmDocumentType } from '../../../../common/document_type';
1212
import {
@@ -70,5 +70,7 @@ export async function getTransactionByName({
7070
fields: requiredFields,
7171
});
7272

73-
return unflattenKnownApmEventFields(maybe(resp.hits.hits[0])?.fields, requiredFields);
73+
const fields = maybe(resp.hits.hits[0])?.fields;
74+
75+
return fields && accessKnownApmEventFields(fields).requireFields(requiredFields).unflatten();
7476
}

x-pack/solutions/observability/plugins/apm/server/routes/transactions/get_transaction_by_trace/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import { ProcessorEvent } from '@kbn/observability-plugin/common';
99
import { rangeQuery } from '@kbn/observability-plugin/server';
10-
import { unflattenKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
10+
import { accessKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
1111
import { maybe } from '../../../../common/utils/maybe';
1212
import { asMutableArray } from '../../../../common/utils/as_mutable_array';
1313
import {
@@ -92,7 +92,10 @@ export async function getRootTransactionByTraceId({
9292

9393
const resp = await apmEventClient.search('get_root_transaction_by_trace_id', params);
9494

95-
const event = unflattenKnownApmEventFields(maybe(resp.hits.hits[0])?.fields, requiredFields);
95+
const fields = maybe(resp.hits.hits[0])?.fields;
96+
97+
const event =
98+
fields && accessKnownApmEventFields(fields).requireFields(requiredFields).unflatten();
9699

97100
return {
98101
transaction: event,

x-pack/solutions/observability/plugins/apm/server/routes/transactions/route.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,10 @@ const transactionGroupsMainStatisticsRoute = createApmServerRoute({
7171
security: { authz: { requiredPrivileges: ['apm'] } },
7272
handler: async (resources): Promise<MergedServiceTransactionGroupsResponse> => {
7373
const { params } = resources;
74-
const apmEventClient = await getApmEventClient(resources);
75-
const apmAlertsClient = await getApmAlertsClient(resources);
74+
const [apmEventClient, apmAlertsClient] = await Promise.all([
75+
getApmEventClient(resources),
76+
getApmAlertsClient(resources),
77+
]);
7678

7779
const {
7880
path: { serviceName },

x-pack/solutions/observability/plugins/apm/server/routes/transactions/trace_samples/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import type { Sort, QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
88
import { ProcessorEvent } from '@kbn/observability-plugin/common';
99
import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server';
10-
import { unflattenKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
10+
import { accessKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
1111
import { asMutableArray } from '../../../../common/utils/as_mutable_array';
1212
import {
1313
AT_TIMESTAMP,
@@ -114,12 +114,13 @@ export async function getTraceSamples({
114114
});
115115

116116
const traceSamples = response.hits.hits.map((hit) => {
117-
const event = unflattenKnownApmEventFields(hit.fields, requiredFields);
117+
const event = accessKnownApmEventFields(hit.fields).requireFields(requiredFields);
118+
118119
return {
119120
score: hit._score,
120121
timestamp: event[AT_TIMESTAMP],
121-
transactionId: event.transaction.id,
122-
traceId: event.trace.id,
122+
transactionId: event[TRANSACTION_ID],
123+
traceId: event[TRACE_ID],
123124
};
124125
});
125126

0 commit comments

Comments
 (0)