Skip to content

Commit 4965f58

Browse files
[APM] Refactor accessKnownApmEventFields usage in Diagnostic & Dependencies routes (#244173)
## Summary Closes #244142 This PR changes usages of `unflattenKnownApmEventFields` to `accessKnownApmEventFields` for the dependencies and diagnostics routes. The behaviour of these routes/APIs should remain the same as before. ## How to test - Ensure the Diagnostic Tool is enabled in Advanced Settings - Go to Discover on Observability mode, select a traces index and click through a trace to go to APM - Go to Service Map for a trace, enable the Diagnostic tool on a Service, go through process to check service connections are being recognised correctly. - Go to Dependencies, ensure they work correctly as before. CI must also pass with no regressions. --------- Co-authored-by: kibanamachine <[email protected]>
1 parent a6cc31e commit 4965f58

File tree

7 files changed

+89
-56
lines changed

7 files changed

+89
-56
lines changed

x-pack/solutions/observability/plugins/apm/server/routes/dependencies/get_metadata_for_dependency.ts

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

88
import { rangeQuery } 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 { asMutableArray } from '../../../common/utils/as_mutable_array';
1212
import { maybe } from '../../../common/utils/maybe';
1313
import {
@@ -58,10 +58,12 @@ export async function getMetadataForDependency({
5858
},
5959
});
6060

61-
const sample = unflattenKnownApmEventFields(maybe(sampleResponse.hits.hits[0])?.fields);
61+
const hitFields = maybe(sampleResponse.hits.hits[0])?.fields;
62+
63+
const sample = hitFields && accessKnownApmEventFields(hitFields);
6264

6365
return {
64-
spanType: sample?.span?.type,
65-
spanSubtype: sample?.span?.subtype,
66+
spanType: sample?.[SPAN_TYPE],
67+
spanSubtype: sample?.[SPAN_SUBTYPE],
6668
};
6769
}

x-pack/solutions/observability/plugins/apm/server/routes/dependencies/get_top_dependency_spans.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import { ProcessorEvent } from '@kbn/observability-plugin/common';
99
import { kqlQuery, rangeQuery, termQuery, termsQuery } from '@kbn/observability-plugin/server';
1010
import { keyBy } from 'lodash';
11-
import { unflattenKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
11+
import { accessKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
1212
import { asMutableArray } from '../../../common/utils/as_mutable_array';
1313
import {
1414
AGENT_NAME,
@@ -111,9 +111,11 @@ export async function getTopDependencySpans({
111111
},
112112
fields: topDedsRequiredFields,
113113
})
114-
).hits.hits.map((hit) => unflattenKnownApmEventFields(hit.fields, topDedsRequiredFields));
114+
).hits.hits.map((hit) =>
115+
accessKnownApmEventFields(hit.fields).requireFields(topDedsRequiredFields)
116+
);
115117

116-
const traceIds = spans.map((span) => span.trace.id);
118+
const traceIds = spans.map((span) => span[TRACE_ID]);
117119

118120
const txRequiredFields = asMutableArray([
119121
TRACE_ID,
@@ -139,25 +141,26 @@ export async function getTopDependencySpans({
139141
'@timestamp': 'desc',
140142
},
141143
})
142-
).hits.hits.map((hit) => unflattenKnownApmEventFields(hit.fields, txRequiredFields));
144+
).hits.hits.map((hit) => accessKnownApmEventFields(hit.fields).requireFields(txRequiredFields));
143145

144-
const transactionsByTraceId = keyBy(transactions, (transaction) => transaction.trace.id);
146+
const transactionsByTraceId = keyBy(transactions, (transaction) => transaction[TRACE_ID]);
145147

