From a8d00f8824385e2d2ad171fdd67e9bd7af41bbac Mon Sep 17 00:00:00 2001 From: Chris Richards Date: Thu, 10 Feb 2022 10:40:13 +0000 Subject: [PATCH 1/4] feat: allow custom aws sdk service extensions via config (#829) --- .../README.md | 3 +- .../package.json | 10 +- .../src/aws-sdk.ts | 8 +- .../src/index.ts | 1 + .../src/services/ServicesExtensions.ts | 11 +- .../src/services/index.ts | 4 + .../src/types.ts | 13 + .../test/aws-sdk-v3.test.ts | 275 +++++++++++++++++- .../test/test-custom-extensions.ts | 123 ++++++++ 9 files changed, 440 insertions(+), 8 deletions(-) create mode 100644 plugins/node/opentelemetry-instrumentation-aws-sdk/test/test-custom-extensions.ts diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md index b84fb36ee0..3609cf5dce 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)| - +| `customServiceExtensions` | `AwsSdkServiceExtensionDefinition[]` | Allows for the provision of custom service extensions by the end user. | ## Span Attributes Both V2 and V3 instrumentations are collecting the following attributes: @@ -100,6 +100,7 @@ Specific service logic currently implemented for: - [SNS](./docs/sns.md) - DynamoDb +The `customServiceExtensions` configuration parameter allows for users to define their own custom service extensions beyond these built-in ones, or to extend or replace these built-in ones. ## Potential Side Effects The instrumentation is doing best effort to support the trace specification of OpenTelemetry. For SQS, it involves defining new attributes on the `Messages` array, as well as on the manipulated types generated from this array (to set correct trace context for a single SQS message operation). Those properties are defined as [non-enumerable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties) properties, so they have minimum side effect on the app. They will, however, show when using the `Object.getOwnPropertyDescriptors` and `Reflect.ownKeys` functions on SQS `Messages` array and for each `Message` in the array. diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json b/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json index 67c650cc0b..c176642ba8 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json @@ -49,29 +49,31 @@ "dependencies": { "@opentelemetry/core": "^1.0.0", "@opentelemetry/instrumentation": "^0.27.0", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@opentelemetry/propagation-utils": "^0.26.0" + "@opentelemetry/propagation-utils": "^0.26.0", + "@opentelemetry/semantic-conventions": "^1.0.0" }, "devDependencies": { "@aws-sdk/client-dynamodb": "3.37.0", + "@aws-sdk/client-lambda": "^3.50.0", "@aws-sdk/client-s3": "3.37.0", "@aws-sdk/client-sqs": "3.37.0", "@aws-sdk/types": "3.37.0", "@opentelemetry/api": "1.0.1", + "@opentelemetry/contrib-test-utils": "^0.29.0", "@opentelemetry/sdk-trace-base": "1.0.1", + "@types/aws-lambda": "^8.10.92", "@types/mocha": "8.2.3", "@types/node": "16.11.21", "@types/sinon": "10.0.6", "aws-sdk": "2.1008.0", "eslint": "8.7.0", "expect": "27.4.2", + "gts": "3.1.0", "mocha": "7.2.0", "nock": "13.2.1", "nyc": "15.1.0", "rimraf": "3.0.2", "sinon": "13.0.1", - "gts": "3.1.0", - "@opentelemetry/contrib-test-utils": "^0.29.0", "test-all-versions": "5.0.1", "ts-mocha": "8.0.0", "typescript": "4.3.4" 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 5d9eddaf8a..e827ce8d1d 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts @@ -74,7 +74,7 @@ type V2PluginRequest = AWS.Request & { export class AwsInstrumentation extends InstrumentationBase { static readonly component = 'aws-sdk'; protected override _config!: AwsSdkInstrumentationConfig; - private servicesExtensions: ServicesExtensions = new ServicesExtensions(); + private servicesExtensions: ServicesExtensions; constructor(config: AwsSdkInstrumentationConfig = {}) { super( @@ -82,10 +82,16 @@ export class AwsInstrumentation extends InstrumentationBase { VERSION, Object.assign({}, config) ); + this.servicesExtensions = new ServicesExtensions( + config.customServiceExtensions + ); } override setConfig(config: AwsSdkInstrumentationConfig = {}) { this._config = Object.assign({}, config); + this.servicesExtensions = new ServicesExtensions( + this._config.customServiceExtensions + ); } protected init(): InstrumentationModuleDefinition[] { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/index.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/index.ts index 2abc3b4f7a..ad5eeb4318 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/index.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/index.ts @@ -15,3 +15,4 @@ */ export * from './aws-sdk'; export * from './types'; +export * from './services'; 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 6796783013..f29d8eedf0 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts @@ -18,6 +18,7 @@ import { ServiceExtension, RequestMetadata } from './ServiceExtension'; import { SqsServiceExtension } from './sqs'; import { AwsSdkInstrumentationConfig, + AwsSdkServiceExtensionDefinition, NormalizedRequest, NormalizedResponse, } from '../types'; @@ -27,10 +28,18 @@ import { SnsServiceExtension } from './sns'; export class ServicesExtensions implements ServiceExtension { services: Map = new Map(); - constructor() { + constructor(customServiceExtensions?: AwsSdkServiceExtensionDefinition[]) { this.services.set('SQS', new SqsServiceExtension()); this.services.set('SNS', new SnsServiceExtension()); this.services.set('DynamoDB', new DynamodbServiceExtension()); + if (customServiceExtensions !== undefined) { + for (const serviceExtensionDefinition of customServiceExtensions) { + this.services.set( + serviceExtensionDefinition.serviceName, + serviceExtensionDefinition.extension + ); + } + } } requestPreSpanHook(request: NormalizedRequest): RequestMetadata { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/index.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/index.ts index 7a77f3400a..29685405c6 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/index.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/index.ts @@ -14,3 +14,7 @@ * limitations under the License. */ export { ServicesExtensions } from './ServicesExtensions'; +export { RequestMetadata, ServiceExtension } from './ServiceExtension'; +export { SnsServiceExtension } from './sns'; +export { SqsServiceExtension } from './sqs'; +export { DynamodbServiceExtension } from './dynamodb'; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts index 340be8deeb..7de8a8b642 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/types.ts @@ -16,6 +16,7 @@ import { Span } from '@opentelemetry/api'; import { InstrumentationConfig } from '@opentelemetry/instrumentation'; import type * as AWS from 'aws-sdk'; +import { ServiceExtension } from './services/ServiceExtension'; /** * These are normalized request and response, which are used by both sdk v2 and v3. @@ -61,6 +62,10 @@ export interface AwsSdkSqsProcessCustomAttributeFunction { (span: Span, sqsProcessInfo: AwsSdkSqsProcessHookInformation): void; } +export interface AwsSdkServiceExtensionDefinition { + serviceName: string; + extension: ServiceExtension; +} export interface AwsSdkInstrumentationConfig extends InstrumentationConfig { /** hook for adding custom attributes before request is sent to aws */ preRequestHook?: AwsSdkRequestCustomAttributeFunction; @@ -91,4 +96,12 @@ export interface AwsSdkInstrumentationConfig extends InstrumentationConfig { * By default it is off. */ sqsExtractContextPropagationFromPayload?: boolean; + + /** + * Some users will want to be able to leverage the AWS SDK instrumentation to provide instrumentation + * for services not yet catered for, or to instrument already catered for services in different ways. + * Rather than forcing them to implement an instrumentation from scratch this allows them to specify + * custom services extensions to be used alongside the built in ones + */ + customServiceExtensions?: AwsSdkServiceExtensionDefinition[]; } 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 84a14c6c78..9014c36695 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 @@ -32,6 +32,7 @@ import { S3Client, } from '@aws-sdk/client-s3'; import { SQS } from '@aws-sdk/client-sqs'; +import { Lambda, InvocationType } from '@aws-sdk/client-lambda'; // set aws environment variables, so tests in non aws environment are able to run process.env.AWS_ACCESS_KEY_ID = 'testing'; @@ -39,13 +40,24 @@ process.env.AWS_SECRET_ACCESS_KEY = 'testing'; import 'mocha'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; -import { context, SpanStatusCode, trace, Span } from '@opentelemetry/api'; +import { + context, + SpanStatusCode, + trace, + Span, + SpanKind, +} from '@opentelemetry/api'; import { MessagingDestinationKindValues, MessagingOperationValues, SemanticAttributes, } from '@opentelemetry/semantic-conventions'; import { AttributeNames } from '../src/enums'; +import { + LambdaTestCustomServiceExtension, + SqsTestCustomServiceExtension, +} from './test-custom-extensions'; +import { ClientRequest } from 'http'; import * as expect from 'expect'; import * as fs from 'fs'; import * as nock from 'nock'; @@ -274,6 +286,267 @@ describe('instrumentation-aws-sdk-v3', () => { ); }); }); + + describe('custom services extensions', () => { + it('should use any provided custom extensions requestPreSpanHook to add span attributes', async () => { + const lambdaClient = new Lambda({ region }); + instrumentation.disable(); + instrumentation.setConfig({ + suppressInternalInstrumentation: true, + customServiceExtensions: [ + { + serviceName: 'Lambda', + extension: new LambdaTestCustomServiceExtension(), + }, + ], + }); + instrumentation.enable(); + + nock(`https://lambda.${region}.amazonaws.com/`) + .post('/2015-03-31/functions/ot-test-function-name/invocations') + .reply(200, 'null'); + + const params = { + FunctionName: 'ot-test-function-name', + InvocationType: InvocationType.RequestResponse, + Payload: Buffer.from( + JSON.stringify({ + test: 'payload', + }) + ), + }; + await lambdaClient.invoke(params); + expect(getTestSpans().length).toBe(1); + const [span] = getTestSpans(); + + expect(span.attributes[SemanticAttributes.RPC_SYSTEM]).toEqual( + 'aws-api' + ); + expect(span.attributes[SemanticAttributes.RPC_METHOD]).toEqual( + 'Invoke' + ); + expect(span.attributes[SemanticAttributes.RPC_SERVICE]).toEqual( + 'Lambda' + ); + expect(span.attributes[AttributeNames.AWS_REGION]).toEqual(region); + + // custom messaging attributes + expect(span.kind).toEqual(SpanKind.CLIENT); + expect(span.attributes[SemanticAttributes.FAAS_INVOKED_NAME]).toEqual( + 'ot-test-function-name' + ); + expect( + span.attributes[SemanticAttributes.FAAS_INVOKED_PROVIDER] + ).toEqual('aws'); + }); + + it('should use any provided custom extensions requestPostSpanHook to add propagation context', async () => { + const lambdaClient = new Lambda({ region }); + instrumentation.disable(); + instrumentation.setConfig({ + suppressInternalInstrumentation: true, + customServiceExtensions: [ + { + serviceName: 'Lambda', + extension: new LambdaTestCustomServiceExtension(), + }, + ], + }); + instrumentation.enable(); + + let request: + | (ClientRequest & { + headers: Record; + }) + | undefined; + nock(`https://lambda.${region}.amazonaws.com/`) + .post('/2015-03-31/functions/ot-test-function-name/invocations') + .reply(function (uri, requestBody, callback) { + request = this.req; + callback(null, [200, 'null']); + }); + + const params = { + FunctionName: 'ot-test-function-name', + InvocationType: InvocationType.RequestResponse, + Payload: Buffer.from( + JSON.stringify({ + test: 'payload', + }) + ), + }; + await lambdaClient.invoke(params); + expect(getTestSpans().length).toBe(1); + const [span] = getTestSpans(); + + expect(span.attributes[SemanticAttributes.RPC_SYSTEM]).toEqual( + 'aws-api' + ); + expect(span.attributes[SemanticAttributes.RPC_METHOD]).toEqual( + 'Invoke' + ); + expect(span.attributes[SemanticAttributes.RPC_SERVICE]).toEqual( + 'Lambda' + ); + expect(span.attributes[AttributeNames.AWS_REGION]).toEqual(region); + + // Context propagation + expect(request).toBeDefined(); + const requestHeaders = request!.headers; + expect(requestHeaders['x-amz-client-context']).toBeDefined(); + const clientContext = JSON.parse( + Buffer.from( + requestHeaders['x-amz-client-context'], + 'base64' + ).toString() + ) as Record; + expect(clientContext.Custom).toHaveProperty('traceparent'); + }); + + it('should use any provided custom extensions responseHook to add any span attributes from the API response', async () => { + const lambdaClient = new Lambda({ region }); + instrumentation.disable(); + instrumentation.setConfig({ + suppressInternalInstrumentation: true, + customServiceExtensions: [ + { + serviceName: 'Lambda', + extension: new LambdaTestCustomServiceExtension(), + }, + ], + }); + instrumentation.enable(); + + let request: + | (ClientRequest & { + headers: Record; + }) + | undefined; + nock(`https://lambda.${region}.amazonaws.com/`) + .post('/2015-03-31/functions/ot-test-function-name/invocations') + .reply(function (uri, requestBody, callback) { + request = this.req; + callback(null, [ + 200, + 'null', + { + 'x-amz-executed-version': '$LATEST', + 'x-amzn-requestid': '95882c2b-3fd2-485d-ada3-9fcb1ca65459', + }, + ]); + }); + + const params = { + FunctionName: 'ot-test-function-name', + InvocationType: InvocationType.RequestResponse, + Payload: Buffer.from( + JSON.stringify({ + test: 'payload', + }) + ), + }; + await lambdaClient.invoke(params); + expect(getTestSpans().length).toBe(1); + const [span] = getTestSpans(); + + expect(span.attributes[SemanticAttributes.RPC_SYSTEM]).toEqual( + 'aws-api' + ); + expect(span.attributes[SemanticAttributes.RPC_METHOD]).toEqual( + 'Invoke' + ); + expect(span.attributes[SemanticAttributes.RPC_SERVICE]).toEqual( + 'Lambda' + ); + expect(span.attributes[AttributeNames.AWS_REGION]).toEqual(region); + + // Response attributes + expect(span.attributes[SemanticAttributes.FAAS_EXECUTION]).toEqual( + '95882c2b-3fd2-485d-ada3-9fcb1ca65459' + ); + }); + + it('should default to the basic SDK instrumentation if the config is overridden', async () => { + const lambdaClient = new Lambda({ region }); + instrumentation.disable(); + instrumentation.setConfig({ + suppressInternalInstrumentation: true, + }); + instrumentation.enable(); + + nock(`https://lambda.${region}.amazonaws.com/`) + .post('/2015-03-31/functions/ot-test-function-name/invocations') + .reply(200, 'null'); + + const params = { + FunctionName: 'ot-test-function-name', + InvocationType: InvocationType.RequestResponse, + Payload: Buffer.from( + JSON.stringify({ + test: 'payload', + }) + ), + }; + await lambdaClient.invoke(params); + expect(getTestSpans().length).toBe(1); + const [span] = getTestSpans(); + + expect(span.attributes[SemanticAttributes.RPC_SYSTEM]).toEqual( + 'aws-api' + ); + expect(span.attributes[SemanticAttributes.RPC_METHOD]).toEqual( + 'Invoke' + ); + expect(span.attributes[SemanticAttributes.RPC_SERVICE]).toEqual( + 'Lambda' + ); + expect(span.attributes[AttributeNames.AWS_REGION]).toEqual(region); + + // custom messaging attributes should be absent as we've reverted to just adding what the + // default AWS SDK instrumentation understands + expect(span.kind).toEqual(SpanKind.INTERNAL); + expect(span.attributes).not.toHaveProperty( + SemanticAttributes.FAAS_INVOKED_NAME + ); + expect(span.attributes).not.toHaveProperty( + SemanticAttributes.FAAS_INVOKED_PROVIDER + ); + }); + + it('should override a built-in service extension if a custom service extension is provided for the same service', async () => { + const sqsClient = new SQS({ region }); + instrumentation.disable(); + instrumentation.setConfig({ + suppressInternalInstrumentation: true, + customServiceExtensions: [ + { + serviceName: 'SQS', + extension: new SqsTestCustomServiceExtension(), + }, + ], + }); + instrumentation.enable(); + + nock(`https://sqs.${region}.amazonaws.com/`) + .post('/') + .reply( + 200, + fs.readFileSync('./test/mock-responses/sqs-send.xml', 'utf8') + ); + + const params = { + QueueUrl: + 'https://sqs.us-east-1.amazonaws.com/731241200085/otel-demo-aws-sdk', + MessageBody: 'payload example from v3 without batch', + }; + await sqsClient.sendMessage(params); + expect(getTestSpans().length).toBe(1); + const [span] = getTestSpans(); + + // Ensure the span name set by the custom instrumentation is there + expect(span.name).toEqual('custom SQS span'); + }); + }); }); describe('custom service behavior', () => { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/test-custom-extensions.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/test-custom-extensions.ts new file mode 100644 index 0000000000..79a4685c9e --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/test-custom-extensions.ts @@ -0,0 +1,123 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Span, SpanKind, Tracer } from '@opentelemetry/api'; +import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; +import { + AwsSdkInstrumentationConfig, + NormalizedRequest, + NormalizedResponse, + RequestMetadata, + ServiceExtension, + SqsServiceExtension, +} from '../src'; +import { TextMapSetter, context, propagation } from '@opentelemetry/api'; +import type { ClientContext } from 'aws-lambda'; + +// Sample implementation of a custom service extension +export class LambdaTestCustomServiceExtension implements ServiceExtension { + requestPreSpanHook(request: NormalizedRequest): RequestMetadata { + const functionName = this.extractFunctionName(request.commandInput); + + const spanAttributes = { + [SemanticAttributes.FAAS_INVOKED_NAME]: functionName, + [SemanticAttributes.FAAS_INVOKED_PROVIDER]: 'aws', + }; + let spanName: string | undefined; + + switch (request.commandName) { + case 'Invoke': + spanName = `${functionName} invoke`; + break; + } + return { + isIncoming: false, + spanAttributes, + spanKind: SpanKind.CLIENT, + spanName, + }; + } + requestPostSpanHook = (request: NormalizedRequest) => { + switch (request.commandName) { + case 'Invoke': + { + request.commandInput = injectPropagationContext(request.commandInput); + } + break; + } + }; + responseHook( + response: NormalizedResponse, + span: Span, + tracer: Tracer, + config: AwsSdkInstrumentationConfig + ) { + const operation = response.request.commandName; + + if (operation === 'Invoke') { + console.log(response.data); + if (response.data && '$metadata' in response.data) { + span.setAttribute( + SemanticAttributes.FAAS_EXECUTION, + response.data['$metadata'].requestId + ); + } + } + } + + extractFunctionName = (commandInput: Record): string => { + return commandInput?.FunctionName; + }; +} + +class ContextSetter implements TextMapSetter> { + set(carrier: Record, key: string, value: string): void { + const parsedClientContext: ClientContext = JSON.parse( + carrier.ClientContext !== undefined + ? Buffer.from(carrier.ClientContext, 'base64').toString('utf8') + : '{"Custom":{}}' + ); + const updatedPayload = { + ...parsedClientContext, + Custom: { + ...parsedClientContext.Custom, + [key]: value, + }, + }; + const encodedPayload = Buffer.from(JSON.stringify(updatedPayload)).toString( + 'base64' + ); + carrier.ClientContext = encodedPayload; + } +} +const contextSetter = new ContextSetter(); + +const injectPropagationContext = ( + invocationRequest: Record +): Record => { + propagation.inject(context.active(), invocationRequest, contextSetter); + return invocationRequest; +}; + +export class SqsTestCustomServiceExtension extends SqsServiceExtension { + override requestPreSpanHook(request: NormalizedRequest): RequestMetadata { + return { + isIncoming: true, + spanAttributes: {}, + spanKind: SpanKind.INTERNAL, + spanName: 'custom SQS span', + }; + } +} From 8500bcf7d166cbc0176c1743275f4961db865c75 Mon Sep 17 00:00:00 2001 From: Chris Richards Date: Thu, 10 Feb 2022 10:52:57 +0000 Subject: [PATCH 2/4] fix: fix markdown lint error --- plugins/node/opentelemetry-instrumentation-aws-sdk/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md index 3609cf5dce..bcd75c8257 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md @@ -50,6 +50,7 @@ aws-sdk instrumentation has few options available to choose from. You can set th | `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)| | `customServiceExtensions` | `AwsSdkServiceExtensionDefinition[]` | Allows for the provision of custom service extensions by the end user. | + ## Span Attributes Both V2 and V3 instrumentations are collecting the following attributes: From dfeadd6edad491b5a7e06eacc59f72bfe322f76f Mon Sep 17 00:00:00 2001 From: Chris Richards Date: Thu, 10 Feb 2022 10:57:33 +0000 Subject: [PATCH 3/4] fix: fix second markdown lint error --- plugins/node/opentelemetry-instrumentation-aws-sdk/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md index bcd75c8257..13c97fab3e 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/README.md @@ -102,6 +102,7 @@ Specific service logic currently implemented for: - DynamoDb The `customServiceExtensions` configuration parameter allows for users to define their own custom service extensions beyond these built-in ones, or to extend or replace these built-in ones. + ## Potential Side Effects The instrumentation is doing best effort to support the trace specification of OpenTelemetry. For SQS, it involves defining new attributes on the `Messages` array, as well as on the manipulated types generated from this array (to set correct trace context for a single SQS message operation). Those properties are defined as [non-enumerable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties) properties, so they have minimum side effect on the app. They will, however, show when using the `Object.getOwnPropertyDescriptors` and `Reflect.ownKeys` functions on SQS `Messages` array and for each `Message` in the array. From dc1a360eab2344eed4be3edbcdc784b50fd0f46f Mon Sep 17 00:00:00 2001 From: Chris Richards Date: Thu, 10 Feb 2022 11:14:51 +0000 Subject: [PATCH 4/4] fix: fix the compile error not surfaced by test command --- .../test/aws-sdk-v3.test.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) 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 9014c36695..411452274c 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 @@ -417,15 +417,9 @@ describe('instrumentation-aws-sdk-v3', () => { }); instrumentation.enable(); - let request: - | (ClientRequest & { - headers: Record; - }) - | undefined; nock(`https://lambda.${region}.amazonaws.com/`) .post('/2015-03-31/functions/ot-test-function-name/invocations') - .reply(function (uri, requestBody, callback) { - request = this.req; + .reply((uri, requestBody, callback) => { callback(null, [ 200, 'null',