Skip to content

Commit

Permalink
[APM] Implementing Journey for APM (elastic#162721)
Browse files Browse the repository at this point in the history
## Summary

Closes - elastic#153844

As part of this PR, as its just the stepping stone, we will only cover a
basic navigation flow and analyze the result obtained from Steps
Dashboard and data collected by the APM Agents for this journey

## Scope

- Generating a data set using Synthtrace instead of Archives
- Capturing the flow from Service Inventory to Trace Waterfall loading
on Transaction page
- Capturing Event loop utilisation metrics enabled for APM Journey

## How to run it

```
node scripts/run_performance.js --journey-path x-pack/performance/journeys/apm_service_inventory.ts --skip-warmup
```

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
achyutjhunjhunwala and kibanamachine committed Jul 31, 2023
1 parent d5761dc commit 6b44fff
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 0 deletions.
1 change: 1 addition & 0 deletions .buildkite/ftr_configs.yml
Expand Up @@ -413,5 +413,6 @@ enabled:
- x-pack/performance/journeys/ecommerce_dashboard_tsvb_gauge_only.ts
- x-pack/performance/journeys/dashboard_listing_page.ts
- x-pack/performance/journeys/cloud_security_dashboard.ts
- x-pack/performance/journeys/apm_service_inventory.ts
- x-pack/test/custom_branding/config.ts
- x-pack/test/profiling_api_integration/cloud/config.ts
37 changes: 37 additions & 0 deletions x-pack/performance/configs/apm_config.ts
@@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { FtrConfigProviderContext } from '@kbn/test';
import { CA_CERT_PATH } from '@kbn/dev-utils';

// eslint-disable-next-line import/no-default-export
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const xpackFunctionalConfig = await readConfigFile(
// eslint-disable-next-line @kbn/imports/no_boundary_crossing
require.resolve('../../test/functional/config.base.js')
);

return {
...xpackFunctionalConfig.getAll(),

kbnTestServer: {
...xpackFunctionalConfig.get('kbnTestServer'),
serverArgs: [
...xpackFunctionalConfig.get('kbnTestServer.serverArgs'),
'--home.disableWelcomeScreen=true',
'--csp.strict=false',
'--csp.warnLegacyBrowsers=false',
// define custom kibana server args here
`--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`,
'--server.eluMonitor.enabled=true',
'--server.eluMonitor.logging.enabled=true',
'--server.eluMonitor.logging.threshold.ela=250',
'--server.eluMonitor.logging.threshold.elu=0.15',
],
},
};
}
53 changes: 53 additions & 0 deletions x-pack/performance/journeys/apm_service_inventory.ts
@@ -0,0 +1,53 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { Journey } from '@kbn/journeys';
import { SynthtraceClient } from '../services/synthtrace';
import { generateData } from '../synthtrace_data/apm_data';

export const journey = new Journey({
beforeSteps: async ({ kbnUrl, log, auth, es }) => {
// Install APM Package
const synthClient = new SynthtraceClient({
kbnBaseUrl: kbnUrl.get(),
logger: log,
username: auth.getUsername(),
password: auth.getPassword(),
esClient: es,
});

await synthClient.installApmPackage();
// Setup Synthtrace Client
await synthClient.initialiseEsClient();
// Generate data using Synthtrace
const start = Date.now() - 1000;
const end = Date.now();
await synthClient.index(
generateData({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
})
);
},
ftrConfigPath: 'x-pack/performance/configs/apm_config.ts',
})
.step('Navigate to Service Inventory Page', async ({ page, kbnUrl }) => {
await page.goto(kbnUrl.get(`app/apm/services`));
await page.waitForSelector(`[data-test-subj="serviceLink_nodejs"]`);
})
.step('Navigate to Service Overview Page', async ({ page, kbnUrl }) => {
await page.click(`[data-test-subj="serviceLink_nodejs"]`);
await page.waitForSelector(`[data-test-subj="apmMainTemplateHeaderServiceName"]`);
})
.step('Navigate to Transactions tabs', async ({ page, kbnUrl }) => {
await page.click(`[data-test-subj="transactionsTab"]`);
await page.waitForSelector(`[data-test-subj="apmTransactionDetailLinkLink"]`);
})
.step('Wait for Trace Waterfall on the page to load', async ({ page, kbnUrl }) => {
await page.click(`[data-test-subj="apmTransactionDetailLinkLink"]`);
await page.waitForSelector(`[data-test-subj="apmWaterfallButton"]`);
});
66 changes: 66 additions & 0 deletions x-pack/performance/services/synthtrace/index.ts
@@ -0,0 +1,66 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { ApmSynthtraceEsClient, ApmSynthtraceKibanaClient } from '@kbn/apm-synthtrace';
import Url from 'url';
import { Readable } from 'stream';
import { ApmFields, SynthtraceGenerator } from '@kbn/apm-synthtrace-client';

