@@ -12,9 +12,12 @@ import {
1212 trace ,
1313 Span ,
1414 Tracer ,
15+ SpanStatusCode ,
16+ defaultTextMapSetter ,
1517} from '@opentelemetry/api' ;
1618import { Instrumentation } from '@opentelemetry/instrumentation' ;
1719import {
20+ AwsInstrumentation ,
1821 AwsSdkInstrumentationConfig ,
1922 NormalizedRequest ,
2023 NormalizedResponse ,
@@ -31,9 +34,8 @@ import {
3134} from './aws/services/bedrock' ;
3235import { SecretsManagerServiceExtension } from './aws/services/secretsmanager' ;
3336import { StepFunctionsServiceExtension } from './aws/services/step-functions' ;
34- import { InstrumentationConfigMap } from '@opentelemetry/auto-instrumentations-node' ;
35- import { AwsSdkInstrumentationExtended } from './extended-instrumentations/aws-sdk-instrumentation-extended' ;
36- import { AwsLambdaInstrumentationPatch } from './extended-instrumentations/aws-lambda' ;
37+ import { AwsLambdaInstrumentation } from '@opentelemetry/instrumentation-aws-lambda' ;
38+ import type { Command as AwsV3Command } from '@aws-sdk/types' ;
3739
3840export const traceContextEnvironmentKey = '_X_AMZN_TRACE_ID' ;
3941const awsPropagator = new AWSXRayPropagator ( ) ;
@@ -46,11 +48,7 @@ export const headerGetter: TextMapGetter<APIGatewayProxyEventHeaders> = {
4648 } ,
4749} ;
4850
49- export function applyInstrumentationPatches (
50- instrumentations : Instrumentation [ ] ,
51- instrumentationConfigs ?: InstrumentationConfigMap ,
52- usePatchedAwsLambdaInstrumentation : boolean = false
53- ) : void {
51+ export function applyInstrumentationPatches ( instrumentations : Instrumentation [ ] ) : void {
5452 /*
5553 Apply patches to upstream instrumentation libraries.
5654
@@ -62,10 +60,8 @@ export function applyInstrumentationPatches(
6260 */
6361 instrumentations . forEach ( ( instrumentation , index ) => {
6462 if ( instrumentation . instrumentationName === '@opentelemetry/instrumentation-aws-sdk' ) {
65- diag . debug ( 'Overriding aws sdk instrumentation' ) ;
66- instrumentations [ index ] = new AwsSdkInstrumentationExtended (
67- instrumentationConfigs ? instrumentationConfigs [ '@opentelemetry/instrumentation-aws-sdk' ] : undefined
68- ) ;
63+ diag . debug ( 'Patching aws sdk instrumentation' ) ;
64+ patchAwsSdkInstrumentation ( instrumentation ) ;
6965
7066 // Access private property servicesExtensions of AwsInstrumentation
7167 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -83,18 +79,11 @@ export function applyInstrumentationPatches(
8379 patchSnsServiceExtension ( services . get ( 'SNS' ) ) ;
8480 patchLambdaServiceExtension ( services . get ( 'Lambda' ) ) ;
8581 }
82+ } else if ( instrumentation . instrumentationName === '@opentelemetry/instrumentation-aws-lambda' ) {
83+ diag . debug ( 'Patching aws lambda instrumentation' ) ;
84+ patchAwsLambdaInstrumentation ( instrumentation ) ;
8685 }
8786 } ) ;
88-
89- if ( usePatchedAwsLambdaInstrumentation ) {
90- diag . debug ( 'Overriding aws lambda instrumentation' ) ;
91- const lambdaInstrumentation = new AwsLambdaInstrumentationPatch ( {
92- // When the `AwsLambdaInstrumentationPatch` is removed in favor of the patched one,
93- // setting `eventContextExtractor` should be in the `instrumentationConfigs` map.
94- eventContextExtractor : customExtractor ,
95- } ) ;
96- instrumentations . push ( lambdaInstrumentation ) ;
97- }
9887}
9988
10089/*
@@ -259,3 +248,78 @@ function patchLambdaServiceExtension(lambdaServiceExtension: any): void {
259248 }
260249 }
261250}
251+
252+ // Override the upstream private _endSpan method to remove the unnecessary metric force-flush error message
253+ // https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/plugins/node/opentelemetry-instrumentation-aws-lambda/src/instrumentation.ts#L358-L398
254+ function patchAwsLambdaInstrumentation ( instrumentation : Instrumentation ) : void {
255+ if ( instrumentation ) {
256+ ( instrumentation as AwsLambdaInstrumentation ) [ '_endSpan' ] = function (
257+ span : Span ,
258+ err : string | Error | null | undefined ,
259+ callback : ( ) => void
260+ ) {
261+ if ( err ) {
262+ span . recordException ( err ) ;
263+ }
264+
265+ let errMessage ;
266+ if ( typeof err === 'string' ) {
267+ errMessage = err ;
268+ } else if ( err ) {
269+ errMessage = err . message ;
270+ }
271+ if ( errMessage ) {
272+ span . setStatus ( {
273+ code : SpanStatusCode . ERROR ,
274+ message : errMessage ,
275+ } ) ;
276+ }
277+
278+ span . end ( ) ;
279+
280+ const flushers = [ ] ;
281+ if ( ( this as any ) . _traceForceFlusher ) {
282+ flushers . push ( ( this as any ) . _traceForceFlusher ( ) ) ;
283+ } else {
284+ diag . error (
285+ 'Spans may not be exported for the lambda function because we are not force flushing before callback.'
286+ ) ;
287+ }
288+
289+ Promise . all ( flushers ) . then ( callback , callback ) ;
290+ } ;
291+ }
292+ }
293+
294+ // Override the upstream private _getV3SmithyClientSendPatch method to add middleware to inject X-Ray Trace Context into HTTP Headers
295+ // https://github.com/open-telemetry/opentelemetry-js-contrib/blob/instrumentation-aws-sdk-v0.48.0/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts#L373-L384
296+ const awsXrayPropagator = new AWSXRayPropagator ( ) ;
297+ const V3_CLIENT_CONFIG_KEY = Symbol ( 'opentelemetry.instrumentation.aws-sdk.client.config' ) ;
298+ type V3PluginCommand = AwsV3Command < any , any , any , any , any > & {
299+ [ V3_CLIENT_CONFIG_KEY ] ?: any ;
300+ } ;
301+ function patchAwsSdkInstrumentation ( instrumentation : Instrumentation ) : void {
302+ if ( instrumentation ) {
303+ ( instrumentation as AwsInstrumentation ) [ '_getV3SmithyClientSendPatch' ] = function (
304+ original : ( ...args : unknown [ ] ) => Promise < any >
305+ ) {
306+ return function send ( this : any , command : V3PluginCommand , ...args : unknown [ ] ) : Promise < any > {
307+ this . middlewareStack ?. add (
308+ ( next : any , context : any ) => async ( middlewareArgs : any ) => {
309+ awsXrayPropagator . inject ( otelContext . active ( ) , middlewareArgs . request . headers , defaultTextMapSetter ) ;
310+ const result = await next ( middlewareArgs ) ;
311+ return result ;
312+ } ,
313+ {
314+ step : 'build' ,
315+ name : '_adotInjectXrayContextMiddleware' ,
316+ override : true ,
317+ }
318+ ) ;
319+
320+ command [ V3_CLIENT_CONFIG_KEY ] = this . config ;
321+ return original . apply ( this , [ command , ...args ] ) ;
322+ } ;
323+ } ;
324+ }
325+ }
0 commit comments