From a5acebfae800d38983fd9149f7191a8c68b248de Mon Sep 17 00:00:00 2001 From: Matthew Turner Date: Wed, 1 Nov 2023 13:00:24 +1100 Subject: [PATCH 1/5] feat: add configuration to customise dynamodb statement serialization --- .../README.md | 25 +- .../src/aws-sdk.ts | 18 +- .../src/services/ServiceExtension.ts | 2 +- .../src/services/ServicesExtensions.ts | 7 +- .../src/services/dynamodb.ts | 14 +- .../src/services/lambda.ts | 2 +- .../src/services/sns.ts | 2 +- .../src/services/sqs.ts | 5 +- .../src/types.ts | 11 +- .../test/dynamodb.test.ts | 298 ++++++++++++++++-- 10 files changed, 328 insertions(+), 56 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md index a49b72860a..a21b08fd79 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md @@ -20,11 +20,11 @@ npm install --save @opentelemetry/instrumentation-aws-sdk For further automatic instrumentation instruction see the [@opentelemetry/instrumentation](https://www.npmjs.com/package/@opentelemetry/instrumentation) package. ```js -const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); -const { registerInstrumentations } = require("@opentelemetry/instrumentation"); +const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); const { AwsInstrumentation, -} = require("@opentelemetry/instrumentation-aws-sdk"); +} = require('@opentelemetry/instrumentation-aws-sdk'); const provider = new NodeTracerProvider(); provider.register(); @@ -42,13 +42,14 @@ registerInstrumentations({ aws-sdk instrumentation has few options available to choose from. You can set the following: -| Options | Type | Description | -| --------------------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `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. | -| `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)| +| Options | Type | Description | +| ----------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `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. | +| `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) | +| `dynamoDBStatementSerializer` | `AwsSdkDynamoDBStatementSerializer` | AWS SDK instrumentation will serialize DynamoDB commands to the `db.statement` attribute using the specified function. Defaults to using a serializer that returns `undefined`. | ## Span Attributes @@ -82,8 +83,8 @@ Usage example: ```js awsInstrumentationConfig = { preRequestHook: (span, request) => { - if (span.serviceName === "s3") { - span.setAttribute("s3.bucket.name", request.commandInput["Bucket"]); + if (span.serviceName === 's3') { + span.setAttribute('s3.bucket.name', request.commandInput['Bucket']); } }, }; 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 b82192ce82..b766ab448e 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts @@ -475,8 +475,10 @@ export class AwsInstrumentation extends InstrumentationBase { command.input, undefined ); - const requestMetadata = - self.servicesExtensions.requestPreSpanHook(normalizedRequest); + const requestMetadata = self.servicesExtensions.requestPreSpanHook( + normalizedRequest, + self._config + ); const span = self._startAwsV3Span(normalizedRequest, requestMetadata); const activeContextWithSpan = trace.setSpan(context.active(), span); @@ -602,8 +604,10 @@ export class AwsInstrumentation extends InstrumentationBase { } const normalizedRequest = normalizeV2Request(this); - const requestMetadata = - self.servicesExtensions.requestPreSpanHook(normalizedRequest); + const requestMetadata = self.servicesExtensions.requestPreSpanHook( + normalizedRequest, + self._config + ); const span = self._startAwsV2Span( this, requestMetadata, @@ -642,8 +646,10 @@ export class AwsInstrumentation extends InstrumentationBase { } const normalizedRequest = normalizeV2Request(this); - const requestMetadata = - self.servicesExtensions.requestPreSpanHook(normalizedRequest); + const requestMetadata = self.servicesExtensions.requestPreSpanHook( + normalizedRequest, + self._config + ); const span = self._startAwsV2Span( this, requestMetadata, diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts index 5a08fecf69..1808d1174a 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts @@ -30,7 +30,7 @@ export interface RequestMetadata { export interface ServiceExtension { // called before request is sent, and before span is started - requestPreSpanHook: (request: NormalizedRequest) => RequestMetadata; + requestPreSpanHook: (request: NormalizedRequest, config: AwsSdkInstrumentationConfig) => RequestMetadata; // called before request is sent, and after span is started requestPostSpanHook?: (request: NormalizedRequest) => void; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts index 52ab59d886..7cc0d9bc6b 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts @@ -35,13 +35,16 @@ export class ServicesExtensions implements ServiceExtension { this.services.set('Lambda', new LambdaServiceExtension()); } - requestPreSpanHook(request: NormalizedRequest): RequestMetadata { + requestPreSpanHook( + request: NormalizedRequest, + config: AwsSdkInstrumentationConfig + ): RequestMetadata { const serviceExtension = this.services.get(request.serviceName); if (!serviceExtension) return { isIncoming: false, }; - return serviceExtension.requestPreSpanHook(request); + return serviceExtension.requestPreSpanHook(request, config); } requestPostSpanHook(request: NormalizedRequest) { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts index 657d71e407..ef8659a2c7 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts @@ -21,26 +21,36 @@ import { } from '@opentelemetry/semantic-conventions'; import { AwsSdkInstrumentationConfig, + AwsSdkDynamoDBStatementSerializer, NormalizedRequest, NormalizedResponse, } from '../types'; +const defaultDynamoDBStatementSerializer: AwsSdkDynamoDBStatementSerializer = () => + undefined; + export class DynamodbServiceExtension implements ServiceExtension { toArray(values: T | T[]): T[] { return Array.isArray(values) ? values : [values]; } - requestPreSpanHook(normalizedRequest: NormalizedRequest): RequestMetadata { + requestPreSpanHook( + normalizedRequest: NormalizedRequest, + config: AwsSdkInstrumentationConfig + ): RequestMetadata { const spanKind: SpanKind = SpanKind.CLIENT; let spanName: string | undefined; const isIncoming = false; const operation = normalizedRequest.commandName; + const dbStatementSerializer = + config.dynamoDBStatementSerializer || defaultDynamoDBStatementSerializer; + const spanAttributes = { [SemanticAttributes.DB_SYSTEM]: DbSystemValues.DYNAMODB, [SemanticAttributes.DB_NAME]: normalizedRequest.commandInput?.TableName, [SemanticAttributes.DB_OPERATION]: operation, - [SemanticAttributes.DB_STATEMENT]: JSON.stringify( + [SemanticAttributes.DB_STATEMENT]: dbStatementSerializer( normalizedRequest.commandInput ), }; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/lambda.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/lambda.ts index 35a9d4a8c5..02ae13b7bf 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/lambda.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/lambda.ts @@ -34,7 +34,7 @@ class LambdaCommands { } export class LambdaServiceExtension implements ServiceExtension { - requestPreSpanHook(request: NormalizedRequest): RequestMetadata { + requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata { const functionName = this.extractFunctionName(request.commandInput); let spanAttributes: SpanAttributes = {}; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts index 9652719e83..1814b376b7 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts @@ -27,7 +27,7 @@ import { injectPropagationContext } from './MessageAttributes'; import { RequestMetadata, ServiceExtension } from './ServiceExtension'; export class SnsServiceExtension implements ServiceExtension { - requestPreSpanHook(request: NormalizedRequest): RequestMetadata { + requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata { let spanKind: SpanKind = SpanKind.CLIENT; let spanName = `SNS ${request.commandName}`; const spanAttributes = { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sqs.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sqs.ts index f428d68cd3..40fee45cd9 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sqs.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sqs.ts @@ -43,7 +43,10 @@ import { } from './MessageAttributes'; export class SqsServiceExtension implements ServiceExtension { - requestPreSpanHook(request: NormalizedRequest): RequestMetadata { + requestPreSpanHook( + request: NormalizedRequest, + _config: AwsSdkInstrumentationConfig + ): RequestMetadata { const queueUrl = this.extractQueueUrl(request.commandInput); const queueName = this.extractQueueNameFromUrl(queueUrl); let spanKind: SpanKind = SpanKind.CLIENT; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts index e23033c9f5..dd606c31df 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts @@ -17,6 +17,8 @@ import { Span } from '@opentelemetry/api'; import { InstrumentationConfig } from '@opentelemetry/instrumentation'; import { SQS } from './aws-sdk.types'; +export type CommandInput = Record; + /** * These are normalized request and response, which are used by both sdk v2 and v3. * They organize the relevant data in one interface which can be processed in a @@ -25,7 +27,7 @@ import { SQS } from './aws-sdk.types'; export interface NormalizedRequest { serviceName: string; commandName: string; - commandInput: Record; + commandInput: CommandInput; region?: string; } export interface NormalizedResponse { @@ -62,6 +64,10 @@ export interface AwsSdkSqsProcessCustomAttributeFunction { (span: Span, sqsProcessInfo: AwsSdkSqsProcessHookInformation): void; } +export type AwsSdkDynamoDBStatementSerializer = ( + commandInput: CommandInput +) => string | undefined; + export interface AwsSdkInstrumentationConfig extends InstrumentationConfig { /** hook for adding custom attributes before request is sent to aws */ preRequestHook?: AwsSdkRequestCustomAttributeFunction; @@ -72,6 +78,9 @@ export interface AwsSdkInstrumentationConfig extends InstrumentationConfig { /** hook for adding custom attribute when an sqs process span is started */ sqsProcessHook?: AwsSdkSqsProcessCustomAttributeFunction; + /** custom serializer function for the db.statement attribute in DynamoDB spans */ + dynamoDBStatementSerializer?: AwsSdkDynamoDBStatementSerializer; + /** * Most aws operation use http request under the hood. * if http instrumentation is enabled, each aws operation will also create diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts index ab5f6b1db5..d79d5e08cb 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts @@ -13,12 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { AwsInstrumentation } from '../src'; +import { + AwsInstrumentation, + CommandInput, + AwsSdkDynamoDBStatementSerializer, +} from '../src'; import { getTestSpans, registerInstrumentationTesting, } from '@opentelemetry/contrib-test-utils'; -registerInstrumentationTesting(new AwsInstrumentation()); +const instrumentation = registerInstrumentationTesting( + new AwsInstrumentation() +); import * as AWS from 'aws-sdk'; import { AWSError } from 'aws-sdk'; @@ -109,9 +115,7 @@ describe('DynamoDB', () => { expect( attrs[SemanticAttributes.AWS_DYNAMODB_PROJECTION] ).toStrictEqual('id'); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -184,9 +188,7 @@ describe('DynamoDB', () => { expect( attrs[SemanticAttributes.AWS_DYNAMODB_PROJECTION] ).toStrictEqual('id'); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -232,9 +234,7 @@ describe('DynamoDB', () => { JSON.stringify({ ItemCollectionKey: [], SizeEstimateRangeGB: [0] }), ]); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -342,9 +342,7 @@ describe('DynamoDB', () => { expect( attrs[SemanticAttributes.AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY] ).toStrictEqual(30); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -428,9 +426,7 @@ describe('DynamoDB', () => { expect( attrs[SemanticAttributes.AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY] ).toStrictEqual(15); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -472,9 +468,7 @@ describe('DynamoDB', () => { attrs[SemanticAttributes.AWS_DYNAMODB_TABLE_COUNT] ).toStrictEqual(3); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -528,9 +522,7 @@ describe('DynamoDB', () => { expect( attrs[SemanticAttributes.AWS_DYNAMODB_CONSUMED_CAPACITY] ).toBeUndefined(); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(dynamodb_params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -579,9 +571,7 @@ describe('DynamoDB', () => { JSON.stringify(x) ) ); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(dynamodb_params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -624,9 +614,7 @@ describe('DynamoDB', () => { expect( attrs[SemanticAttributes.AWS_DYNAMODB_CONSUMED_CAPACITY] ).toBeUndefined(); - expect( - JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) - ).toEqual(dynamodb_params); + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); expect(err).toBeFalsy(); done(); } @@ -707,4 +695,256 @@ describe('DynamoDB', () => { ); }); }); + + describe('dbStatementSerializer config', () => { + const SERIALIZED_DB_STATEMENT = 'serialized statement'; + + const dynamoDBStatementSerializer: AwsSdkDynamoDBStatementSerializer = ( + _command: CommandInput + ): string => { + return SERIALIZED_DB_STATEMENT; + }; + + beforeEach(() => { + instrumentation.disable(); + instrumentation.setConfig({ + dynamoDBStatementSerializer, + }); + instrumentation.enable(); + }); + + it('should properly execute the db statement serializer for Query operation', done => { + mockV2AwsSend(responseMockSuccess, { + Items: [{ key1: 'val1' }, { key2: 'val2' }], + Count: 2, + ScannedCount: 5, + } as AWS.DynamoDB.Types.QueryOutput); + const dynamodb = new AWS.DynamoDB.DocumentClient(); + const params = { + TableName: 'test-table', + KeyConditionExpression: '#k = :v', + ExpressionAttributeNames: { + '#k': 'key1', + }, + ExpressionAttributeValues: { + ':v': 'val1', + }, + ProjectionExpression: 'id', + ScanIndexForward: true, + ConsistentRead: true, + IndexName: 'name_to_group', + Limit: 10, + Select: 'ALL_ATTRIBUTES', + }; + + dynamodb.query( + params, + (err: AWSError, _data: AWS.DynamoDB.DocumentClient.QueryOutput) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + + expect(attrs[SemanticAttributes.DB_STATEMENT]).toStrictEqual( + SERIALIZED_DB_STATEMENT + ); + expect(err).toBeFalsy(); + done(); + } + ); + }); + + it('should properly execute the db statement serializer for CreateTable operation', done => { + mockV2AwsSend(responseMockSuccess, { + TableName: 'test_table', + ItemCollectionMetrics: { + ItemCollectionKey: [], + SizeEstimateRangeGB: [0], + }, + ConsumedCapacity: undefined, + } as AWS.DynamoDB.Types.CreateTableOutput); + const globalSecondaryIndexMockData = { + IndexName: 'test_index', + KeySchema: [ + { + AttributeName: 'attribute1', + KeyType: 'HASH', + }, + ], + Projection: { + ProjectionType: 'ALL', + NonKeyAttributes: ['non_key_attr'], + }, + ProvisionedThroughput: { + ReadCapacityUnits: 5, + WriteCapacityUnits: 10, + }, + }; + + const localSecondaryIndexMockData = { + IndexName: 'test_index', + KeySchema: [ + { + AttributeName: 'test_attribute', + KeyType: 'HASH', + }, + ], + Projection: { + ProjectionType: 'ALL', + NonKeyAttributes: ['STRING_VALUE'], + }, + }; + + const dynamodb = new AWS.DynamoDB(); + const params = { + AttributeDefinitions: [ + { + AttributeName: 'test_attribute', + AttributeType: 'S', + }, + ], + TableName: 'test_table', + KeySchema: [ + { + AttributeName: 'test_attribute', + KeyType: 'HASH', + }, + ], + LocalSecondaryIndexes: [localSecondaryIndexMockData], + GlobalSecondaryIndexes: [globalSecondaryIndexMockData], + BillingMode: 'PROVISIONED', + ProvisionedThroughput: { + ReadCapacityUnits: 20, + WriteCapacityUnits: 30, + }, + }; + + dynamodb.createTable( + params, + ( + err: AWSError, + _data: AWS.DynamoDB.DocumentClient.CreateTableOutput + ) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + + expect(attrs[SemanticAttributes.DB_STATEMENT]).toStrictEqual( + SERIALIZED_DB_STATEMENT + ); + expect(err).toBeFalsy(); + done(); + } + ); + }); + + it('should properly execute the db statement serializer for UpdateTable operation', done => { + mockV2AwsSend(responseMockSuccess, { + TableName: 'test_table', + } as AWS.DynamoDB.Types.UpdateTableOutput); + const dynamodb = new AWS.DynamoDB(); + const params = { + AttributeDefinitions: [ + { + AttributeName: 'test_attr', + AttributeType: 'S', + }, + ], + TableName: 'test_table', + ProvisionedThroughput: { + ReadCapacityUnits: 10, + WriteCapacityUnits: 15, + }, + GlobalSecondaryIndexUpdates: [ + { + Update: { + IndexName: 'test_index', + ProvisionedThroughput: { + ReadCapacityUnits: 1, + WriteCapacityUnits: 5, + }, + }, + }, + ], + }; + + dynamodb.updateTable( + params, + ( + err: AWSError, + _data: AWS.DynamoDB.DocumentClient.UpdateTableOutput + ) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + + expect(attrs[SemanticAttributes.DB_STATEMENT]).toStrictEqual( + SERIALIZED_DB_STATEMENT + ); + expect(err).toBeFalsy(); + done(); + } + ); + }); + + it('should properly execute the db statement serializer for ListTables operation', done => { + mockV2AwsSend(responseMockSuccess, { + TableNames: ['test_table', 'test_table_2', 'start_table'], + } as AWS.DynamoDB.Types.ListTablesOutput); + const dynamodb = new AWS.DynamoDB(); + const params = { + ExclusiveStartTableName: 'start_table', + Limit: 10, + }; + + dynamodb.listTables( + params, + (err: AWSError, _data: AWS.DynamoDB.DocumentClient.ListTablesOutput) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + + expect(attrs[SemanticAttributes.DB_STATEMENT]).toStrictEqual( + SERIALIZED_DB_STATEMENT + ); + expect(err).toBeFalsy(); + done(); + } + ); + }); + + it('should properly execute the db statement serializer for BatchWriteItem operation', done => { + mockV2AwsSend(responseMockSuccess, { + UnprocessedItems: {}, + ItemCollectionMetrics: { + ItemCollectionKey: [], + SizeEstimateRangeGB: [0], + }, + ConsumedCapacity: undefined, + } as AWS.DynamoDB.Types.BatchWriteItemOutput); + const dynamodb = new AWS.DynamoDB.DocumentClient(); + const params = { + RequestItems: {}, + ReturnConsumedCapacity: 'INDEXES', + ReturnItemCollectionMetrics: 'SIZE', + }; + + dynamodb.batchWrite( + params, + ( + err: AWSError, + _data: AWS.DynamoDB.DocumentClient.BatchWriteItemOutput + ) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + + expect(attrs[SemanticAttributes.DB_STATEMENT]).toStrictEqual( + SERIALIZED_DB_STATEMENT + ); + expect(err).toBeFalsy(); + done(); + } + ); + }); + }); }); From 52d09b71cc206a6a40a77cfcf7ab69f7809805d2 Mon Sep 17 00:00:00 2001 From: Matthew Turner Date: Wed, 1 Nov 2023 13:02:00 +1100 Subject: [PATCH 2/5] fix: format readme --- plugins/node/opentelemetry-instrumentation-aws-sdk/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md index a21b08fd79..1a24f908bd 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md @@ -49,7 +49,7 @@ aws-sdk instrumentation has few options available to choose from. You can set th | `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) | -| `dynamoDBStatementSerializer` | `AwsSdkDynamoDBStatementSerializer` | AWS SDK instrumentation will serialize DynamoDB commands to the `db.statement` attribute using the specified function. Defaults to using a serializer that returns `undefined`. | +| `dynamoDBStatementSerializer` | `AwsSdkDynamoDBStatementSerializer` | AWS SDK instrumentation will serialize DynamoDB commands to the `db.statement` attribute using the specified function. Defaults to using a serializer that returns `undefined`. | ## Span Attributes From c198332cfe1df85371f4246f797a2400188420af Mon Sep 17 00:00:00 2001 From: Matthew Turner Date: Thu, 9 Nov 2023 22:56:04 +1100 Subject: [PATCH 3/5] chore: pass DiagLogger to DynamoDB instrumentation --- .../opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts | 9 ++++++--- .../src/services/ServiceExtension.ts | 4 ++-- .../src/services/ServicesExtensions.ts | 7 ++++--- .../src/services/dynamodb.ts | 5 +++-- 4 files changed, 15 insertions(+), 10 deletions(-) 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 b766ab448e..77bdaaba83 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts @@ -477,7 +477,8 @@ export class AwsInstrumentation extends InstrumentationBase { ); const requestMetadata = self.servicesExtensions.requestPreSpanHook( normalizedRequest, - self._config + self._config, + self._diag, ); const span = self._startAwsV3Span(normalizedRequest, requestMetadata); const activeContextWithSpan = trace.setSpan(context.active(), span); @@ -606,7 +607,8 @@ export class AwsInstrumentation extends InstrumentationBase { const normalizedRequest = normalizeV2Request(this); const requestMetadata = self.servicesExtensions.requestPreSpanHook( normalizedRequest, - self._config + self._config, + self._diag, ); const span = self._startAwsV2Span( this, @@ -648,7 +650,8 @@ export class AwsInstrumentation extends InstrumentationBase { const normalizedRequest = normalizeV2Request(this); const requestMetadata = self.servicesExtensions.requestPreSpanHook( normalizedRequest, - self._config + self._config, + self._diag, ); const span = self._startAwsV2Span( this, diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts index 1808d1174a..606a4ddd17 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Span, SpanAttributes, SpanKind, Tracer } from '@opentelemetry/api'; +import { DiagLogger, Span, SpanAttributes, SpanKind, Tracer } from '@opentelemetry/api'; import { AwsSdkInstrumentationConfig, NormalizedRequest, @@ -30,7 +30,7 @@ export interface RequestMetadata { export interface ServiceExtension { // called before request is sent, and before span is started - requestPreSpanHook: (request: NormalizedRequest, config: AwsSdkInstrumentationConfig) => RequestMetadata; + requestPreSpanHook: (request: NormalizedRequest, config: AwsSdkInstrumentationConfig, diag: DiagLogger) => RequestMetadata; // called before request is sent, and after span is started requestPostSpanHook?: (request: NormalizedRequest) => void; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts index 7cc0d9bc6b..cb739a2011 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Tracer, Span } from '@opentelemetry/api'; +import { Tracer, Span, DiagLogger } from '@opentelemetry/api'; import { ServiceExtension, RequestMetadata } from './ServiceExtension'; import { SqsServiceExtension } from './sqs'; import { @@ -37,14 +37,15 @@ export class ServicesExtensions implements ServiceExtension { requestPreSpanHook( request: NormalizedRequest, - config: AwsSdkInstrumentationConfig + config: AwsSdkInstrumentationConfig, + diag: DiagLogger ): RequestMetadata { const serviceExtension = this.services.get(request.serviceName); if (!serviceExtension) return { isIncoming: false, }; - return serviceExtension.requestPreSpanHook(request, config); + return serviceExtension.requestPreSpanHook(request, config, diag); } requestPostSpanHook(request: NormalizedRequest) { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts index ef8659a2c7..3e364d5eec 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Span, SpanKind, Tracer } from '@opentelemetry/api'; +import { DiagLogger, Span, SpanKind, Tracer } from '@opentelemetry/api'; import { RequestMetadata, ServiceExtension } from './ServiceExtension'; import { DbSystemValues, @@ -36,7 +36,8 @@ export class DynamodbServiceExtension implements ServiceExtension { requestPreSpanHook( normalizedRequest: NormalizedRequest, - config: AwsSdkInstrumentationConfig + config: AwsSdkInstrumentationConfig, + diag: DiagLogger, ): RequestMetadata { const spanKind: SpanKind = SpanKind.CLIENT; let spanName: string | undefined; From a37da4a5e76bcc85d3c04222a2e3acfd92016a90 Mon Sep 17 00:00:00 2001 From: Matthew Turner Date: Thu, 9 Nov 2023 22:56:39 +1100 Subject: [PATCH 4/5] chore: omit db statement when serializer is not configured or when it returned undefined Allow for passing operation to serializer --- .../src/services/dynamodb.ts | 25 ++- .../src/types.ts | 1 + .../test/dynamodb.test.ts | 200 +++++++++++++++++- 3 files changed, 215 insertions(+), 11 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts index 3e364d5eec..c285867cd8 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts @@ -21,14 +21,10 @@ import { } from '@opentelemetry/semantic-conventions'; import { AwsSdkInstrumentationConfig, - AwsSdkDynamoDBStatementSerializer, NormalizedRequest, NormalizedResponse, } from '../types'; -const defaultDynamoDBStatementSerializer: AwsSdkDynamoDBStatementSerializer = () => - undefined; - export class DynamodbServiceExtension implements ServiceExtension { toArray(values: T | T[]): T[] { return Array.isArray(values) ? values : [values]; @@ -44,18 +40,27 @@ export class DynamodbServiceExtension implements ServiceExtension { const isIncoming = false; const operation = normalizedRequest.commandName; - const dbStatementSerializer = - config.dynamoDBStatementSerializer || defaultDynamoDBStatementSerializer; - const spanAttributes = { [SemanticAttributes.DB_SYSTEM]: DbSystemValues.DYNAMODB, [SemanticAttributes.DB_NAME]: normalizedRequest.commandInput?.TableName, [SemanticAttributes.DB_OPERATION]: operation, - [SemanticAttributes.DB_STATEMENT]: dbStatementSerializer( - normalizedRequest.commandInput - ), }; + if (config.dynamoDBStatementSerializer) { + try { + const sanitizedStatement = config.dynamoDBStatementSerializer( + operation, + normalizedRequest.commandInput + ); + + if (typeof sanitizedStatement === 'string') { + spanAttributes[SemanticAttributes.DB_STATEMENT] = sanitizedStatement; + } + } catch (err) { + diag.error('failed to sanitize DynamoDB statement', err); + } + } + // normalizedRequest.commandInput.RequestItems) is undefined when no table names are returned // keys in this object are the table names if (normalizedRequest.commandInput?.TableName) { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts index dd606c31df..ce99e8c441 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts @@ -65,6 +65,7 @@ export interface AwsSdkSqsProcessCustomAttributeFunction { } export type AwsSdkDynamoDBStatementSerializer = ( + operation: string, commandInput: CommandInput ) => string | undefined; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts index d79d5e08cb..ea4317c63d 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts @@ -36,6 +36,7 @@ import { import { expect } from 'expect'; import type { ConsumedCapacity as ConsumedCapacityV2 } from 'aws-sdk/clients/dynamodb'; import type { ConsumedCapacity as ConsumedCapacityV3 } from '@aws-sdk/client-dynamodb'; +import * as sinon from 'sinon'; type ConsumedCapacity = ConsumedCapacityV2 | ConsumedCapacityV3; @@ -700,6 +701,7 @@ describe('DynamoDB', () => { const SERIALIZED_DB_STATEMENT = 'serialized statement'; const dynamoDBStatementSerializer: AwsSdkDynamoDBStatementSerializer = ( + _operation: string, _command: CommandInput ): string => { return SERIALIZED_DB_STATEMENT; @@ -713,6 +715,199 @@ describe('DynamoDB', () => { instrumentation.enable(); }); + it('should not fail if serializer throws', done => { + instrumentation.disable(); + instrumentation.setConfig({ + dynamoDBStatementSerializer: () => { + throw new Error('Serializer failure'); + }, + }); + instrumentation.enable(); + mockV2AwsSend(responseMockSuccess, { + Items: [{ key1: 'val1' }, { key2: 'val2' }], + Count: 2, + ScannedCount: 5, + } as AWS.DynamoDB.Types.QueryOutput); + const dynamodb = new AWS.DynamoDB.DocumentClient(); + const params = { + TableName: 'test-table', + KeyConditionExpression: '#k = :v', + ExpressionAttributeNames: { + '#k': 'key1', + }, + ExpressionAttributeValues: { + ':v': 'val1', + }, + ProjectionExpression: 'id', + ScanIndexForward: true, + ConsistentRead: true, + IndexName: 'name_to_group', + Limit: 10, + Select: 'ALL_ATTRIBUTES', + }; + + dynamodb.query( + params, + (err: AWSError, _data: AWS.DynamoDB.DocumentClient.QueryOutput) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); + expect(err).toBeFalsy(); + done(); + } + ); + }); + + it('should omit DB statement if serializer is not configured', done => { + instrumentation.disable(); + instrumentation.setConfig({ + dynamoDBStatementSerializer: undefined, + }); + instrumentation.enable(); + mockV2AwsSend(responseMockSuccess, { + Items: [{ key1: 'val1' }, { key2: 'val2' }], + Count: 2, + ScannedCount: 5, + } as AWS.DynamoDB.Types.QueryOutput); + const dynamodb = new AWS.DynamoDB.DocumentClient(); + const params = { + TableName: 'test-table', + KeyConditionExpression: '#k = :v', + ExpressionAttributeNames: { + '#k': 'key1', + }, + ExpressionAttributeValues: { + ':v': 'val1', + }, + ProjectionExpression: 'id', + ScanIndexForward: true, + ConsistentRead: true, + IndexName: 'name_to_group', + Limit: 10, + Select: 'ALL_ATTRIBUTES', + }; + + dynamodb.query( + params, + (err: AWSError, _data: AWS.DynamoDB.DocumentClient.QueryOutput) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); + expect(err).toBeFalsy(); + done(); + } + ); + }); + + it('should omit DB statement if serializer returns undefined', done => { + instrumentation.disable(); + instrumentation.setConfig({ + dynamoDBStatementSerializer: () => undefined, + }); + instrumentation.enable(); + mockV2AwsSend(responseMockSuccess, { + Items: [{ key1: 'val1' }, { key2: 'val2' }], + Count: 2, + ScannedCount: 5, + } as AWS.DynamoDB.Types.QueryOutput); + const dynamodb = new AWS.DynamoDB.DocumentClient(); + const params = { + TableName: 'test-table', + KeyConditionExpression: '#k = :v', + ExpressionAttributeNames: { + '#k': 'key1', + }, + ExpressionAttributeValues: { + ':v': 'val1', + }, + ProjectionExpression: 'id', + ScanIndexForward: true, + ConsistentRead: true, + IndexName: 'name_to_group', + Limit: 10, + Select: 'ALL_ATTRIBUTES', + }; + + dynamodb.query( + params, + (err: AWSError, _data: AWS.DynamoDB.DocumentClient.QueryOutput) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + + expect(attrs).not.toHaveProperty(SemanticAttributes.DB_STATEMENT); + expect(err).toBeFalsy(); + done(); + } + ); + }); + + it('should provide operation and command input to serializer', done => { + const dynamoDBStatementSerializerSpy = sinon.spy(); + instrumentation.disable(); + instrumentation.setConfig({ + dynamoDBStatementSerializer: dynamoDBStatementSerializerSpy, + }); + instrumentation.enable(); + mockV2AwsSend(responseMockSuccess, { + Items: [{ key1: 'val1' }, { key2: 'val2' }], + Count: 2, + ScannedCount: 5, + } as AWS.DynamoDB.Types.QueryOutput); + const dynamodb = new AWS.DynamoDB.DocumentClient(); + const params = { + TableName: 'test-table', + KeyConditionExpression: '#k = :v', + ExpressionAttributeNames: { + '#k': 'key1', + }, + ExpressionAttributeValues: { + ':v': 'val1', + }, + ProjectionExpression: 'id', + ScanIndexForward: true, + ConsistentRead: true, + IndexName: 'name_to_group', + Limit: 10, + Select: 'ALL_ATTRIBUTES', + }; + + dynamodb.query( + params, + (err: AWSError, _data: AWS.DynamoDB.DocumentClient.QueryOutput) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + + expect(dynamoDBStatementSerializerSpy.callCount).toBe(1); + expect(dynamoDBStatementSerializerSpy.args[0][0]).toStrictEqual( + 'Query' + ); + expect(dynamoDBStatementSerializerSpy.args[0][1]).toStrictEqual({ + ConsistentRead: true, + ExpressionAttributeNames: { + '#k': 'key1', + }, + ExpressionAttributeValues: { + ':v': 'val1', + }, + IndexName: 'name_to_group', + KeyConditionExpression: '#k = :v', + Limit: 10, + ProjectionExpression: 'id', + ScanIndexForward: true, + Select: 'ALL_ATTRIBUTES', + TableName: 'test-table', + }); + + done(); + } + ); + }); + it('should properly execute the db statement serializer for Query operation', done => { mockV2AwsSend(responseMockSuccess, { Items: [{ key1: 'val1' }, { key2: 'val2' }], @@ -898,7 +1093,10 @@ describe('DynamoDB', () => { dynamodb.listTables( params, - (err: AWSError, _data: AWS.DynamoDB.DocumentClient.ListTablesOutput) => { + ( + err: AWSError, + _data: AWS.DynamoDB.DocumentClient.ListTablesOutput + ) => { const spans = getTestSpans(); expect(spans.length).toStrictEqual(1); const attrs = spans[0].attributes; From 648c03437b33b7c2583080672f5ec26a1e18df99 Mon Sep 17 00:00:00 2001 From: Matthew Turner Date: Tue, 14 Nov 2023 21:20:01 +1100 Subject: [PATCH 5/5] chore: run lint:fix --- .../src/aws-sdk.ts | 6 +++--- .../src/services/ServiceExtension.ts | 14 ++++++++++++-- .../src/services/dynamodb.ts | 2 +- .../src/services/lambda.ts | 5 ++++- .../src/services/sns.ts | 5 ++++- 5 files changed, 24 insertions(+), 8 deletions(-) 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 77bdaaba83..f07a0795ac 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts @@ -478,7 +478,7 @@ export class AwsInstrumentation extends InstrumentationBase { const requestMetadata = self.servicesExtensions.requestPreSpanHook( normalizedRequest, self._config, - self._diag, + self._diag ); const span = self._startAwsV3Span(normalizedRequest, requestMetadata); const activeContextWithSpan = trace.setSpan(context.active(), span); @@ -608,7 +608,7 @@ export class AwsInstrumentation extends InstrumentationBase { const requestMetadata = self.servicesExtensions.requestPreSpanHook( normalizedRequest, self._config, - self._diag, + self._diag ); const span = self._startAwsV2Span( this, @@ -651,7 +651,7 @@ export class AwsInstrumentation extends InstrumentationBase { const requestMetadata = self.servicesExtensions.requestPreSpanHook( normalizedRequest, self._config, - self._diag, + self._diag ); const span = self._startAwsV2Span( this, diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts index 606a4ddd17..95f89bdac5 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts @@ -13,7 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { DiagLogger, Span, SpanAttributes, SpanKind, Tracer } from '@opentelemetry/api'; +import { + DiagLogger, + Span, + SpanAttributes, + SpanKind, + Tracer, +} from '@opentelemetry/api'; import { AwsSdkInstrumentationConfig, NormalizedRequest, @@ -30,7 +36,11 @@ export interface RequestMetadata { export interface ServiceExtension { // called before request is sent, and before span is started - requestPreSpanHook: (request: NormalizedRequest, config: AwsSdkInstrumentationConfig, diag: DiagLogger) => RequestMetadata; + requestPreSpanHook: ( + request: NormalizedRequest, + config: AwsSdkInstrumentationConfig, + diag: DiagLogger + ) => RequestMetadata; // called before request is sent, and after span is started requestPostSpanHook?: (request: NormalizedRequest) => void; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts index c285867cd8..871d985118 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts @@ -33,7 +33,7 @@ export class DynamodbServiceExtension implements ServiceExtension { requestPreSpanHook( normalizedRequest: NormalizedRequest, config: AwsSdkInstrumentationConfig, - diag: DiagLogger, + diag: DiagLogger ): RequestMetadata { const spanKind: SpanKind = SpanKind.CLIENT; let spanName: string | undefined; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/lambda.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/lambda.ts index 02ae13b7bf..3254374966 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/lambda.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/lambda.ts @@ -34,7 +34,10 @@ class LambdaCommands { } export class LambdaServiceExtension implements ServiceExtension { - requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata { + requestPreSpanHook( + request: NormalizedRequest, + _config: AwsSdkInstrumentationConfig + ): RequestMetadata { const functionName = this.extractFunctionName(request.commandInput); let spanAttributes: SpanAttributes = {}; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts index 3285839684..07a016ea8a 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts @@ -27,7 +27,10 @@ import { injectPropagationContext } from './MessageAttributes'; import { RequestMetadata, ServiceExtension } from './ServiceExtension'; export class SnsServiceExtension implements ServiceExtension { - requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata { + requestPreSpanHook( + request: NormalizedRequest, + _config: AwsSdkInstrumentationConfig + ): RequestMetadata { let spanKind: SpanKind = SpanKind.CLIENT; let spanName = `SNS ${request.commandName}`; const spanAttributes = {