Skip to content

Commit 8fe1574

Browse files
committed
feat(aws-sdk): add exception hook
1 parent 5d60689 commit 8fe1574

File tree

4 files changed

+89
-0
lines changed

4 files changed

+89
-0
lines changed

plugins/node/opentelemetry-instrumentation-aws-sdk/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ aws-sdk instrumentation has few options available to choose from. You can set th
5353
| ----------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5454
| `preRequestHook` | `AwsSdkRequestCustomAttributeFunction` | Hook called before request send, which allow to add custom attributes to span. |
5555
| `responseHook` | `AwsSdkResponseCustomAttributeFunction` | Hook for adding custom attributes when response is received from aws. |
56+
| `exceptionHook` | `AwsSdkExceptionCustomAttributeFunction` | Hook for adding custom attributes when exception is received from aws. |
5657
| `sqsProcessHook` | `AwsSdkSqsProcessCustomAttributeFunction` | Hook called after starting sqs `process` span (for each sqs received message), which allow to add custom attributes to it. |
5758
| `suppressInternalInstrumentation` | `boolean` | Most aws operation use http requests under the hood. Set this to `true` to hide all underlying http spans. |
5859
| `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) |

plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,30 @@ export class AwsInstrumentation extends InstrumentationBase<AwsSdkInstrumentatio
310310
);
311311
}
312312

313+
private _callUserExceptionResponseHook(
314+
span: Span,
315+
request: NormalizedRequest,
316+
err: any
317+
) {
318+
const { exceptionHook } = this.getConfig();
319+
if (!exceptionHook) return;
320+
const requestInfo: AwsSdkRequestHookInformation = {
321+
request,
322+
};
323+
324+
safeExecuteInTheMiddle(
325+
() => exceptionHook(span, requestInfo, err),
326+
(e: Error | undefined) => {
327+
if (e)
328+
diag.error(
329+
`${AwsInstrumentation.component} instrumentation: exceptionHook error`,
330+
e
331+
);
332+
},
333+
true
334+
);
335+
}
336+
313337
private _registerV2CompletedEvent(
314338
span: Span,
315339
v2Request: V2PluginRequest,
@@ -557,6 +581,11 @@ export class AwsInstrumentation extends InstrumentationBase<AwsSdkInstrumentatio
557581
message: err.message,
558582
});
559583
span.recordException(err);
584+
self._callUserExceptionResponseHook(
585+
span,
586+
normalizedRequest,
587+
err
588+
);
560589
throw err;
561590
})
562591
.finally(() => {

plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export interface AwsSdkResponseHookInformation {
4848
moduleVersion?: string;
4949
response: NormalizedResponse;
5050
}
51+
5152
/**
5253
* span can be used to add custom attributes, or for any other need.
5354
* response is the object that is returned to the user calling the aws-sdk operation.
@@ -57,6 +58,14 @@ export interface AwsSdkResponseCustomAttributeFunction {
5758
(span: Span, responseInfo: AwsSdkResponseHookInformation): void;
5859
}
5960

61+
/**
62+
* span can be used to modify the status.
63+
* As we have no response object, the request can be used to determine the failed aws-sdk operation.
64+
*/
65+
export interface AwsSdkExceptionCustomAttributeFunction {
66+
(span: Span, requestInfo: AwsSdkRequestHookInformation, err: any): void;
67+
}
68+
6069
export interface AwsSdkSqsProcessHookInformation {
6170
message: SQS.Message;
6271
}
@@ -76,6 +85,12 @@ export interface AwsSdkInstrumentationConfig extends InstrumentationConfig {
7685
/** hook for adding custom attributes when response is received from aws */
7786
responseHook?: AwsSdkResponseCustomAttributeFunction;
7887

88+
/**
89+
* Hook for adding custom attributes when exception is received from aws.
90+
* This hook is only available with aws sdk v3
91+
*/
92+
exceptionHook?: AwsSdkExceptionCustomAttributeFunction;
93+
7994
/** hook for adding custom attribute when an sqs process span is started */
8095
sqsProcessHook?: AwsSdkSqsProcessCustomAttributeFunction;
8196

plugins/node/opentelemetry-instrumentation-aws-sdk/test/aws-sdk-v3.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,50 @@ describe('instrumentation-aws-sdk-v3', () => {
284284
);
285285
});
286286
});
287+
288+
it('handle aws sdk exception', async () => {
289+
instrumentation.disable();
290+
instrumentation.setConfig({
291+
exceptionHook: (
292+
span: Span,
293+
requestInfo: AwsSdkRequestHookInformation,
294+
err: any
295+
) => {
296+
span.setAttribute(
297+
'attribute.from.exception.hook',
298+
requestInfo.request.commandInput.Bucket
299+
);
300+
span.setAttribute('error.from.exception.hook', err.name);
301+
},
302+
303+
suppressInternalInstrumentation: true,
304+
});
305+
instrumentation.enable();
306+
307+
nock(`https://ot-demo-test.s3.${region}.amazonaws.com/`)
308+
.put('/aws-ot-s3-test-object.txt?x-id=PutObject')
309+
.reply(
310+
404,
311+
fs.readFileSync('./test/mock-responses/s3-put-object.xml', 'utf8')
312+
);
313+
314+
const params = {
315+
Bucket: 'ot-demo-test',
316+
Key: 'aws-ot-s3-test-object.txt',
317+
};
318+
try {
319+
await s3Client.putObject(params);
320+
} catch {
321+
expect(getTestSpans().length).toBe(1);
322+
const [span] = getTestSpans();
323+
expect(span.attributes['attribute.from.exception.hook']).toEqual(
324+
params.Bucket
325+
);
326+
expect(span.attributes['error.from.exception.hook']).toEqual(
327+
'NotFound'
328+
);
329+
}
330+
});
287331
});
288332

289333
describe('custom service behavior', () => {

0 commit comments

Comments
 (0)