[8.18] [Journeys] Set traceparent for Playwright (#189800) (#209859)

# Backport

This will backport the following commits from `main` to `8.18`:
- [[Journeys] Set traceparent for Playwright
(#189800)](https://github.com/elastic/kibana/pull/189800)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Dario
Gieselaar","email":"dario.gieselaar@elastic.co"},"sourceCommit":{"committedDate":"2025-02-05T17:53:34Z","message":"[Journeys]
Set traceparent for Playwright (#189800)\n\nSets the traceparent for
Playwright, so the trace from the test runner\nincludes the trace events
from the browser and Kibana server.\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"27893f5fcd8ef9775df54e8aadaa41f3b2d78c3a","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:version","v8.18.0","v9.1.0"],"title":"[Journeys]
Set traceparent for
Playwright","number":189800,"url":"https://github.com/elastic/kibana/pull/189800","mergeCommit":{"message":"[Journeys]
Set traceparent for Playwright (#189800)\n\nSets the traceparent for
Playwright, so the trace from the test runner\nincludes the trace events
from the browser and Kibana server.\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"27893f5fcd8ef9775df54e8aadaa41f3b2d78c3a"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.18"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/189800","number":189800,"mergeCommit":{"message":"[Journeys]
Set traceparent for Playwright (#189800)\n\nSets the traceparent for
Playwright, so the trace from the test runner\nincludes the trace events
from the browser and Kibana server.\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"27893f5fcd8ef9775df54e8aadaa41f3b2d78c3a"}}]}]
BACKPORT-->

Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co>
This commit is contained in:
Kibana Machine 2025-02-06 06:52:54 +11:00 committed by GitHub
parent 4225d4db0f
commit cd940ff75f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 83 additions and 8 deletions

View file

@ -16,7 +16,7 @@ export const JOURNEY_APM_CONFIG = {
secretToken: APM_PUBLIC_TOKEN,
active: 'true',
contextPropagationOnly: 'false',
environment: process.env.CI ? 'ci' : 'development',
environment: process.env.ELASTIC_APM_ENVIRONMENT || (process.env.CI ? 'ci' : 'development'),
transactionSampleRate: '1.0',
// capture request body for both errors and request transactions
// https://www.elastic.co/guide/en/apm/agent/nodejs/current/configuration.html#capture-body

View file

@ -12,6 +12,7 @@ import { inspect, format } from 'util';
import { setTimeout as setTimer } from 'timers/promises';
import * as Rx from 'rxjs';
import apmNode from 'elastic-apm-node';
import type { ApmBase } from '@elastic/apm-rum';
import playwright, { ChromiumBrowser, Page, BrowserContext, CDPSession, Request } from 'playwright';
import { asyncMap, asyncForEach } from '@kbn/std';
import { ToolingLog } from '@kbn/tooling-log';
@ -32,6 +33,13 @@ import { JourneyScreenshots } from './journey_screenshots';
import { getNewPageObject } from '../services/page';
import { getSynthtraceClient } from '../services/synthtrace';
type WindowWithApmContext = Window & {
elasticApm?: ApmBase;
traceIdOverrideListenerAttached?: boolean;
journeyTraceId?: string;
journeyParentId?: string;
};
export class JourneyFtrHarness {
private readonly screenshots: JourneyScreenshots;
private readonly kbnUrl: KibanaUrl;
@ -161,6 +169,53 @@ export class JourneyFtrHarness {
this.page = await this.context.newPage();
await this.interceptBrowserRequests(this.page);
const initializeApmInitListener = async () => {
await this.page?.evaluate(() => {
const win = window as WindowWithApmContext;
const attachTraceIdOverrideListener = () => {
if (win.traceIdOverrideListenerAttached) {
return;
}
win.traceIdOverrideListenerAttached = true;
win.elasticApm!.observe('transaction:start', (tx) => {
// private properties, bit of a hack
// @ts-expect-error
tx.traceId = win.journeyTraceId || tx.traceId;
// @ts-expect-error
tx.parentId = win.journeyParentId || tx.parentId;
});
};
if (win.elasticApm) {
attachTraceIdOverrideListener();
} else {
// attach trace listener as soon as elasticApm API is available
let originalValue: any;
Object.defineProperty(window, 'elasticApm', {
get() {
return originalValue;
},
set(newValue) {
originalValue = newValue;
attachTraceIdOverrideListener();
},
configurable: true,
enumerable: true,
});
}
});
};
this.page.on('framenavigated', () => {
initializeApmInitListener();
});
await initializeApmInitListener();
if (!process.env.NO_BROWSER_LOG) {
this.page.on('console', this.onConsoleEvent);
}
@ -168,7 +223,6 @@ export class JourneyFtrHarness {
await this.sendCDPCommands(this.context, this.page);
this.trackTelemetryRequests(this.page);
await this.interceptBrowserRequests(this.page);
}
private async runSynthtrace() {
@ -382,9 +436,12 @@ export class JourneyFtrHarness {
}
}
private getCurrentSpanOrTransaction() {
return this.currentSpanStack.length ? this.currentSpanStack[0] : this.currentTransaction;
}
private getCurrentTraceparent() {
return (this.currentSpanStack.length ? this.currentSpanStack[0] : this.currentTransaction)
?.traceparent;
return this.getCurrentSpanOrTransaction()?.traceparent;
}
private async getBrowserInstance() {
@ -514,6 +571,18 @@ export class JourneyFtrHarness {
for (const step of steps) {
it(step.name, async () => {
await this.withSpan(`step: ${step.name}`, 'step', async () => {
await this.page?.evaluate(
([traceId, parentId]) => {
const win = window as WindowWithApmContext;
win.journeyTraceId = traceId;
win.journeyParentId = parentId;
},
[
this.apm?.currentTraceIds['trace.id'],
this.apm?.currentTraceIds['span.id'] || this.apm?.currentTraceIds['transaction.id'],
]
);
try {
await step.fn(this.getCtx());
await this.onStepSuccess(step);

View file

@ -81,7 +81,9 @@ describe('getApmConfig', () => {
agentMock.currentTransaction = {
sampled: 'sampled',
traceId: 'traceId',
ensureParentId: () => 'parentId',
ids: {
['transaction.id']: 'transactionId',
},
} as any;
const config = getApmConfig('/some-other-path');
@ -90,7 +92,7 @@ describe('getApmConfig', () => {
expect.objectContaining({
pageLoadTraceId: 'traceId',
pageLoadSampled: 'sampled',
pageLoadSpanId: 'parentId',
pageLoadParentId: 'transactionId',
})
);
});

View file

@ -46,7 +46,8 @@ export const getApmConfig = (requestPath: string) => {
...config,
pageLoadTraceId: traceId,
pageLoadSampled: sampled,
pageLoadSpanId: backendTransaction.ensureParentId(),
pageLoadParentId:
agent.currentSpan?.ids['span.id'] || agent.currentTransaction?.ids['transaction.id'],
};
}

View file

@ -109,7 +109,8 @@ async function startEs(props: EsRunProps) {
'scripts/es',
'snapshot',
'--license=trial',
// Temporarily disabling APM
// Temporarily disabling APM because the token needs to be added to the keystore
// and cannot be set via command line
// ...(JOURNEY_APM_CONFIG.active
// ? [
// '-E',
@ -155,6 +156,8 @@ async function runFunctionalTest(props: TestRunProps) {
k.startsWith('ELASTIC_APM_') ? [[k, undefined]] : []
)
),
ELASTIC_APM_ENVIRONMENT: process.env.ELASTIC_APM_ENVIRONMENT,
ELASTIC_APM_SERVICE_NAME: process.env.ELASTIC_APM_SERVICE_NAME,
TEST_PERFORMANCE_PHASE: phase,
TEST_ES_URL: 'http://elastic:changeme@localhost:9200',
TEST_ES_DISABLE_STARTUP: 'true',