146148
return spans.map((span): DependencySpan => {
147-
const transaction = maybe(transactionsByTraceId[span.trace!.id]);
149+
const traceId = span[TRACE_ID];
150+
const transaction = maybe(transactionsByTraceId[traceId]);
148151

149152
return {
150-
'@timestamp': new Date(span['@timestamp']).getTime(),
151-
spanId: span.span.id,
152-
spanName: span.span.name,
153-
serviceName: span.service.name,
154-
agentName: span.agent.name,
155-
duration: span.span.duration.us,
156-
traceId: span.trace.id,
157-
outcome: (span.event?.outcome || EventOutcome.unknown) as EventOutcome,
158-
transactionId: transaction?.transaction.id,
159-
transactionType: transaction?.transaction.type,
160-
transactionName: transaction?.transaction.name,
153+
[AT_TIMESTAMP]: new Date(span[AT_TIMESTAMP]).getTime(),
154+
spanId: span[SPAN_ID],
155+
spanName: span[SPAN_NAME],
156+
serviceName: span[SERVICE_NAME],
157+
agentName: span[AGENT_NAME],
158+
duration: span[SPAN_DURATION],
159+
traceId,
160+
outcome: (span[EVENT_OUTCOME] || EventOutcome.unknown) as EventOutcome,
161+
transactionId: transaction?.[TRANSACTION_ID],
162+
transactionType: transaction?.[TRANSACTION_TYPE],
163+
transactionName: transaction?.[TRANSACTION_NAME],
161164
};
162165
});
163166
}

x-pack/solutions/observability/plugins/apm/server/routes/diagnostics/bundle/get_indices.ts

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

8-
import { compact, uniq } from 'lodash';
98
import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
109
import type { APMIndices } from '@kbn/apm-sources-access-plugin/server';
10+
import { compactMap } from '../../../utils/compact_map';
1111

1212
export function getApmIndexPatterns(indices: string[]) {
13-
return uniq(indices.flatMap((index): string[] => index.split(',')));
13+
return Array.from(new Set(indices.flatMap((index): string[] => index.split(','))));
1414
}
1515