export interface SynthtraceClientParams {
kbnBaseUrl: string;
logger: any;
username: string;
password: string;
esClient: any;
}

export class SynthtraceClient {
private synthtraceEsClient: ApmSynthtraceEsClient | undefined;
private packageVersion: string = '';
private readonly kibanaUrlWithAuth: string;

constructor(private readonly baseParams: SynthtraceClientParams) {
const kibanaUrl = new URL(this.baseParams.kbnBaseUrl);
this.kibanaUrlWithAuth = Url.format({
protocol: kibanaUrl.protocol,
hostname: kibanaUrl.hostname,
port: kibanaUrl.port,
auth: `${this.baseParams.username}:${this.baseParams.password}`,
});
}

async installApmPackage() {
const kibanaClient = new ApmSynthtraceKibanaClient({
logger: this.baseParams.logger,
target: this.kibanaUrlWithAuth,
});
this.packageVersion = await kibanaClient.fetchLatestApmPackageVersion();

await kibanaClient.installApmPackage(this.packageVersion);
}

async initialiseEsClient() {
this.synthtraceEsClient = new ApmSynthtraceEsClient({
client: this.baseParams.esClient,
logger: this.baseParams.logger,
refreshAfterIndex: true,
version: this.packageVersion,
});

this.synthtraceEsClient.pipeline(this.synthtraceEsClient.getDefaultPipeline(false));
}

async index(events: SynthtraceGenerator<ApmFields>) {
if (this.synthtraceEsClient) {
await this.synthtraceEsClient.index(
Readable.from(Array.from(events).flatMap((event) => event.serialize()))
);
} else {
throw new Error('ES Client not initialised');
}
}
}
77 changes: 77 additions & 0 deletions x-pack/performance/synthtrace_data/apm_data.ts
@@ -0,0 +1,77 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { apm, httpExitSpan, timerange } from '@kbn/apm-synthtrace-client';

export function generateData({ from, to }: { from: number; to: number }) {
const range = timerange(from, to);
const transactionName = '240rpm/75% 1000ms';

const synthRum = apm
.service({ name: 'synth-rum', environment: 'production', agentName: 'rum-js' })
.instance('my-instance');
const synthNode = apm
.service({ name: 'synth-node', environment: 'production', agentName: 'nodejs' })
.instance('my-instance');
const synthGo = apm
.service({ name: 'synth-go', environment: 'production', agentName: 'go' })
.instance('my-instance');

return range.interval('1m').generator((timestamp) => {
return synthRum
.transaction({ transactionName })
.duration(400)
.timestamp(timestamp)
.children(
// synth-rum -> synth-node
synthRum
.span(
httpExitSpan({
spanName: 'GET /api/products/top',
destinationUrl: 'http://synth-node:3000',
})
)
.duration(300)
.timestamp(timestamp)

.children(
// synth-node
synthNode
.transaction({ transactionName: 'Initial transaction in synth-node' })
.duration(300)
.timestamp(timestamp)
.children(
synthNode
// synth-node -> synth-go
.span(
httpExitSpan({
spanName: 'GET synth-go:3000',
destinationUrl: 'http://synth-go:3000',
})
)
.timestamp(timestamp)
.duration(400)

.children(
// synth-go
synthGo

.transaction({ transactionName: 'Initial transaction in synth-go' })
.timestamp(timestamp)
.duration(200)
.children(
synthGo
.span({ spanName: 'custom_operation', spanType: 'custom' })
.timestamp(timestamp)
.duration(100)
.success()
)
)
)
)
);
});
}
3 changes: 3 additions & 0 deletions x-pack/performance/tsconfig.json
Expand Up @@ -14,5 +14,8 @@
"@kbn/tooling-log",
"@kbn/test",
"@kbn/expect",
"@kbn/dev-utils",
"@kbn/apm-synthtrace",
"@kbn/apm-synthtrace-client",
]
}

0 comments on commit 6b44fff

Please sign in to comment.