diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/apm_fields.ts b/packages/kbn-apm-synthtrace/src/lib/apm/apm_fields.ts index b5181e80a92e9..690e6c3563f27 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/apm_fields.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/apm_fields.ts @@ -32,6 +32,7 @@ export interface ApmException { message: string; } export interface Observer { + type: string; version: string; version_major: number; } @@ -42,6 +43,8 @@ export type ApmFields = Fields & 'agent.name': string; 'agent.version': string; 'container.id': string; + 'destination.address': string; + 'destination.port': number; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; @@ -75,6 +78,8 @@ export type ApmFields = Fields & 'service.runtime.name': string; 'service.runtime.version': string; 'service.framework.name': string; + 'service.target.name': string; + 'service.target.type': string; 'span.id': string; 'span.name': string; 'span.type': string; diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/instance.ts b/packages/kbn-apm-synthtrace/src/lib/apm/instance.ts index c89fda7f576fb..d212c1f2cead0 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/instance.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/instance.ts @@ -22,9 +22,10 @@ export class Instance extends Entity { }); } - span(spanName: string, spanType: string, spanSubtype?: string) { + span(spanName: string, spanType: string, spanSubtype?: string, apmFields?: ApmFields) { return new Span({ ...this.fields, + ...apmFields, 'span.name': spanName, 'span.type': spanType, 'span.subtype': spanSubtype, diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/span.ts b/packages/kbn-apm-synthtrace/src/lib/apm/span.ts index 91cbacadf59cc..388e65385e7dd 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/span.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/span.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import url from 'url'; import { BaseSpan } from './base_span'; import { generateShortId } from '../utils/generate_id'; import { ApmFields } from './apm_fields'; @@ -39,3 +40,56 @@ export class Span extends BaseSpan { return this; } } + +export function httpExitSpan({ + spanName, + destinationUrl, +}: { + spanName: string; + destinationUrl: string; +}): [string, string, string, ApmFields] { + // origin: 'http://opbeans-go:3000', + // host: 'opbeans-go:3000', + // hostname: 'opbeans-go', + // port: '3000', + const destination = new url.URL(destinationUrl); + + const spanType = 'external'; + const spanSubType = 'http'; + + return [ + spanName, + spanType, + spanSubType, + { + 'destination.address': destination.hostname, + 'destination.port': parseInt(destination.port, 10), + 'service.target.name': destination.host, + 'span.destination.service.name': destination.origin, + 'span.destination.service.resource': destination.host, + 'span.destination.service.type': 'external', + }, + ]; +} + +export function dbExitSpan({ + spanName, + spanSubType, +}: { + spanName: string; + spanSubType?: string; +}): [string, string, string | undefined, ApmFields] { + const spanType = 'db'; + + return [ + spanName, + spanType, + spanSubType, + { + 'service.target.type': spanSubType, + 'span.destination.service.name': spanSubType, + 'span.destination.service.resource': spanSubType, + 'span.destination.service.type': spanType, + }, + ]; +} diff --git a/packages/kbn-apm-synthtrace/src/lib/stream_processor.ts b/packages/kbn-apm-synthtrace/src/lib/stream_processor.ts index 6a0bb276fb0ff..0d7d0ff5dfa51 100644 --- a/packages/kbn-apm-synthtrace/src/lib/stream_processor.ts +++ b/packages/kbn-apm-synthtrace/src/lib/stream_processor.ts @@ -180,6 +180,7 @@ export class StreamProcessor { private static enrich(document: ApmFields, version: string, versionMajor: number): ApmFields { // see https://github.com/elastic/apm-server/issues/7088 can not be provided as flat key/values document.observer = { + type: 'synthtrace', version: version ?? '8.2.0', version_major: versionMajor, }; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/distributed_trace.ts b/packages/kbn-apm-synthtrace/src/scenarios/distributed_trace.ts new file mode 100644 index 0000000000000..a87cbfe5ab4d3 --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/distributed_trace.ts @@ -0,0 +1,93 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { apm, timerange } from '../..'; +import { ApmFields } from '../lib/apm/apm_fields'; +import { Scenario } from '../cli/scenario'; + +import { RunOptions } from '../cli/utils/parse_run_cli_flags'; +import { getSynthtraceEnvironment } from '../lib/utils/get_synthtrace_environment'; +import { httpExitSpan } from '../lib/apm/span'; + +const ENVIRONMENT = getSynthtraceEnvironment(__filename); + +const scenario: Scenario = async (runOptions: RunOptions) => { + return { + generate: ({ from, to }) => { + const range = timerange(from, to); + const transactionName = '240rpm/75% 1000ms'; + const successfulTimestamps = range.interval('1s').rate(3); + + const opbeansRum = apm.service('opbeans-rum', ENVIRONMENT, 'rum-js').instance('my-instance'); + const opbeansNode = apm + .service('opbeans-node', ENVIRONMENT, 'nodejs') + .instance('my-instance'); + const opbeansGo = apm.service('opbeans-go', ENVIRONMENT, 'go').instance('my-instance'); + + const traces = successfulTimestamps.generator((timestamp) => { + // opbeans-rum + return opbeansRum + .transaction(transactionName) + .duration(400) + .timestamp(timestamp) + .children( + // opbeans-rum -> opbeans-node + opbeansRum + .span( + ...httpExitSpan({ + spanName: 'GET /api/products/top', + destinationUrl: 'http://opbeans-node:3000', + }) + ) + .duration(300) + .timestamp(timestamp) + + .children( + // opbeans-node + opbeansNode + .transaction('Initial transaction in opbeans-node') + .duration(300) + .timestamp(timestamp) + .children( + opbeansNode + // opbeans-node -> opbeans-go + .span( + ...httpExitSpan({ + spanName: 'GET opbeans-go:3000', + destinationUrl: 'http://opbeans-go:3000', + }) + ) + .timestamp(timestamp) + .duration(400) + + .children( + // opbeans-go + opbeansGo + + .transaction('Initial transaction in opbeans-go') + .timestamp(timestamp) + .duration(200) + .children( + opbeansGo + .span('custom_operation', 'custom') + .timestamp(timestamp) + .duration(100) + .success() + ) + ) + ) + ) + ); + }); + + return traces; + }, + }; +}; + +export default scenario; diff --git a/packages/kbn-apm-synthtrace/src/test/apm_events_to_elasticsearch_output.test.ts b/packages/kbn-apm-synthtrace/src/test/apm_events_to_elasticsearch_output.test.ts index 3d4225cf3f243..afafcc0c49665 100644 --- a/packages/kbn-apm-synthtrace/src/test/apm_events_to_elasticsearch_output.test.ts +++ b/packages/kbn-apm-synthtrace/src/test/apm_events_to_elasticsearch_output.test.ts @@ -46,6 +46,7 @@ describe('output apm events to elasticsearch', () => { "version": "1.4", }, "observer": Object { + "type": "synthtrace", "version": "8.0.0", "version_major": 8, },