Skip to content

Commit d10a4a0

Browse files
[9.0] [data.search] Add APM instrumentation to search route (#214280) (#215214)
# Backport This will backport the following commits from `main` to `9.0`: - [[data.search] Add APM instrumentation to search route (#214280)](#214280) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Lukas Olson","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-03-19T16:37:54Z","message":"[data.search] Add APM instrumentation to search route (#214280)\n\n## Summary\n\nResolves https://github.com/elastic/kibana/issues/208219.\n\nAdds APM instrumentation to the search route called by `data.search`\nservices. This was part of `bsearch` before it was removed but for some\nreason was never added to the search routes directly.\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n\n---------\n\nCo-authored-by: kibanamachine <[email protected]>","sha":"423d331b3b8b333d71b7cbcf41e09158c83a9108","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Search","release_note:skip","Team:DataDiscovery","backport:prev-minor","apm:instrumentation","v9.1.0"],"title":"[data.search] Add APM instrumentation to search route","number":214280,"url":"https://github.com/elastic/kibana/pull/214280","mergeCommit":{"message":"[data.search] Add APM instrumentation to search route (#214280)\n\n## Summary\n\nResolves https://github.com/elastic/kibana/issues/208219.\n\nAdds APM instrumentation to the search route called by `data.search`\nservices. This was part of `bsearch` before it was removed but for some\nreason was never added to the search routes directly.\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n\n---------\n\nCo-authored-by: kibanamachine <[email protected]>","sha":"423d331b3b8b333d71b7cbcf41e09158c83a9108"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/214280","number":214280,"mergeCommit":{"message":"[data.search] Add APM instrumentation to search route (#214280)\n\n## Summary\n\nResolves https://github.com/elastic/kibana/issues/208219.\n\nAdds APM instrumentation to the search route called by `data.search`\nservices. This was part of `bsearch` before it was removed but for some\nreason was never added to the search routes directly.\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n\n---------\n\nCo-authored-by: kibanamachine <[email protected]>","sha":"423d331b3b8b333d71b7cbcf41e09158c83a9108"}}]}] BACKPORT--> Co-authored-by: Lukas Olson <[email protected]>
1 parent 483f5ec commit d10a4a0

File tree

5 files changed

+71
-35
lines changed

5 files changed

+71
-35
lines changed

src/platform/plugins/shared/data/public/search/search_interceptor/search_interceptor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ export class SearchInterceptor {
443443
{
444444
version: '1',
445445
signal: abortSignal,
446-
context: executionContext,
446+
context: this.deps.executionContext.withGlobalContext(executionContext),
447447
body: JSON.stringify({
448448
...request,
449449
...searchOptions,

src/platform/plugins/shared/data/server/search/routes/search.test.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import type { MockedKeys } from '@kbn/utility-types-jest';
1111
import { from } from 'rxjs';
12-
import { CoreSetup, RequestHandlerContext } from '@kbn/core/server';
12+
import { CoreSetup, type Logger, RequestHandlerContext } from '@kbn/core/server';
1313
import { coreMock, httpServerMock } from '@kbn/core/server/mocks';
1414
import { registerSearchRoute } from './search';
1515
import { DataPluginStart } from '../../plugin';
@@ -19,21 +19,30 @@ import { KbnSearchError } from '../report_search_error';
1919

2020
describe('Search service', () => {
2121
let mockCoreSetup: MockedKeys<CoreSetup<{}, DataPluginStart>>;
22+
let mockLogger: Logger;
2223

2324
function mockEsError(message: string, statusCode: number, errBody?: Record<string, any>) {
2425
return new KbnSearchError(message, statusCode, errBody);
2526
}
2627

2728
async function runMockSearch(mockContext: any, mockRequest: any, mockResponse: any) {
28-
registerSearchRoute(mockCoreSetup.http.createRouter());
29+
registerSearchRoute(
30+
mockCoreSetup.http.createRouter(),
31+
mockLogger,
32+
mockCoreSetup.executionContext
33+
);
2934

3035
const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value;
3136
const handler = mockRouter.versioned.post.mock.results[0].value.addVersion.mock.calls[0][1];
3237
await handler(mockContext as unknown as RequestHandlerContext, mockRequest, mockResponse);
3338
}
3439

3540
async function runMockDelete(mockContext: any, mockRequest: any, mockResponse: any) {
36-
registerSearchRoute(mockCoreSetup.http.createRouter());
41+
registerSearchRoute(
42+
mockCoreSetup.http.createRouter(),
43+
mockLogger,
44+
mockCoreSetup.executionContext
45+
);
3746

3847
const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value;
3948
const handler = mockRouter.versioned.delete.mock.results[0].value.addVersion.mock.calls[0][1];
@@ -43,6 +52,7 @@ describe('Search service', () => {
4352
beforeEach(() => {
4453
jest.clearAllMocks();
4554
mockCoreSetup = coreMock.createSetup();
55+
mockLogger = coreMock.createPluginInitializerContext().logger.get();
4656
});
4757

4858
it('handler calls context.search.search with the given request and strategy', async () => {

src/platform/plugins/shared/data/server/search/routes/search.ts

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@ import { first } from 'rxjs';
1111
import { schema } from '@kbn/config-schema';
1212
import { reportServerError } from '@kbn/kibana-utils-plugin/server';
1313
import { IncomingMessage } from 'http';
14+
import type { KibanaExecutionContext } from '@kbn/core-execution-context-common';
15+
import { Logger } from '@kbn/logging';
16+
import type { ExecutionContextSetup } from '@kbn/core-execution-context-server';
17+
import apm from 'elastic-apm-node';
1418
import { reportSearchError } from '../report_search_error';
1519
import { getRequestAbortedSignal } from '../../lib';
1620
import type { DataPluginRouter } from '../types';
1721

1822
export const SEARCH_API_BASE_URL = '/internal/search';
1923

20-
export function registerSearchRoute(router: DataPluginRouter): void {
24+
export function registerSearchRoute(
25+
router: DataPluginRouter,
26+
logger: Logger,
27+
executionContextSetup: ExecutionContextSetup
28+
): void {
2129
router.versioned
2230
.post({
2331
path: `${SEARCH_API_BASE_URL}/{strategy}/{id?}`,
@@ -65,39 +73,54 @@ export function registerSearchRoute(router: DataPluginRouter): void {
6573
const { strategy, id } = request.params;
6674
const abortSignal = getRequestAbortedSignal(request.events.aborted$);
6775

76+
let executionContext: KibanaExecutionContext | undefined;
77+
const contextHeader = request.headers['x-kbn-context'];
6878
try {
69-
const search = await context.search;
70-
const response = await search
71-
.search(
72-
{ ...searchRequest, id },
73-
{
74-
abortSignal,
75-
strategy,
76-
legacyHitsTotal,
77-
sessionId,
78-
isStored,
79-
isRestore,
80-
retrieveResults,
81-
stream,
82-
}
83-
)
84-
.pipe(first())
85-
.toPromise();
86-
87-
if (response && (response.rawResponse as unknown as IncomingMessage).pipe) {
88-
return res.ok({
89-
body: response.rawResponse,
90-
headers: {
91-
'kbn-search-is-restored': response.isRestored ? '?1' : '?0',
92-
'kbn-search-request-params': JSON.stringify(response.requestParams),
93-
},
94-
});
95-
} else {
96-
return res.ok({ body: response });
79+
if (contextHeader != null) {
80+
executionContext = JSON.parse(
81+
decodeURIComponent(Array.isArray(contextHeader) ? contextHeader[0] : contextHeader)
82+
);
9783
}
9884
} catch (err) {
99-
return reportSearchError(res, err);
85+
logger.error(`Error parsing search execution context: ${contextHeader}`);
10086
}
87+
88+
return executionContextSetup.withContext(executionContext, async () => {
89+
apm.addLabels(executionContextSetup.getAsLabels());
90+
try {
91+
const search = await context.search;
92+
const response = await search
93+
.search(
94+
{ ...searchRequest, id },
95+
{
96+
abortSignal,
97+
strategy,
98+
legacyHitsTotal,
99+
sessionId,
100+
isStored,
101+
isRestore,
102+
retrieveResults,
103+
stream,
104+
}
105+
)
106+
.pipe(first())
107+
.toPromise();
108+
109+
if (response && (response.rawResponse as unknown as IncomingMessage).pipe) {
110+
return res.ok({
111+
body: response.rawResponse,
112+
headers: {
113+
'kbn-search-is-restored': response.isRestored ? '?1' : '?0',
114+
'kbn-search-request-params': JSON.stringify(response.requestParams),
115+
},
116+
});
117+
} else {
118+
return res.ok({ body: response });
119+
}
120+
} catch (err) {
121+
return reportSearchError(res, err);
122+
}
123+
});
101124
}
102125
);
103126

src/platform/plugins/shared/data/server/search/search_service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export class SearchService {
148148
const usage = usageCollection ? usageProvider(core) : undefined;
149149

150150
const router = core.http.createRouter<DataRequestHandlerContext>();
151-
registerSearchRoute(router);
151+
registerSearchRoute(router, this.logger, core.executionContext);
152152
registerSessionRoutes(router, this.logger);
153153

154154
this.sessionService.setup(core, {});

src/platform/plugins/shared/data/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
"@kbn/esql-utils",
5656
"@kbn/shared-ux-table-persist",
5757
"@kbn/core-deprecations-common",
58+
"@kbn/core-execution-context-common",
59+
"@kbn/logging",
60+
"@kbn/core-execution-context-server",
5861
],
5962
"exclude": [
6063
"target/**/*",

0 commit comments

Comments
 (0)