Skip to content

Commit 1743b7f

Browse files
Nir Hadassidyladan
andauthored
feat(aws-lambda): disableAwsContextPropagation config option (#546)
Co-authored-by: Daniel Dyla <[email protected]>
1 parent c1b6eec commit 1743b7f

4 files changed

Lines changed: 81 additions & 20 deletions

File tree

plugins/node/opentelemetry-instrumentation-aws-lambda/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ In your Lambda function configuration, add or update the `NODE_OPTIONS` environm
4646
| --- | --- | --- |
4747
| `requestHook` | `RequestHook` (function) | Hook for adding custom attributes before lambda starts handling the request. Receives params: `span, { event, context }` |
4848
| `responseHook` | `ResponseHook` (function) | Hook for adding custom attributes before lambda returns the response. Receives params: `span, { err?, res? } ` |
49+
| `disableAwsContextPropagation` | `boolean` | By default, this instrumentation will try to read the context from the `_X_AMZN_TRACE_ID` environment variable set by Lambda, set this to `true` to disable this behavior |
4950

5051
### Hooks Usage Example
5152

plugins/node/opentelemetry-instrumentation-aws-lambda/src/instrumentation.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ export class AwsLambdaInstrumentation extends InstrumentationBase {
151151
) {
152152
const httpHeaders =
153153
typeof event.headers === 'object' ? event.headers : {};
154-
const parent = AwsLambdaInstrumentation._determineParent(httpHeaders);
154+
const parent = AwsLambdaInstrumentation._determineParent(
155+
httpHeaders,
156+
plugin._config.disableAwsContextPropagation === true
157+
);
155158

156159
const name = context.functionName;
157160
const span = plugin.tracer.startSpan(
@@ -298,29 +301,34 @@ export class AwsLambdaInstrumentation extends InstrumentationBase {
298301
}
299302

300303
private static _determineParent(
301-
httpHeaders: APIGatewayProxyEventHeaders
304+
httpHeaders: APIGatewayProxyEventHeaders,
305+
disableAwsContextPropagation: boolean
302306
): OtelContext {
303307
let parent: OtelContext | undefined = undefined;
304-
const lambdaTraceHeader = process.env[traceContextEnvironmentKey];
305-
if (lambdaTraceHeader) {
306-
parent = awsPropagator.extract(
307-
otelContext.active(),
308-
{ [AWSXRAY_TRACE_ID_HEADER]: lambdaTraceHeader },
309-
headerGetter
310-
);
311-
}
312-
if (parent) {
313-
const spanContext = trace.getSpan(parent)?.spanContext();
314-
if (
315-
spanContext &&
316-
(spanContext.traceFlags & TraceFlags.SAMPLED) === TraceFlags.SAMPLED
317-
) {
318-
// Trace header provided by Lambda only sampled if a sampled context was propagated from
319-
// an upstream cloud service such as S3, or the user is using X-Ray. In these cases, we
320-
// need to use it as the parent.
321-
return parent;
308+
309+
if (!disableAwsContextPropagation) {
310+
const lambdaTraceHeader = process.env[traceContextEnvironmentKey];
311+
if (lambdaTraceHeader) {
312+
parent = awsPropagator.extract(
313+
otelContext.active(),
314+
{ [AWSXRAY_TRACE_ID_HEADER]: lambdaTraceHeader },
315+
headerGetter
316+
);
317+
}
318+
if (parent) {
319+
const spanContext = trace.getSpan(parent)?.spanContext();
320+
if (
321+
spanContext &&
322+
(spanContext.traceFlags & TraceFlags.SAMPLED) === TraceFlags.SAMPLED
323+
) {
324+
// Trace header provided by Lambda only sampled if a sampled context was propagated from
325+
// an upstream cloud service such as S3, or the user is using X-Ray. In these cases, we
326+
// need to use it as the parent.
327+
return parent;
328+
}
322329
}
323330
}
331+
324332
// There was not a sampled trace header from Lambda so try from HTTP headers.
325333
const httpContext = propagation.extract(
326334
otelContext.active(),

plugins/node/opentelemetry-instrumentation-aws-lambda/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@ export type ResponseHook = (
3636
export interface AwsLambdaInstrumentationConfig extends InstrumentationConfig {
3737
requestHook?: RequestHook;
3838
responseHook?: ResponseHook;
39+
disableAwsContextPropagation?: boolean;
3940
}

plugins/node/opentelemetry-instrumentation-aws-lambda/test/integrations/lambda-handler.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,57 @@ describe('lambda handler', () => {
526526
// Parent unsampled so no spans exported.
527527
assert.strictEqual(spans.length, 0);
528528
});
529+
530+
it('ignores sampled lambda context if "disableAwsContextPropagation" config option is true', async () => {
531+
process.env[traceContextEnvironmentKey] = sampledAwsHeader;
532+
initializeHandler('lambda-test/async.handler', {
533+
disableAwsContextPropagation: true,
534+
});
535+
536+
const result = await lambdaRequire('lambda-test/async').handler(
537+
'arg',
538+
ctx
539+
);
540+
assert.strictEqual(result, 'ok');
541+
const spans = memoryExporter.getFinishedSpans();
542+
const [span] = spans;
543+
assert.strictEqual(spans.length, 1);
544+
assertSpanSuccess(span);
545+
assert.notDeepStrictEqual(
546+
span.spanContext().traceId,
547+
sampledAwsSpanContext.traceId
548+
);
549+
assert.strictEqual(span.parentSpanId, undefined);
550+
});
551+
552+
it('takes sampled http context over sampled lambda context if "disableAwsContextPropagation" config option is true', async () => {
553+
process.env[traceContextEnvironmentKey] = sampledAwsHeader;
554+
initializeHandler('lambda-test/async.handler', {
555+
disableAwsContextPropagation: true,
556+
});
557+
558+
const proxyEvent = {
559+
headers: {
560+
traceparent: sampledHttpHeader,
561+
},
562+
};
563+
564+
const result = await lambdaRequire('lambda-test/async').handler(
565+
proxyEvent,
566+
ctx
567+
);
568+
569+
assert.strictEqual(result, 'ok');
570+
const spans = memoryExporter.getFinishedSpans();
571+
const [span] = spans;
572+
assert.strictEqual(spans.length, 1);
573+
assertSpanSuccess(span);
574+
assert.strictEqual(
575+
span.spanContext().traceId,
576+
sampledHttpSpanContext.traceId
577+
);
578+
assert.strictEqual(span.parentSpanId, sampledHttpSpanContext.spanId);
579+
});
529580
});
530581

531582
describe('hooks', () => {

0 commit comments

Comments
 (0)