1616
export async function getIndicesAndIngestPipelines({
@@ -35,12 +35,12 @@ export async function getIndicesAndIngestPipelines({
3535
ignore_unavailable: true,
3636
});
3737

38-
const pipelineIds = compact(
39-
uniq(Object.values(indices).map((index) => index.settings?.index?.default_pipeline))
40-
).join(',');
38+
const pipelineIds = Array.from(
39+
new Set(compactMap(Object.values(indices), (index) => index.settings?.index?.default_pipeline))
40+
);
4141

4242
const ingestPipelines = await esClient.ingest.getPipeline({
43-
id: pipelineIds,
43+
id: pipelineIds.join(','),
4444
filter_path: ['*.processors.grok.field', '*.processors.grok.patterns'],
4545
});
4646

x-pack/solutions/observability/plugins/apm/server/routes/diagnostics/bundle/get_non_data_stream_indices.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
99
import type { APMIndices } from '@kbn/apm-sources-access-plugin/server';
1010
import { getApmIndexPatterns } from './get_indices';
11+
import { compactMap } from '../../../utils/compact_map';
1112

1213
export async function getNonDataStreamIndices({
1314
esClient,
@@ -30,9 +31,14 @@ export async function getNonDataStreamIndices({
3031
ignore_unavailable: true,
3132
});
3233

33-
const nonDataStreamIndices = Object.entries(nonDataStreamIndicesResponse)
34-
.filter(([indexName, { data_stream: dataStream }]): boolean => !dataStream)
35-
.map(([indexName]): string => indexName);
34+
const nonDataStreamIndices = compactMap(
35+
Object.entries(nonDataStreamIndicesResponse),
36+
([indexName, { data_stream: dataStream }]) => {
37+
if (!dataStream) {
38+
return indexName;
39+
}
40+
}
41+
);
3642

3743
return nonDataStreamIndices;
3844
}

x-pack/solutions/observability/plugins/apm/server/routes/diagnostics/service_map/get_exit_spans_from_samples.ts

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

88
import { termQuery, rangeQuery, termsQuery } 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 { ESSearchResponse, ESSearchRequest } from '@kbn/es-types';
1212
import {
1313
SERVICE_NAME,
@@ -23,6 +23,7 @@ import {
2323
import type { APMEventClient } from '@kbn/apm-data-access-plugin/server';
2424
import type { ExitSpanFields } from '../../../../common/service_map_diagnostic_types';
2525
import { asMutableArray } from '../../../../common/utils/as_mutable_array';
26+
import { compactMap } from '../../../utils/compact_map';
2627

2728
type DestinationsBySpanId = Map<string, string | undefined>;
2829

@@ -83,24 +84,27 @@ export async function getExitSpans({
8384
},
8485
});
8586

86-
const apmExitSpans = (
87-
response?.aggregations?.matching_destination_resources?.sample_docs?.hits?.hits.map((doc) => {
88-
const fields = unflattenKnownApmEventFields(doc?.fields);
89-
90-
if (!fields?.parent?.id || !parentSpans.get(fields?.parent?.id)) {
91-
return;
92-
}
93-
94-
return {
95-
destinationService: fields?.service?.name,
96-
spanId: fields?.span?.id ?? '',
97-
transactionId: fields?.transaction?.id ?? '',
98-
serviceNodeName: fields?.service?.node?.name ?? '',
99-
traceId: fields?.trace?.id ?? '',
100-
agentName: fields?.agent?.name ?? '',
101-
};
102-
}) ?? []
103-
).filter((span): span is ExitSpanFields => !!span);
87+
const hits =
88+
response?.aggregations?.matching_destination_resources?.sample_docs?.hits?.hits ?? [];
89+
90+
const apmExitSpans = compactMap(hits, (hit) => {
91+
const fields = hit?.fields && accessKnownApmEventFields(hit.fields);
92+
93+
const parentId = fields?.[PARENT_ID];
94+
95+
if (!fields || !parentId || !parentSpans.get(parentId)) {
96+
return;
97+
}
98+
99+
return {
100+
destinationService: fields[SERVICE_NAME] ?? '',
101+
spanId: fields[SPAN_ID] ?? '',
102+
transactionId: fields[TRANSACTION_ID] ?? '',
103+
serviceNodeName: fields[SERVICE_NODE_NAME] ?? '',
104+
traceId: fields[TRACE_ID] ?? '',
105+
agentName: fields[AGENT_NAME] ?? '',
106+
} satisfies ExitSpanFields;
107+
});
104108

105109
return {
106110
apmExitSpans,
@@ -178,11 +182,10 @@ export async function getSourceSpanIds({
178182
sourceSpanIdsRawResponse: response,
179183
destinationsBySpanId:
180184
response.aggregations?.sample_docs?.buckets?.reduce((acc, bucket) => {
181-
const event = unflattenKnownApmEventFields(
182-
bucket.top_span_ids.hits.hits[0].fields,
183-
requiredFields
184-
);
185-
acc.set(event.span.id, event.span?.destination?.service?.resource);
185+
const event = accessKnownApmEventFields(
186+
bucket.top_span_ids.hits.hits[0].fields
187+
).requireFields(requiredFields);
188+
acc.set(event[SPAN_ID], event[SPAN_DESTINATION_SERVICE_RESOURCE]);
186189
return acc;
187190
}, destinationsBySpanId) ?? destinationsBySpanId,
188191
};

x-pack/solutions/observability/plugins/apm/server/utils/compact_map.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,23 @@ describe('compactMap', () => {
2929

3030
expect(compactMap(values, (value) => value)).toEqual([0, '', false, {}]);
3131
});
32+
33+
it('maps iterable collections into a new array', () => {
34+
const values = new Set([0, 1, 1, 2, 3, 4, 4, 5]);
35+
36+
expect(compactMap(values, (value) => (value % 2 === 0 ? `${value}` : undefined))).toEqual([
37+
'0',
38+
'2',
39+
'4',
40+
]);
41+
42+
const valuesMap = new Map([
43+
['a', 1],
44+
['b', 2],
45+
['c', 3],
46+
['c', 4],
47+
]);
48+
49+
expect(compactMap(valuesMap, ([key, value]) => (key === 'b' ? null : value))).toEqual([1, 4]);
50+
});
3251
});

x-pack/solutions/observability/plugins/apm/server/utils/compact_map.ts

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

88
/**
9-
* Takes an input array and a map function, outputting a new mapped array that removes
9+
* Takes an iterable input and a map function, outputs a new mapped array that removes
1010
* all `null` or `undefined` slots.
1111
*/
12-
export function compactMap<T, U>(array: T[], mapFn: (val: T) => U | undefined | null): U[] {
12+
export function compactMap<T, U>(array: Iterable<T>, mapFn: (val: T) => U | undefined | null): U[] {
1313
const mapped: U[] = [];
1414

1515
for (const item of array) {

0 commit comments

Comments
 (0)