Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lambda): add OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION environment variable #1227

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ In your Lambda function configuration, add or update the `NODE_OPTIONS` environm
| --- | --- | --- |
| `requestHook` | `RequestHook` (function) | Hook for adding custom attributes before lambda starts handling the request. Receives params: `span, { event, context }` |
| `responseHook` | `ResponseHook` (function) | Hook for adding custom attributes before lambda returns the response. Receives params: `span, { err?, res? }` |
| `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 |
| `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` or set the environment variable `OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION=true` to disable this behavior |
| `eventContextExtractor` | `EventContextExtractor` (function) | Function for providing custom context extractor in order to support different event types that are handled by AWS Lambda (e.g., SQS, CloudWatch, Kinesis, API Gateway). Applied only when `disableAwsContextPropagation` is set to `true`. Receives params: `event, context` |

### Hooks Usage Example
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {

import { AwsLambdaInstrumentationConfig, EventContextExtractor } from './types';
import { VERSION } from './version';
import { env } from 'process';
import { LambdaModule } from './internal-types';

const awsPropagator = new AWSXRayPropagator();
Expand All @@ -73,6 +74,21 @@ export class AwsLambdaInstrumentation extends InstrumentationBase {
private _forceFlush?: () => Promise<void>;

constructor(protected override _config: AwsLambdaInstrumentationConfig = {}) {
// shallow copy to prevent modification of original object
_config = { ..._config }

if (_config.disableAwsContextPropagation == null) {
if (
blumamir marked this conversation as resolved.
Show resolved Hide resolved
typeof env['OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION'] ===
'string' &&
env[
'OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION'
].toLocaleLowerCase() === 'true'
) {
_config.disableAwsContextPropagation = true;
blumamir marked this conversation as resolved.
Show resolved Hide resolved
}
}

super('@opentelemetry/instrumentation-aws-lambda', VERSION, _config);
}

Expand Down Expand Up @@ -156,7 +172,7 @@ export class AwsLambdaInstrumentation extends InstrumentationBase {
context,
config.disableAwsContextPropagation === true,
config.eventContextExtractor ||
AwsLambdaInstrumentation._defaultEventContextExtractor
AwsLambdaInstrumentation._defaultEventContextExtractor
);

const name = context.functionName;
Expand Down Expand Up @@ -199,7 +215,7 @@ export class AwsLambdaInstrumentation extends InstrumentationBase {
if (error != null) {
// Exception thrown synchronously before resolving callback / promise.
plugin._applyResponseHook(span, error);
plugin._endSpan(span, error, () => {});
plugin._endSpan(span, error, () => { });
}
}
) as Promise<{}> | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,92 @@ describe('lambda handler', () => {
assert.strictEqual(spans.length, 0);
});

it('ignores sampled lambda context if env OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION is set to "true"', async () => {
process.env['OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION'] = 'true';
process.env[traceContextEnvironmentKey] = sampledAwsHeader;
initializeHandler('lambda-test/async.handler', {});

const result = await lambdaRequire('lambda-test/async').handler(
'arg',
ctx
);
assert.strictEqual(result, 'ok');
const spans = memoryExporter.getFinishedSpans();
const [span] = spans;
assert.strictEqual(spans.length, 1);
assertSpanSuccess(span);
assert.notDeepStrictEqual(
span.spanContext().traceId,
sampledAwsSpanContext.traceId
);
assert.strictEqual(span.parentSpanId, undefined);
});

it('ignores sampled lambda context if env OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION is set to "TRUE"', async () => {
process.env['OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION'] = 'TRUE';
process.env[traceContextEnvironmentKey] = sampledAwsHeader;
initializeHandler('lambda-test/async.handler', {});

const result = await lambdaRequire('lambda-test/async').handler(
'arg',
ctx
);
assert.strictEqual(result, 'ok');
const spans = memoryExporter.getFinishedSpans();
const [span] = spans;
assert.strictEqual(spans.length, 1);
assertSpanSuccess(span);
assert.notDeepStrictEqual(
span.spanContext().traceId,
sampledAwsSpanContext.traceId
);
assert.strictEqual(span.parentSpanId, undefined);
});

it('ignores sampled lambda context if env OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION is set to "True"', async () => {
process.env['OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION'] = 'True';
process.env[traceContextEnvironmentKey] = sampledAwsHeader;
initializeHandler('lambda-test/async.handler', {});

const result = await lambdaRequire('lambda-test/async').handler(
'arg',
ctx
);
assert.strictEqual(result, 'ok');
const spans = memoryExporter.getFinishedSpans();
const [span] = spans;
assert.strictEqual(spans.length, 1);
assertSpanSuccess(span);
assert.notDeepStrictEqual(
span.spanContext().traceId,
sampledAwsSpanContext.traceId
);
assert.strictEqual(span.parentSpanId, undefined);
});

it('ignores OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION if `config.disableAwsContextPropagation` is set', async () => {
process.env['OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION'] = 'true';
process.env[traceContextEnvironmentKey] = sampledAwsHeader;
initializeHandler('lambda-test/async.handler', {
disableAwsContextPropagation: false,
});

const result = await lambdaRequire('lambda-test/async').handler(
'arg',
ctx
);
assert.strictEqual(result, 'ok');
const spans = memoryExporter.getFinishedSpans();
const [span] = spans;
assert.strictEqual(spans.length, 1);
assertSpanSuccess(span);
assert.strictEqual(
span.spanContext().traceId,
sampledAwsSpanContext.traceId
);
assert.strictEqual(span.parentSpanId, sampledAwsSpanContext.spanId);
});

it('ignores sampled lambda context if "disableAwsContextPropagation" config option is true', async () => {
process.env[traceContextEnvironmentKey] = sampledAwsHeader;
initializeHandler('lambda-test/async.handler', {
Expand Down