Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/image_scan/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ runs:
run: docker logout public.ecr.aws

- name: Run Trivy vulnerability scanner on image
uses: aquasecurity/trivy-action@master
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 #v0.33.1
with:
image-ref: ${{ inputs.image-ref }}
severity: ${{ inputs.severity }}
Expand Down
5 changes: 0 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,3 @@ For any change that affects end users of this package, please add an entry under
If your change does not need a CHANGELOG entry, add the "skip changelog" label to your PR.

## Unreleased

### Enhancements

- Support X-Ray Trace Id extraction from Lambda Context object, and respect user-configured OTEL_PROPAGATORS in AWS Lamdba instrumentation
([#259](https://github.com/aws-observability/aws-otel-js-instrumentation/pull/259))
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import {
diag,
isSpanContextValid,
Context as OtelContext,
context as otelContext,
propagation,
Expand All @@ -21,7 +22,7 @@ import {
NormalizedRequest,
NormalizedResponse,
} from '@opentelemetry/instrumentation-aws-sdk';
import { AWSXRAY_TRACE_ID_HEADER } from '@opentelemetry/propagator-aws-xray';
import { AWSXRAY_TRACE_ID_HEADER, AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray';
import { APIGatewayProxyEventHeaders, Context } from 'aws-lambda';
import { AWS_ATTRIBUTE_KEYS } from '../aws-attribute-keys';
import { RequestMetadata } from '../third-party/otel/aws/services/ServiceExtension';
Expand All @@ -41,6 +42,7 @@ import { suppressTracing } from '@opentelemetry/core';
export const traceContextEnvironmentKey = '_X_AMZN_TRACE_ID';
export const AWSXRAY_TRACE_ID_HEADER_CAPITALIZED = 'X-Amzn-Trace-Id';

const awsPropagator = new AWSXRayPropagator();
export const headerGetter: TextMapGetter<APIGatewayProxyEventHeaders> = {
keys(carrier: any): string[] {
return Object.keys(carrier);
Expand Down Expand Up @@ -92,29 +94,28 @@ export function applyInstrumentationPatches(instrumentations: Instrumentation[])

/*
* This function `customExtractor` is used to extract SpanContext for AWS Lambda functions.
* It extracts the X-Ray trace ID from the Lambda context (xRayTraceId) or environment variable (_X_AMZN_TRACE_ID) into the event headers
* It then uses OpenTelemetry global propagator to extract trace context from the event headers
* If a valid span context is extracted, it returns that context; otherwise, it returns the root context.
* It first attempts to extract the trace context from the AWS X-Ray header, which is stored in the Lambda environment variables.
* If a valid span context is extracted from the environment, it uses this as the parent context for the function's tracing.
* If the X-Ray header is missing or invalid, it falls back to extracting trace context from the Lambda handler's event headers.
* If neither approach succeeds, it defaults to using the root Otel context, ensuring the function is still instrumented for tracing.
*/
const lambdaContextXrayTraceIdKey = 'xRayTraceId';
export const customExtractor = (event: any, _handlerContext: Context): OtelContext => {
const xrayTraceIdFromLambdaContext = _handlerContext
? (_handlerContext as any)[lambdaContextXrayTraceIdKey]
: undefined;
const xrayTraceIdFromLambdaEnv = process.env[traceContextEnvironmentKey];
const xrayTraceIdFromLambda = xrayTraceIdFromLambdaContext || xrayTraceIdFromLambdaEnv;

const httpHeaders = event.headers || {};
if (xrayTraceIdFromLambda) {
// Delete any X-Ray Trace ID via case-insensitive checks since we will overwrite it here.
Object.keys(httpHeaders).forEach(key => {
if (key.toLowerCase() === AWSXRAY_TRACE_ID_HEADER.toLowerCase()) {
delete httpHeaders[key];
}
});
httpHeaders[AWSXRAY_TRACE_ID_HEADER] = xrayTraceIdFromLambda;
let parent: OtelContext | undefined = undefined;
const lambdaTraceHeader = process.env[traceContextEnvironmentKey];
if (lambdaTraceHeader) {
parent = awsPropagator.extract(
otelContext.active(),
{ [AWSXRAY_TRACE_ID_HEADER]: lambdaTraceHeader },
headerGetter
);
}

if (parent) {
const spanContext = trace.getSpan(parent)?.spanContext();
if (spanContext && isSpanContextValid(spanContext)) {
return parent;
}
}
const httpHeaders = event.headers || {};
const extractedContext = propagation.extract(otelContext.active(), httpHeaders, headerGetter);
if (trace.getSpan(extractedContext)?.spanContext()) {
return extractedContext;
Expand Down
Loading
Loading