From 117d248f3ddfdcc5d7554d5b8f232873ab2addf0 Mon Sep 17 00:00:00 2001 From: Richard Hillmann Date: Thu, 22 Aug 2024 15:12:10 +0200 Subject: [PATCH] feat(aws-sdk): add exception hook --- .../README.md | 1 + .../src/aws-sdk.ts | 29 ++++++++++++ .../src/types.ts | 15 +++++++ .../test/aws-sdk-v3.test.ts | 44 +++++++++++++++++++ 4 files changed, 89 insertions(+) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md index a6e01f85ba..8d5c7d94e7 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md @@ -53,6 +53,7 @@ aws-sdk instrumentation has few options available to choose from. You can set th | ----------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `preRequestHook` | `AwsSdkRequestCustomAttributeFunction` | Hook called before request send, which allow to add custom attributes to span. | | `responseHook` | `AwsSdkResponseCustomAttributeFunction` | Hook for adding custom attributes when response is received from aws. | +| `exceptionHook` | `AwsSdkExceptionCustomAttributeFunction` | Hook for adding custom attributes when exception is received from aws. | | `sqsProcessHook` | `AwsSdkSqsProcessCustomAttributeFunction` | Hook called after starting sqs `process` span (for each sqs received message), which allow to add custom attributes to it. | | `suppressInternalInstrumentation` | `boolean` | Most aws operation use http requests under the hood. Set this to `true` to hide all underlying http spans. | | `sqsExtractContextPropagationFromPayload` | `boolean` | Will parse and extract context propagation headers from SQS Payload, false by default. [When should it be used?](./doc/sns.md#integration-with-sqs) | diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts index c8180d3def..2934d3f875 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts @@ -309,6 +309,30 @@ export class AwsInstrumentation extends InstrumentationBase exceptionHook(span, requestInfo, err), + (e: Error | undefined) => { + if (e) + diag.error( + `${AwsInstrumentation.component} instrumentation: exceptionHook error`, + e + ); + }, + true + ); + } + private _registerV2CompletedEvent( span: Span, v2Request: V2PluginRequest, @@ -556,6 +580,11 @@ export class AwsInstrumentation extends InstrumentationBase { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts index ce99e8c441..b3ff3d7edb 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts @@ -48,6 +48,7 @@ export interface AwsSdkResponseHookInformation { moduleVersion?: string; response: NormalizedResponse; } + /** * span can be used to add custom attributes, or for any other need. * response is the object that is returned to the user calling the aws-sdk operation. @@ -57,6 +58,14 @@ export interface AwsSdkResponseCustomAttributeFunction { (span: Span, responseInfo: AwsSdkResponseHookInformation): void; } +/** + * span can be used to modify the status. + * As we have no response object, the request can be used to determine the failed aws-sdk operation. + */ +export interface AwsSdkExceptionCustomAttributeFunction { + (span: Span, requestInfo: AwsSdkRequestHookInformation, err: any): void; +} + export interface AwsSdkSqsProcessHookInformation { message: SQS.Message; } @@ -76,6 +85,12 @@ export interface AwsSdkInstrumentationConfig extends InstrumentationConfig { /** hook for adding custom attributes when response is received from aws */ responseHook?: AwsSdkResponseCustomAttributeFunction; + /** + * Hook for adding custom attributes when exception is received from aws. + * This hook is only available with aws sdk v3 + */ + exceptionHook?: AwsSdkExceptionCustomAttributeFunction; + /** hook for adding custom attribute when an sqs process span is started */ sqsProcessHook?: AwsSdkSqsProcessCustomAttributeFunction; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/aws-sdk-v3.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/aws-sdk-v3.test.ts index 0e3a752c1b..e553ab98dd 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/aws-sdk-v3.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/aws-sdk-v3.test.ts @@ -272,6 +272,50 @@ describe('instrumentation-aws-sdk-v3', () => { ); }); }); + + it('handle aws sdk exception', async () => { + instrumentation.disable(); + instrumentation.setConfig({ + exceptionHook: ( + span: Span, + requestInfo: AwsSdkRequestHookInformation, + err: any + ) => { + span.setAttribute( + 'attribute.from.exception.hook', + requestInfo.request.commandInput.Bucket + ); + span.setAttribute('error.from.exception.hook', err.name); + }, + + suppressInternalInstrumentation: true, + }); + instrumentation.enable(); + + nock(`https://ot-demo-test.s3.${region}.amazonaws.com/`) + .put('/aws-ot-s3-test-object.txt?x-id=PutObject') + .reply( + 404, + fs.readFileSync('./test/mock-responses/s3-put-object.xml', 'utf8') + ); + + const params = { + Bucket: 'ot-demo-test', + Key: 'aws-ot-s3-test-object.txt', + }; + try { + await s3Client.putObject(params); + } catch { + expect(getTestSpans().length).toBe(1); + const [span] = getTestSpans(); + expect(span.attributes['attribute.from.exception.hook']).toEqual( + params.Bucket + ); + expect(span.attributes['error.from.exception.hook']).toEqual( + 'NotFound' + ); + } + }); }); describe('custom service behavior', () => {