33
44import {
55 diag ,
6- isSpanContextValid ,
76 Context as OtelContext ,
87 context as otelContext ,
98 propagation ,
@@ -22,7 +21,7 @@ import {
2221 NormalizedRequest ,
2322 NormalizedResponse ,
2423} from '@opentelemetry/instrumentation-aws-sdk' ;
25- import { AWSXRAY_TRACE_ID_HEADER , AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray' ;
24+ import { AWSXRAY_TRACE_ID_HEADER } from '@opentelemetry/propagator-aws-xray' ;
2625import { APIGatewayProxyEventHeaders , Context } from 'aws-lambda' ;
2726import { AWS_ATTRIBUTE_KEYS } from '../aws-attribute-keys' ;
2827import { RequestMetadata } from '../third-party/otel/aws/services/ServiceExtension' ;
@@ -42,7 +41,6 @@ import { suppressTracing } from '@opentelemetry/core';
4241export const traceContextEnvironmentKey = '_X_AMZN_TRACE_ID' ;
4342export const AWSXRAY_TRACE_ID_HEADER_CAPITALIZED = 'X-Amzn-Trace-Id' ;
4443
45- const awsPropagator = new AWSXRayPropagator ( ) ;
4644export const headerGetter : TextMapGetter < APIGatewayProxyEventHeaders > = {
4745 keys ( carrier : any ) : string [ ] {
4846 return Object . keys ( carrier ) ;
@@ -94,28 +92,29 @@ export function applyInstrumentationPatches(instrumentations: Instrumentation[])
9492
9593/*
9694 * This function `customExtractor` is used to extract SpanContext for AWS Lambda functions.
97- * It first attempts to extract the trace context from the AWS X-Ray header, which is stored in the Lambda environment variables.
98- * If a valid span context is extracted from the environment, it uses this as the parent context for the function's tracing.
99- * If the X-Ray header is missing or invalid, it falls back to extracting trace context from the Lambda handler's event headers.
100- * If neither approach succeeds, it defaults to using the root Otel context, ensuring the function is still instrumented for tracing.
95+ * It extracts the X-Ray trace ID from the Lambda context (xRayTraceId) or environment variable (_X_AMZN_TRACE_ID) into the event headers
96+ * It then uses OpenTelemetry global propagator to extract trace context from the event headers
97+ * If a valid span context is extracted, it returns that context; otherwise, it returns the root context.
10198 */
99+ const lambdaContextXrayTraceIdKey = 'xRayTraceId' ;
102100export const customExtractor = ( event : any , _handlerContext : Context ) : OtelContext => {
103- let parent : OtelContext | undefined = undefined ;
104- const lambdaTraceHeader = process . env [ traceContextEnvironmentKey ] ;
105- if ( lambdaTraceHeader ) {
106- parent = awsPropagator . extract (
107- otelContext . active ( ) ,
108- { [ AWSXRAY_TRACE_ID_HEADER ] : lambdaTraceHeader } ,
109- headerGetter
110- ) ;
111- }
112- if ( parent ) {
113- const spanContext = trace . getSpan ( parent ) ?. spanContext ( ) ;
114- if ( spanContext && isSpanContextValid ( spanContext ) ) {
115- return parent ;
116- }
117- }
101+ const xrayTraceIdFromLambdaContext = _handlerContext
102+ ? ( _handlerContext as any ) [ lambdaContextXrayTraceIdKey ]
103+ : undefined ;
104+ const xrayTraceIdFromLambdaEnv = process . env [ traceContextEnvironmentKey ] ;
105+ const xrayTraceIdFromLambda = xrayTraceIdFromLambdaContext || xrayTraceIdFromLambdaEnv ;
106+
118107 const httpHeaders = event . headers || { } ;
108+ if ( xrayTraceIdFromLambda ) {
109+ // Delete any X-Ray Trace ID via case-insensitive checks since we will overwrite it here.
110+ Object . keys ( httpHeaders ) . forEach ( key => {
111+ if ( key . toLowerCase ( ) === AWSXRAY_TRACE_ID_HEADER . toLowerCase ( ) ) {
112+ delete httpHeaders [ key ] ;
113+ }
114+ } ) ;
115+ httpHeaders [ AWSXRAY_TRACE_ID_HEADER ] = xrayTraceIdFromLambda ;
116+ }
117+
119118 const extractedContext = propagation . extract ( otelContext . active ( ) , httpHeaders , headerGetter ) ;
120119 if ( trace . getSpan ( extractedContext ) ?. spanContext ( ) ) {
121120 return extractedContext ;
0 commit comments