From 3633a92b09623c7e0386c3e4bde735e9b2c83c87 Mon Sep 17 00:00:00 2001 From: "martin.kuba" Date: Mon, 5 Aug 2024 21:36:15 -0700 Subject: [PATCH] add tests for getting parent span context --- package-lock.json | 4 + .../README.md | 2 +- .../package.json | 2 + .../test/integrations/lambda-handler.test.ts | 132 +++++++++++++----- 4 files changed, 105 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2db12cb080..2291098bc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38428,6 +38428,8 @@ "devDependencies": { "@opentelemetry/api": "^1.3.0", "@opentelemetry/core": "^1.8.0", + "@opentelemetry/propagator-aws-xray": "^1.25.1", + "@opentelemetry/propagator-aws-xray-lambda": "^0.52.1", "@opentelemetry/sdk-metrics": "^1.8.0", "@opentelemetry/sdk-trace-base": "^1.8.0", "@opentelemetry/sdk-trace-node": "^1.8.0", @@ -51596,6 +51598,8 @@ "@opentelemetry/api": "^1.3.0", "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.52.0", + "@opentelemetry/propagator-aws-xray": "^1.25.1", + "@opentelemetry/propagator-aws-xray-lambda": "^0.52.1", "@opentelemetry/resources": "^1.8.0", "@opentelemetry/sdk-metrics": "^1.8.0", "@opentelemetry/sdk-trace-base": "^1.8.0", diff --git a/plugins/node/opentelemetry-instrumentation-aws-lambda/README.md b/plugins/node/opentelemetry-instrumentation-aws-lambda/README.md index 5afe433718..6160add9c1 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-lambda/README.md +++ b/plugins/node/opentelemetry-instrumentation-aws-lambda/README.md @@ -107,7 +107,7 @@ provider.register({ }); ``` -Alternatively, you can use the [auto-configuration-propagators](https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/metapackages/auto-configuration-propagators/README.md) package, which makes it possible to configure propgators via the `OTEL_PROPAGATORS` environment variable. In order to use the `AWSXRayLambdaPropagator`, set the env variable value to `xray-lambda`. +Alternatively, you can use the [auto-configuration-propagators](https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/metapackages/auto-configuration-propagators/README.md) package, which makes it possible to configure propagators via the `OTEL_PROPAGATORS` environment variable. In order to use the `AWSXRayLambdaPropagator`, set the env variable value to `xray-lambda`. ```js const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); diff --git a/plugins/node/opentelemetry-instrumentation-aws-lambda/package.json b/plugins/node/opentelemetry-instrumentation-aws-lambda/package.json index 740c912a3c..b606b01e50 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-lambda/package.json +++ b/plugins/node/opentelemetry-instrumentation-aws-lambda/package.json @@ -45,6 +45,8 @@ "devDependencies": { "@opentelemetry/api": "^1.3.0", "@opentelemetry/core": "^1.8.0", + "@opentelemetry/propagator-aws-xray": "^1.25.1", + "@opentelemetry/propagator-aws-xray-lambda": "^0.52.1", "@opentelemetry/sdk-metrics": "^1.8.0", "@opentelemetry/sdk-trace-base": "^1.8.0", "@opentelemetry/sdk-trace-node": "^1.8.0", diff --git a/plugins/node/opentelemetry-instrumentation-aws-lambda/test/integrations/lambda-handler.test.ts b/plugins/node/opentelemetry-instrumentation-aws-lambda/test/integrations/lambda-handler.test.ts index 10df8d49f7..83dbffc0b5 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-lambda/test/integrations/lambda-handler.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-lambda/test/integrations/lambda-handler.test.ts @@ -46,9 +46,12 @@ import { SpanKind, SpanStatusCode, TextMapPropagator, + ROOT_CONTEXT, + defaultTextMapGetter, } from '@opentelemetry/api'; import { AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray'; import { W3CTraceContextPropagator } from '@opentelemetry/core'; +import { AWSXRayLambdaPropagator } from '@opentelemetry/propagator-aws-xray-lambda'; const memoryExporter = new InMemorySpanExporter(); @@ -405,49 +408,81 @@ describe('lambda handler', () => { }); describe('with remote parent', () => { - it('passes the lambda context object into the eventContextExtractor for scenarios where it is the otel context carrier', async () => { + beforeEach(() => { + propagation.disable(); + }); + + it('uses globally registered propagator', async () => { + propagation.setGlobalPropagator(new AWSXRayPropagator()); + initializeHandler('lambda-test/async.handler'); + + const proxyEvent = { + headers: { + 'x-amzn-trace-id': sampledAwsHeader, + }, + }; + + const result = await lambdaRequire('lambda-test/async').handler( + proxyEvent, + ctx + ); + assert.strictEqual(result, 'ok'); + const spans = memoryExporter.getFinishedSpans(); + + assert.strictEqual(spans.length, 1); + assert.equal( + spans[0].spanContext().traceId, + sampledAwsSpanContext.traceId + ); + assert.equal(spans[0].parentSpanId, sampledAwsSpanContext.spanId); + }); + + it('can extract context from lambda context env variable using a global propagator', async () => { process.env[traceContextEnvironmentKey] = sampledAwsHeader; - const customExtractor = ( - event: any, - handlerContext: Context - ): OtelContext => { - const contextCarrier = handlerContext.clientContext?.Custom ?? {}; - return propagation.extract(context.active(), contextCarrier); + propagation.setGlobalPropagator(new AWSXRayLambdaPropagator()); + initializeHandler('lambda-test/async.handler'); + + const result = await lambdaRequire('lambda-test/async').handler( + 'arg', + ctx + ); + + assert.strictEqual(result, 'ok'); + const spans = memoryExporter.getFinishedSpans(); + + assert.strictEqual(spans.length, 1); + assert.equal( + spans[0].spanContext().traceId, + sampledAwsSpanContext.traceId + ); + assert.equal(spans[0].parentSpanId, sampledAwsSpanContext.spanId); + }); + + it('used custom eventContextExtractor over global propagator if defined', async () => { + propagation.setGlobalPropagator(new W3CTraceContextPropagator()); + const customExtractor = (event: any): OtelContext => { + const propagator = new AWSXRayPropagator(); + return propagator.extract( + context.active(), + event.contextCarrier, + defaultTextMapGetter + ); }; initializeHandler('lambda-test/async.handler', { eventContextExtractor: customExtractor, }); - const otherEvent = {}; - const ctxWithCustomData = { - functionName: 'my_function', - invokedFunctionArn: 'my_arn', - awsRequestId: 'aws_request_id', - clientContext: { - client: { - installationId: '', - appTitle: '', - appVersionName: '', - appVersionCode: '', - appPackageName: '', - }, - Custom: { - traceparent: sampledGenericSpan, - }, - env: { - platformVersion: '', - platform: '', - make: '', - model: '', - locale: '', - }, + const otherEvent = { + contextCarrier: { + traceparent: sampledGenericSpan, + 'x-amzn-trace-id': sampledAwsHeader, }, - } as Context; + }; const result = await lambdaRequire('lambda-test/async').handler( otherEvent, - ctxWithCustomData + ctx ); assert.strictEqual(result, 'ok'); @@ -457,9 +492,38 @@ describe('lambda handler', () => { assertSpanSuccess(span); assert.strictEqual( span.spanContext().traceId, - sampledGenericSpanContext.traceId + sampledAwsSpanContext.traceId ); - assert.strictEqual(span.parentSpanId, sampledGenericSpanContext.spanId); + assert.strictEqual(span.parentSpanId, sampledAwsSpanContext.spanId); + }); + + it('creates trace from ROOT_CONTEXT eventContextExtractor is provided, and no custom context is found', async () => { + const customExtractor = (event: any): OtelContext => { + if (!event.contextCarrier) { + return ROOT_CONTEXT; + } + + return propagation.extract(context.active(), event.contextCarrier); + }; + + const provider = initializeHandler('lambda-test/async.handler', { + eventContextExtractor: customExtractor, + }); + + const testSpan = provider.getTracer('test').startSpan('random_span'); + await context.with( + trace.setSpan(context.active(), testSpan), + async () => { + await lambdaRequire('lambda-test/async').handler( + { message: 'event with no context' }, + ctx + ); + } + ); + + const spans = memoryExporter.getFinishedSpans(); + const [span] = spans; + assert.strictEqual(span.parentSpanId, undefined); }); });