mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Journeys] Set traceparent for Playwright (#189800)
Sets the traceparent for Playwright, so the trace from the test runner includes the trace events from the browser and Kibana server. --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
fe9023efff
commit
27893f5fcd
5 changed files with 83 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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'],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue