From ec864756eb243a752ef39de3bea2481f3d883cae Mon Sep 17 00:00:00 2001 From: jjllee Date: Mon, 29 Jul 2024 23:25:47 -0700 Subject: [PATCH 1/7] add s3 and kinesis service extensions for aws-sdk instrumentation --- .../package.json | 1 + .../src/services/ServicesExtensions.ts | 4 + .../src/services/kinesis.ts | 59 ++++++++++++++ .../src/services/s3.ts | 59 ++++++++++++++ .../src/utils.ts | 6 ++ .../test/kinesis.test.ts | 81 +++++++++++++++++++ .../test/s3.test.ts | 76 +++++++++++++++++ 7 files changed, 286 insertions(+) create mode 100644 plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/kinesis.ts create mode 100644 plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/s3.ts create mode 100644 plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts create mode 100644 plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json b/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json index 30925579de..b858c8c264 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json @@ -52,6 +52,7 @@ }, "devDependencies": { "@aws-sdk/client-dynamodb": "3.85.0", + "@aws-sdk/client-kinesis": "3.85.0", "@aws-sdk/client-lambda": "3.85.0", "@aws-sdk/client-s3": "3.85.0", "@aws-sdk/client-sns": "3.85.0", 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 cb739a2011..609ed7f7a0 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts @@ -24,6 +24,8 @@ import { import { DynamodbServiceExtension } from './dynamodb'; import { SnsServiceExtension } from './sns'; import { LambdaServiceExtension } from './lambda'; +import { S3ServiceExtension } from './s3'; +import { KinesisServiceExtension } from './kinesis'; export class ServicesExtensions implements ServiceExtension { services: Map = new Map(); @@ -33,6 +35,8 @@ export class ServicesExtensions implements ServiceExtension { this.services.set('SNS', new SnsServiceExtension()); this.services.set('DynamoDB', new DynamodbServiceExtension()); this.services.set('Lambda', new LambdaServiceExtension()); + this.services.set('S3', new S3ServiceExtension()); + this.services.set('Kinesis', new KinesisServiceExtension()); } requestPreSpanHook( diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/kinesis.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/kinesis.ts new file mode 100644 index 0000000000..7a6df4f5c3 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/kinesis.ts @@ -0,0 +1,59 @@ +/* + * 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 { Attributes, Span, SpanKind, Tracer } from '@opentelemetry/api'; +import { + AwsSdkInstrumentationConfig, + NormalizedRequest, + NormalizedResponse, +} from '../types'; +import { _AWS_KINESIS_STREAM_NAME } from '../utils'; +import { RequestMetadata, ServiceExtension } from './ServiceExtension'; + +export class KinesisServiceExtension implements ServiceExtension { + requestPreSpanHook( + request: NormalizedRequest, + _config: AwsSdkInstrumentationConfig + ): RequestMetadata { + const streamName = request.commandInput.StreamName; + + const spanKind: SpanKind = SpanKind.CLIENT; + let spanName: string | undefined; + + const spanAttributes: Attributes = {}; + + if (streamName) { + spanAttributes[_AWS_KINESIS_STREAM_NAME] = streamName; + } + + const isIncoming = false; + + return { + isIncoming, + spanAttributes, + spanKind, + spanName, + }; + } + + requestPostSpanHook = (request: NormalizedRequest) => {}; + + responseHook = ( + response: NormalizedResponse, + span: Span, + tracer: Tracer, + config: AwsSdkInstrumentationConfig + ) => {}; +} diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/s3.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/s3.ts new file mode 100644 index 0000000000..5c54f74924 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/s3.ts @@ -0,0 +1,59 @@ +/* + * 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 { Attributes, Span, SpanKind, Tracer } from '@opentelemetry/api'; +import { + AwsSdkInstrumentationConfig, + NormalizedRequest, + NormalizedResponse, +} from '../types'; +import { _AWS_S3_BUCKET } from '../utils'; +import { RequestMetadata, ServiceExtension } from './ServiceExtension'; + +export class S3ServiceExtension implements ServiceExtension { + requestPreSpanHook( + request: NormalizedRequest, + _config: AwsSdkInstrumentationConfig + ): RequestMetadata { + const bucketName = request.commandInput.Bucket; + + const spanKind: SpanKind = SpanKind.CLIENT; + let spanName: string | undefined; + + const spanAttributes: Attributes = {}; + + if (bucketName) { + spanAttributes[_AWS_S3_BUCKET] = bucketName; + } + + const isIncoming = false; + + return { + isIncoming, + spanAttributes, + spanKind, + spanName, + }; + } + + requestPostSpanHook = (request: NormalizedRequest) => {}; + + responseHook = ( + response: NormalizedResponse, + span: Span, + tracer: Tracer, + config: AwsSdkInstrumentationConfig + ) => {}; +} diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/utils.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/utils.ts index e3d0db6bdb..4a34aeddde 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/utils.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/utils.ts @@ -22,6 +22,12 @@ import { } from '@opentelemetry/semantic-conventions'; import { AttributeNames } from './enums'; +// TODO: Add these semantic attributes to: +// - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts +// For S3, see specification: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/object-stores/s3.md +export const _AWS_S3_BUCKET = 'aws.s3.bucket'; +export const _AWS_KINESIS_STREAM_NAME = 'aws.kinesis.stream.name'; + const toPascalCase = (str: string): string => typeof str === 'string' ? str.charAt(0).toUpperCase() + str.slice(1) : str; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts new file mode 100644 index 0000000000..0fc7ed2b19 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts @@ -0,0 +1,81 @@ +/* + * 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 { + getTestSpans, + registerInstrumentationTesting, +} from '@opentelemetry/contrib-test-utils'; +import { AwsInstrumentation } from '../src'; +registerInstrumentationTesting(new AwsInstrumentation()); + +import * as AWS from 'aws-sdk'; +import { AWSError } from 'aws-sdk'; +import * as nock from 'nock'; + +import { SpanKind } from '@opentelemetry/api'; +import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; +import { expect } from 'expect'; +import { _AWS_KINESIS_STREAM_NAME } from '../src/utils'; + +const region = 'us-east-1'; + +describe('Kinesis', () => { + let kinesis: AWS.Kinesis; + beforeEach(() => { + AWS.config.credentials = { + accessKeyId: 'test key id', + expired: false, + expireTime: new Date(), + secretAccessKey: 'test acc key', + sessionToken: 'test token', + }; + }); + + describe('CreateStream', () => { + it('adds Stream Name', async () => { + kinesis = new AWS.Kinesis({ region: region }); + const dummyStreamName = 'dummy-stream-name'; + + nock(`https://kinesis.${region}.amazonaws.com`) + .get('/') + .reply(200, 'null'); + + await kinesis + .createStream( + { + StreamName: dummyStreamName, + ShardCount: 3, + }, + (err: AWSError) => { + expect(err).toBeFalsy(); + } + ) + .promise(); + + const testSpans = getTestSpans(); + console.log(testSpans.length); + const creationSpans = testSpans.filter((s: ReadableSpan) => { + return s.name === 'Kinesis.CreateStream'; + }); + expect(creationSpans.length).toBe(1); + const publishSpan = creationSpans[0]; + expect(publishSpan.attributes[_AWS_KINESIS_STREAM_NAME]).toBe( + dummyStreamName + ); + expect(publishSpan.kind).toBe(SpanKind.CLIENT); + }); + }); +}); diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts new file mode 100644 index 0000000000..b45aac2f65 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts @@ -0,0 +1,76 @@ +/* + * 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 { + getTestSpans, + registerInstrumentationTesting, +} from '@opentelemetry/contrib-test-utils'; +import { AwsInstrumentation } from '../src'; +registerInstrumentationTesting(new AwsInstrumentation()); + +import * as AWS from 'aws-sdk'; +import { AWSError } from 'aws-sdk'; +import * as nock from 'nock'; + +import { SpanKind } from '@opentelemetry/api'; +import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; +import { expect } from 'expect'; +import { _AWS_S3_BUCKET } from '../src/utils'; + +const region = 'us-east-1'; + +describe('S3', () => { + let s3: AWS.S3; + beforeEach(() => { + AWS.config.credentials = { + accessKeyId: 'test key id', + expired: false, + expireTime: new Date(), + secretAccessKey: 'test acc key', + sessionToken: 'test token', + }; + }); + + describe('ListObjects', () => { + it('adds bucket Name', async () => { + s3 = new AWS.S3({ region: region }); + const dummyBucketName = 'dummy-bucket-name'; + + nock(`https://s3.${region}.amazonaws.com`).get('/').reply(200, 'null'); + + await s3 + .listObjects( + { + Bucket: dummyBucketName, + }, + (err: AWSError) => { + expect(err).toBeFalsy(); + } + ) + .promise(); + + const testSpans = getTestSpans(); + console.log(testSpans.length); + const creationSpans = testSpans.filter((s: ReadableSpan) => { + return s.name === 'S3.ListObjects'; + }); + expect(creationSpans.length).toBe(1); + const publishSpan = creationSpans[0]; + expect(publishSpan.attributes[_AWS_S3_BUCKET]).toBe(dummyBucketName); + expect(publishSpan.kind).toBe(SpanKind.CLIENT); + }); + }); +}); From b74f29d5fc87e6600ecf6877cd35dae119f7138a Mon Sep 17 00:00:00 2001 From: jjllee Date: Tue, 30 Jul 2024 17:12:35 -0700 Subject: [PATCH 2/7] npm install -> add updated package-lock.json --- package-lock.json | 96 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/package-lock.json b/package-lock.json index 29c9747eef..c37653e5fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1768,6 +1768,55 @@ "node": ">=12.0.0" } }, + "node_modules/@aws-sdk/client-kinesis": { + "version": "3.85.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kinesis/-/client-kinesis-3.85.0.tgz", + "integrity": "sha512-TlBYyNCkNZqnarpReaYCJTHQeVpjb6XpVcpoznsPnRpPjcm57JVhuErpKjU6tOKmtAl0uKrmJsjupizgQwFMIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/client-sts": "3.85.0", + "@aws-sdk/config-resolver": "3.80.0", + "@aws-sdk/credential-provider-node": "3.85.0", + "@aws-sdk/eventstream-serde-browser": "3.78.0", + "@aws-sdk/eventstream-serde-config-resolver": "3.78.0", + "@aws-sdk/eventstream-serde-node": "3.78.0", + "@aws-sdk/fetch-http-handler": "3.78.0", + "@aws-sdk/hash-node": "3.78.0", + "@aws-sdk/invalid-dependency": "3.78.0", + "@aws-sdk/middleware-content-length": "3.78.0", + "@aws-sdk/middleware-host-header": "3.78.0", + "@aws-sdk/middleware-logger": "3.78.0", + "@aws-sdk/middleware-retry": "3.80.0", + "@aws-sdk/middleware-serde": "3.78.0", + "@aws-sdk/middleware-signing": "3.78.0", + "@aws-sdk/middleware-stack": "3.78.0", + "@aws-sdk/middleware-user-agent": "3.78.0", + "@aws-sdk/node-config-provider": "3.80.0", + "@aws-sdk/node-http-handler": "3.82.0", + "@aws-sdk/protocol-http": "3.78.0", + "@aws-sdk/smithy-client": "3.85.0", + "@aws-sdk/types": "3.78.0", + "@aws-sdk/url-parser": "3.78.0", + "@aws-sdk/util-base64-browser": "3.58.0", + "@aws-sdk/util-base64-node": "3.55.0", + "@aws-sdk/util-body-length-browser": "3.55.0", + "@aws-sdk/util-body-length-node": "3.55.0", + "@aws-sdk/util-defaults-mode-browser": "3.85.0", + "@aws-sdk/util-defaults-mode-node": "3.85.0", + "@aws-sdk/util-user-agent-browser": "3.78.0", + "@aws-sdk/util-user-agent-node": "3.80.0", + "@aws-sdk/util-utf8-browser": "3.55.0", + "@aws-sdk/util-utf8-node": "3.55.0", + "@aws-sdk/util-waiter": "3.78.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@aws-sdk/client-lambda": { "version": "3.85.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.85.0.tgz", @@ -38459,6 +38508,7 @@ }, "devDependencies": { "@aws-sdk/client-dynamodb": "3.85.0", + "@aws-sdk/client-kinesis": "3.85.0", "@aws-sdk/client-lambda": "3.85.0", "@aws-sdk/client-s3": "3.85.0", "@aws-sdk/client-sns": "3.85.0", @@ -43515,6 +43565,51 @@ "uuid": "^8.3.2" } }, + "@aws-sdk/client-kinesis": { + "version": "3.85.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kinesis/-/client-kinesis-3.85.0.tgz", + "integrity": "sha512-TlBYyNCkNZqnarpReaYCJTHQeVpjb6XpVcpoznsPnRpPjcm57JVhuErpKjU6tOKmtAl0uKrmJsjupizgQwFMIA==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/client-sts": "3.85.0", + "@aws-sdk/config-resolver": "3.80.0", + "@aws-sdk/credential-provider-node": "3.85.0", + "@aws-sdk/eventstream-serde-browser": "3.78.0", + "@aws-sdk/eventstream-serde-config-resolver": "3.78.0", + "@aws-sdk/eventstream-serde-node": "3.78.0", + "@aws-sdk/fetch-http-handler": "3.78.0", + "@aws-sdk/hash-node": "3.78.0", + "@aws-sdk/invalid-dependency": "3.78.0", + "@aws-sdk/middleware-content-length": "3.78.0", + "@aws-sdk/middleware-host-header": "3.78.0", + "@aws-sdk/middleware-logger": "3.78.0", + "@aws-sdk/middleware-retry": "3.80.0", + "@aws-sdk/middleware-serde": "3.78.0", + "@aws-sdk/middleware-signing": "3.78.0", + "@aws-sdk/middleware-stack": "3.78.0", + "@aws-sdk/middleware-user-agent": "3.78.0", + "@aws-sdk/node-config-provider": "3.80.0", + "@aws-sdk/node-http-handler": "3.82.0", + "@aws-sdk/protocol-http": "3.78.0", + "@aws-sdk/smithy-client": "3.85.0", + "@aws-sdk/types": "3.78.0", + "@aws-sdk/url-parser": "3.78.0", + "@aws-sdk/util-base64-browser": "3.58.0", + "@aws-sdk/util-base64-node": "3.55.0", + "@aws-sdk/util-body-length-browser": "3.55.0", + "@aws-sdk/util-body-length-node": "3.55.0", + "@aws-sdk/util-defaults-mode-browser": "3.85.0", + "@aws-sdk/util-defaults-mode-node": "3.85.0", + "@aws-sdk/util-user-agent-browser": "3.78.0", + "@aws-sdk/util-user-agent-node": "3.80.0", + "@aws-sdk/util-utf8-browser": "3.55.0", + "@aws-sdk/util-utf8-node": "3.55.0", + "@aws-sdk/util-waiter": "3.78.0", + "tslib": "^2.3.1" + } + }, "@aws-sdk/client-lambda": { "version": "3.85.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.85.0.tgz", @@ -51617,6 +51712,7 @@ "version": "file:plugins/node/opentelemetry-instrumentation-aws-sdk", "requires": { "@aws-sdk/client-dynamodb": "3.85.0", + "@aws-sdk/client-kinesis": "3.85.0", "@aws-sdk/client-lambda": "3.85.0", "@aws-sdk/client-s3": "3.85.0", "@aws-sdk/client-sns": "3.85.0", From f3b9422fefedeb1571534e656b04cc748cd1b1f7 Mon Sep 17 00:00:00 2001 From: jjllee Date: Tue, 30 Jul 2024 17:20:01 -0700 Subject: [PATCH 3/7] update variable names --- .../test/kinesis.test.ts | 7 +++---- .../test/s3.test.ts | 11 +++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts index 0fc7ed2b19..3a025ad68b 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts @@ -66,16 +66,15 @@ describe('Kinesis', () => { .promise(); const testSpans = getTestSpans(); - console.log(testSpans.length); const creationSpans = testSpans.filter((s: ReadableSpan) => { return s.name === 'Kinesis.CreateStream'; }); expect(creationSpans.length).toBe(1); - const publishSpan = creationSpans[0]; - expect(publishSpan.attributes[_AWS_KINESIS_STREAM_NAME]).toBe( + const creationSpan = creationSpans[0]; + expect(creationSpan.attributes[_AWS_KINESIS_STREAM_NAME]).toBe( dummyStreamName ); - expect(publishSpan.kind).toBe(SpanKind.CLIENT); + expect(creationSpan.kind).toBe(SpanKind.CLIENT); }); }); }); diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts index b45aac2f65..edfdcda2f6 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts @@ -63,14 +63,13 @@ describe('S3', () => { .promise(); const testSpans = getTestSpans(); - console.log(testSpans.length); - const creationSpans = testSpans.filter((s: ReadableSpan) => { + const listObjectsSpans = testSpans.filter((s: ReadableSpan) => { return s.name === 'S3.ListObjects'; }); - expect(creationSpans.length).toBe(1); - const publishSpan = creationSpans[0]; - expect(publishSpan.attributes[_AWS_S3_BUCKET]).toBe(dummyBucketName); - expect(publishSpan.kind).toBe(SpanKind.CLIENT); + expect(listObjectsSpans.length).toBe(1); + const listObjectsSpan = listObjectsSpans[0]; + expect(listObjectsSpan.attributes[_AWS_S3_BUCKET]).toBe(dummyBucketName); + expect(listObjectsSpan.kind).toBe(SpanKind.CLIENT); }); }); }); From ce592e557bd0d3442d6d104a6dd00727a948c140 Mon Sep 17 00:00:00 2001 From: jjllee Date: Thu, 15 Aug 2024 09:12:06 -0700 Subject: [PATCH 4/7] address comments --- .../src/enums.ts | 6 ++ .../src/services/kinesis.ts | 27 ++------ .../src/services/s3.ts | 27 ++------ .../src/utils.ts | 8 +-- .../test/kinesis.test.ts | 64 +++++++++++++++---- .../test/s3.test.ts | 49 +++++++++++++- 6 files changed, 115 insertions(+), 66 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/enums.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/enums.ts index c3a36dcb12..764bd173c7 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/enums.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/enums.ts @@ -22,4 +22,10 @@ export enum AttributeNames { AWS_REQUEST_ID = 'aws.request.id', AWS_REQUEST_EXTENDED_ID = 'aws.request.extended_id', AWS_SIGNATURE_VERSION = 'aws.signature.version', + + // TODO: Add these semantic attributes to: + // - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts + // For S3, see specification: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/object-stores/s3.md + AWS_S3_BUCKET = 'aws.s3.bucket', + AWS_KINESIS_STREAM_NAME = 'aws.kinesis.stream.name', } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/kinesis.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/kinesis.ts index 7a6df4f5c3..76ecdf805c 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/kinesis.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/kinesis.ts @@ -13,13 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Attributes, Span, SpanKind, Tracer } from '@opentelemetry/api'; -import { - AwsSdkInstrumentationConfig, - NormalizedRequest, - NormalizedResponse, -} from '../types'; -import { _AWS_KINESIS_STREAM_NAME } from '../utils'; +import { Attributes, SpanKind } from '@opentelemetry/api'; +import { AttributeNames } from '../enums'; +import { AwsSdkInstrumentationConfig, NormalizedRequest } from '../types'; import { RequestMetadata, ServiceExtension } from './ServiceExtension'; export class KinesisServiceExtension implements ServiceExtension { @@ -27,15 +23,12 @@ export class KinesisServiceExtension implements ServiceExtension { request: NormalizedRequest, _config: AwsSdkInstrumentationConfig ): RequestMetadata { - const streamName = request.commandInput.StreamName; - + const streamName = request.commandInput?.StreamName; const spanKind: SpanKind = SpanKind.CLIENT; - let spanName: string | undefined; - const spanAttributes: Attributes = {}; if (streamName) { - spanAttributes[_AWS_KINESIS_STREAM_NAME] = streamName; + spanAttributes[AttributeNames.AWS_KINESIS_STREAM_NAME] = streamName; } const isIncoming = false; @@ -44,16 +37,6 @@ export class KinesisServiceExtension implements ServiceExtension { isIncoming, spanAttributes, spanKind, - spanName, }; } - - requestPostSpanHook = (request: NormalizedRequest) => {}; - - responseHook = ( - response: NormalizedResponse, - span: Span, - tracer: Tracer, - config: AwsSdkInstrumentationConfig - ) => {}; } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/s3.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/s3.ts index 5c54f74924..5bf0830e11 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/s3.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/s3.ts @@ -13,13 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Attributes, Span, SpanKind, Tracer } from '@opentelemetry/api'; -import { - AwsSdkInstrumentationConfig, - NormalizedRequest, - NormalizedResponse, -} from '../types'; -import { _AWS_S3_BUCKET } from '../utils'; +import { Attributes, SpanKind } from '@opentelemetry/api'; +import { AttributeNames } from '../enums'; +import { AwsSdkInstrumentationConfig, NormalizedRequest } from '../types'; import { RequestMetadata, ServiceExtension } from './ServiceExtension'; export class S3ServiceExtension implements ServiceExtension { @@ -27,15 +23,12 @@ export class S3ServiceExtension implements ServiceExtension { request: NormalizedRequest, _config: AwsSdkInstrumentationConfig ): RequestMetadata { - const bucketName = request.commandInput.Bucket; - + const bucketName = request.commandInput?.Bucket; const spanKind: SpanKind = SpanKind.CLIENT; - let spanName: string | undefined; - const spanAttributes: Attributes = {}; if (bucketName) { - spanAttributes[_AWS_S3_BUCKET] = bucketName; + spanAttributes[AttributeNames.AWS_S3_BUCKET] = bucketName; } const isIncoming = false; @@ -44,16 +37,6 @@ export class S3ServiceExtension implements ServiceExtension { isIncoming, spanAttributes, spanKind, - spanName, }; } - - requestPostSpanHook = (request: NormalizedRequest) => {}; - - responseHook = ( - response: NormalizedResponse, - span: Span, - tracer: Tracer, - config: AwsSdkInstrumentationConfig - ) => {}; } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/utils.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/utils.ts index 4a34aeddde..cb8aaa6591 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/utils.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/utils.ts @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { NormalizedRequest } from './types'; import { Attributes, Context, context } from '@opentelemetry/api'; import { SEMATTRS_RPC_METHOD, @@ -21,12 +20,7 @@ import { SEMATTRS_RPC_SYSTEM, } from '@opentelemetry/semantic-conventions'; import { AttributeNames } from './enums'; - -// TODO: Add these semantic attributes to: -// - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts -// For S3, see specification: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/object-stores/s3.md -export const _AWS_S3_BUCKET = 'aws.s3.bucket'; -export const _AWS_KINESIS_STREAM_NAME = 'aws.kinesis.stream.name'; +import { NormalizedRequest } from './types'; const toPascalCase = (str: string): string => typeof str === 'string' ? str.charAt(0).toUpperCase() + str.slice(1) : str; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts index 3a025ad68b..626b811069 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts @@ -19,8 +19,10 @@ import { registerInstrumentationTesting, } from '@opentelemetry/contrib-test-utils'; import { AwsInstrumentation } from '../src'; +import { AttributeNames } from '../src/enums'; registerInstrumentationTesting(new AwsInstrumentation()); +import { Kinesis } from '@aws-sdk/client-kinesis'; import * as AWS from 'aws-sdk'; import { AWSError } from 'aws-sdk'; import * as nock from 'nock'; @@ -28,11 +30,10 @@ import * as nock from 'nock'; import { SpanKind } from '@opentelemetry/api'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import { expect } from 'expect'; -import { _AWS_KINESIS_STREAM_NAME } from '../src/utils'; const region = 'us-east-1'; -describe('Kinesis', () => { +describe('Kinesis - v2', () => { let kinesis: AWS.Kinesis; beforeEach(() => { AWS.config.credentials = { @@ -44,7 +45,7 @@ describe('Kinesis', () => { }; }); - describe('CreateStream', () => { + describe('DescribeStream', () => { it('adds Stream Name', async () => { kinesis = new AWS.Kinesis({ region: region }); const dummyStreamName = 'dummy-stream-name'; @@ -54,10 +55,9 @@ describe('Kinesis', () => { .reply(200, 'null'); await kinesis - .createStream( + .describeStream( { StreamName: dummyStreamName, - ShardCount: 3, }, (err: AWSError) => { expect(err).toBeFalsy(); @@ -66,15 +66,55 @@ describe('Kinesis', () => { .promise(); const testSpans = getTestSpans(); - const creationSpans = testSpans.filter((s: ReadableSpan) => { - return s.name === 'Kinesis.CreateStream'; + const describeSpans = testSpans.filter((s: ReadableSpan) => { + return s.name === 'Kinesis.DescribeStream'; }); - expect(creationSpans.length).toBe(1); - const creationSpan = creationSpans[0]; - expect(creationSpan.attributes[_AWS_KINESIS_STREAM_NAME]).toBe( - dummyStreamName + expect(describeSpans.length).toBe(1); + const describeSpan = describeSpans[0]; + expect( + describeSpan.attributes[AttributeNames.AWS_KINESIS_STREAM_NAME] + ).toBe(dummyStreamName); + expect(describeSpan.kind).toBe(SpanKind.CLIENT); + }); + }); +}); + +describe('Kinesis - v3', () => { + let kinesis: Kinesis; + beforeEach(() => { + kinesis = new Kinesis({ + region: region, + credentials: { + accessKeyId: 'abcde', + secretAccessKey: 'abcde', + }, + }); + }); + + describe('DescribeStream', () => { + it('adds Stream Name', async () => { + const dummyStreamName = 'dummy-stream-name'; + + nock(`https://kinesis.${region}.amazonaws.com/`).post('/').reply(200, {}); + + await kinesis + .describeStream({ + StreamName: dummyStreamName, + }) + .catch((err: any) => {}); + + const testSpans: ReadableSpan[] = getTestSpans(); + const describeSpans: ReadableSpan[] = testSpans.filter( + (s: ReadableSpan) => { + return s.name === 'Kinesis.DescribeStream'; + } ); - expect(creationSpan.kind).toBe(SpanKind.CLIENT); + expect(describeSpans.length).toBe(1); + const describeSpan = describeSpans[0]; + expect( + describeSpan.attributes[AttributeNames.AWS_KINESIS_STREAM_NAME] + ).toBe(dummyStreamName); + expect(describeSpan.kind).toBe(SpanKind.CLIENT); }); }); }); diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts index edfdcda2f6..dc73c1b22b 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts @@ -19,8 +19,10 @@ import { registerInstrumentationTesting, } from '@opentelemetry/contrib-test-utils'; import { AwsInstrumentation } from '../src'; +import { AttributeNames } from '../src/enums'; registerInstrumentationTesting(new AwsInstrumentation()); +import { S3 } from '@aws-sdk/client-s3'; import * as AWS from 'aws-sdk'; import { AWSError } from 'aws-sdk'; import * as nock from 'nock'; @@ -28,11 +30,10 @@ import * as nock from 'nock'; import { SpanKind } from '@opentelemetry/api'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import { expect } from 'expect'; -import { _AWS_S3_BUCKET } from '../src/utils'; const region = 'us-east-1'; -describe('S3', () => { +describe('S3 - v2', () => { let s3: AWS.S3; beforeEach(() => { AWS.config.credentials = { @@ -68,7 +69,49 @@ describe('S3', () => { }); expect(listObjectsSpans.length).toBe(1); const listObjectsSpan = listObjectsSpans[0]; - expect(listObjectsSpan.attributes[_AWS_S3_BUCKET]).toBe(dummyBucketName); + expect(listObjectsSpan.attributes[AttributeNames.AWS_S3_BUCKET]).toBe( + dummyBucketName + ); + expect(listObjectsSpan.kind).toBe(SpanKind.CLIENT); + }); + }); +}); + +describe('S3 - v3', () => { + let s3: S3; + beforeEach(() => { + s3 = new S3({ + region: region, + credentials: { + accessKeyId: 'abcde', + secretAccessKey: 'abcde', + }, + }); + }); + + describe('ListObjects', () => { + it('adds bucket Name', async () => { + const dummyBucketName = 'dummy-bucket-name'; + + nock(`https://s3.${region}.amazonaws.com/`).post('/').reply(200, 'null'); + + await s3 + .listObjects({ + Bucket: dummyBucketName, + }) + .catch((err: any) => {}); + + const testSpans: ReadableSpan[] = getTestSpans(); + const listObjectsSpans: ReadableSpan[] = testSpans.filter( + (s: ReadableSpan) => { + return s.name === 'S3.ListObjects'; + } + ); + expect(listObjectsSpans.length).toBe(1); + const listObjectsSpan = listObjectsSpans[0]; + expect(listObjectsSpan.attributes[AttributeNames.AWS_S3_BUCKET]).toBe( + dummyBucketName + ); expect(listObjectsSpan.kind).toBe(SpanKind.CLIENT); }); }); From ed94e6c82a053a61d1812868af5bb3d8b354e599 Mon Sep 17 00:00:00 2001 From: jjllee Date: Thu, 15 Aug 2024 11:36:22 -0700 Subject: [PATCH 5/7] fix tests --- .../test/aws-sdk-v3.test.ts | 12 ++++++ .../test/kinesis.test.ts | 27 +++++-------- .../test/s3.test.ts | 38 +++++++++---------- 3 files changed, 38 insertions(+), 39 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 0e3a752c1b..29a1f6bded 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 @@ -84,6 +84,9 @@ describe('instrumentation-aws-sdk-v3', () => { expect(span.attributes[SEMATTRS_RPC_SYSTEM]).toEqual('aws-api'); expect(span.attributes[SEMATTRS_RPC_METHOD]).toEqual('PutObject'); expect(span.attributes[SEMATTRS_RPC_SERVICE]).toEqual('S3'); + expect(span.attributes[AttributeNames.AWS_S3_BUCKET]).toEqual( + 'ot-demo-test' + ); expect(span.attributes[AttributeNames.AWS_REGION]).toEqual(region); expect(span.name).toEqual('S3.PutObject'); expect(span.kind).toEqual(SpanKind.CLIENT); @@ -108,6 +111,9 @@ describe('instrumentation-aws-sdk-v3', () => { expect(span.attributes[SEMATTRS_RPC_SYSTEM]).toEqual('aws-api'); expect(span.attributes[SEMATTRS_RPC_METHOD]).toEqual('PutObject'); expect(span.attributes[SEMATTRS_RPC_SERVICE]).toEqual('S3'); + expect(span.attributes[AttributeNames.AWS_S3_BUCKET]).toEqual( + 'ot-demo-test' + ); expect(span.attributes[AttributeNames.AWS_REGION]).toEqual(region); expect(span.name).toEqual('S3.PutObject'); expect(span.attributes[SEMATTRS_HTTP_STATUS_CODE]).toEqual(200); @@ -134,6 +140,9 @@ describe('instrumentation-aws-sdk-v3', () => { expect(span.attributes[SEMATTRS_RPC_SYSTEM]).toEqual('aws-api'); expect(span.attributes[SEMATTRS_RPC_METHOD]).toEqual('PutObject'); expect(span.attributes[SEMATTRS_RPC_SERVICE]).toEqual('S3'); + expect(span.attributes[AttributeNames.AWS_S3_BUCKET]).toEqual( + 'ot-demo-test' + ); expect(span.attributes[AttributeNames.AWS_REGION]).toEqual(region); expect(span.name).toEqual('S3.PutObject'); expect(span.attributes[SEMATTRS_HTTP_STATUS_CODE]).toEqual(200); @@ -167,6 +176,9 @@ describe('instrumentation-aws-sdk-v3', () => { expect(span.attributes[SEMATTRS_RPC_SYSTEM]).toEqual('aws-api'); expect(span.attributes[SEMATTRS_RPC_METHOD]).toEqual('PutObject'); expect(span.attributes[SEMATTRS_RPC_SERVICE]).toEqual('S3'); + expect(span.attributes[AttributeNames.AWS_S3_BUCKET]).toEqual( + 'invalid-bucket-name' + ); expect(span.attributes[SEMATTRS_HTTP_STATUS_CODE]).toEqual(403); expect(span.attributes[AttributeNames.AWS_REGION]).toEqual(region); expect(span.attributes[AttributeNames.AWS_REQUEST_ID]).toEqual( diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts index 626b811069..25f0f4df77 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts @@ -22,7 +22,7 @@ import { AwsInstrumentation } from '../src'; import { AttributeNames } from '../src/enums'; registerInstrumentationTesting(new AwsInstrumentation()); -import { Kinesis } from '@aws-sdk/client-kinesis'; +import { DescribeStreamCommand, KinesisClient } from '@aws-sdk/client-kinesis'; import * as AWS from 'aws-sdk'; import { AWSError } from 'aws-sdk'; import * as nock from 'nock'; @@ -80,28 +80,19 @@ describe('Kinesis - v2', () => { }); describe('Kinesis - v3', () => { - let kinesis: Kinesis; - beforeEach(() => { - kinesis = new Kinesis({ - region: region, - credentials: { - accessKeyId: 'abcde', - secretAccessKey: 'abcde', - }, - }); - }); - describe('DescribeStream', () => { it('adds Stream Name', async () => { const dummyStreamName = 'dummy-stream-name'; - nock(`https://kinesis.${region}.amazonaws.com/`).post('/').reply(200, {}); + nock(`https://kinesis.${region}.amazonaws.com/`) + .post('/') + .reply(200, 'null'); - await kinesis - .describeStream({ - StreamName: dummyStreamName, - }) - .catch((err: any) => {}); + const params = { + StreamName: dummyStreamName, + }; + const client = new KinesisClient({ region }); + await client.send(new DescribeStreamCommand(params)).catch(() => {}); const testSpans: ReadableSpan[] = getTestSpans(); const describeSpans: ReadableSpan[] = testSpans.filter( diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts index dc73c1b22b..7ca1eda3cb 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts @@ -22,9 +22,10 @@ import { AwsInstrumentation } from '../src'; import { AttributeNames } from '../src/enums'; registerInstrumentationTesting(new AwsInstrumentation()); -import { S3 } from '@aws-sdk/client-s3'; +import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; import * as AWS from 'aws-sdk'; import { AWSError } from 'aws-sdk'; +import * as fs from 'fs'; import * as nock from 'nock'; import { SpanKind } from '@opentelemetry/api'; @@ -78,33 +79,28 @@ describe('S3 - v2', () => { }); describe('S3 - v3', () => { - let s3: S3; - beforeEach(() => { - s3 = new S3({ - region: region, - credentials: { - accessKeyId: 'abcde', - secretAccessKey: 'abcde', - }, - }); - }); - - describe('ListObjects', () => { + describe('PutObject', () => { it('adds bucket Name', async () => { - const dummyBucketName = 'dummy-bucket-name'; + const dummyBucketName = 'ot-demo-test'; - nock(`https://s3.${region}.amazonaws.com/`).post('/').reply(200, 'null'); + nock(`https://${dummyBucketName}.s3.${region}.amazonaws.com/`) + .put('/aws-ot-s3-test-object.txt?x-id=PutObject') + .reply( + 200, + fs.readFileSync('./test/mock-responses/s3-put-object.xml', 'utf8') + ); - await s3 - .listObjects({ - Bucket: dummyBucketName, - }) - .catch((err: any) => {}); + const params = { + Bucket: dummyBucketName, + Key: 'aws-ot-s3-test-object.txt', + }; + const client = new S3Client({ region }); + await client.send(new PutObjectCommand(params)); const testSpans: ReadableSpan[] = getTestSpans(); const listObjectsSpans: ReadableSpan[] = testSpans.filter( (s: ReadableSpan) => { - return s.name === 'S3.ListObjects'; + return s.name === 'S3.PutObject'; } ); expect(listObjectsSpans.length).toBe(1); From b97d73ad53f18f50ae8cf5ed3e1aa2cef712ea15 Mon Sep 17 00:00:00 2001 From: jjllee Date: Fri, 13 Sep 2024 19:22:50 -0700 Subject: [PATCH 6/7] Trigger Build to rerun TAV From 450a1c2cbd2144c096dc590a1519e44bc6d5bcbb Mon Sep 17 00:00:00 2001 From: jjllee Date: Thu, 26 Sep 2024 12:59:12 -0700 Subject: [PATCH 7/7] remove tests for end-of-life aws-sdk v2, fix kinesis test latency --- package-lock.json | 12 +--- .../package.json | 1 + .../test/kinesis.test.ts | 71 +++++-------------- .../kinesis-describe-stream.json | 1 + .../test/s3.test.ts | 48 +------------ 5 files changed, 23 insertions(+), 110 deletions(-) create mode 100644 plugins/node/opentelemetry-instrumentation-aws-sdk/test/mock-responses/kinesis-describe-stream.json diff --git a/package-lock.json b/package-lock.json index 5a7e645fb2..daa7123ab8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11716,7 +11716,6 @@ "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-iwUxrFm/ZFCXhzhtZ6JnoJzAsqUrVfBAZUTQj8ypXGtIjwXZpKqmgYiuqrDERiydDI5gesqvsC4Rqe57GGhbVg==", "dev": true, - "optional": true, "dependencies": { "@smithy/types": "^2.10.0", "tslib": "^2.5.0" @@ -12002,7 +12001,6 @@ "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.4.0.tgz", "integrity": "sha512-Mf2f7MMy31W8LisJ9O+7J5cKiNwBwBBLU6biQ7/sFSFdhuOxPN7hOPoZ8vlaFjvrpfOUJw9YOpjGyNTKuvomOQ==", "dev": true, - "optional": true, "dependencies": { "@smithy/abort-controller": "^2.1.2", "@smithy/protocol-http": "^3.2.0", @@ -12033,7 +12031,6 @@ "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.2.0.tgz", "integrity": "sha512-VRp0YITYIQum+rX4zeZ3cW1wl9r90IQzQN+VLS1NxdSMt6NLsJiJqR9czTxlaeWNrLHsFAETmjmdrS48Ug1liA==", "dev": true, - "optional": true, "dependencies": { "@smithy/types": "^2.10.0", "tslib": "^2.5.0" @@ -12047,7 +12044,6 @@ "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.1.2.tgz", "integrity": "sha512-wk6QpuvBBLJF5w8aADsZOtxaHY9cF5MZe1Ry3hSqqBxARdUrMoXi/jukUz5W0ftXGlbA398IN8dIIUj3WXqJXg==", "dev": true, - "optional": true, "dependencies": { "@smithy/types": "^2.10.0", "@smithy/util-uri-escape": "^2.1.1", @@ -12342,7 +12338,6 @@ "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.1.1.tgz", "integrity": "sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==", "dev": true, - "optional": true, "dependencies": { "tslib": "^2.5.0" }, @@ -38594,6 +38589,7 @@ "@opentelemetry/api": "^1.3.0", "@opentelemetry/contrib-test-utils": "^0.41.0", "@opentelemetry/sdk-trace-base": "^1.8.0", + "@smithy/node-http-handler": "2.4.0", "@types/mocha": "8.2.3", "@types/node": "18.6.5", "@types/sinon": "10.0.20", @@ -50752,6 +50748,7 @@ "@opentelemetry/propagation-utils": "^0.30.11", "@opentelemetry/sdk-trace-base": "^1.8.0", "@opentelemetry/semantic-conventions": "^1.27.0", + "@smithy/node-http-handler": "2.4.0", "@types/mocha": "8.2.3", "@types/node": "18.6.5", "@types/sinon": "10.0.20", @@ -54944,7 +54941,6 @@ "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.2.tgz", "integrity": "sha512-iwUxrFm/ZFCXhzhtZ6JnoJzAsqUrVfBAZUTQj8ypXGtIjwXZpKqmgYiuqrDERiydDI5gesqvsC4Rqe57GGhbVg==", "dev": true, - "optional": true, "requires": { "@smithy/types": "^2.10.0", "tslib": "^2.5.0" @@ -55197,7 +55193,6 @@ "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.4.0.tgz", "integrity": "sha512-Mf2f7MMy31W8LisJ9O+7J5cKiNwBwBBLU6biQ7/sFSFdhuOxPN7hOPoZ8vlaFjvrpfOUJw9YOpjGyNTKuvomOQ==", "dev": true, - "optional": true, "requires": { "@smithy/abort-controller": "^2.1.2", "@smithy/protocol-http": "^3.2.0", @@ -55222,7 +55217,6 @@ "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.2.0.tgz", "integrity": "sha512-VRp0YITYIQum+rX4zeZ3cW1wl9r90IQzQN+VLS1NxdSMt6NLsJiJqR9czTxlaeWNrLHsFAETmjmdrS48Ug1liA==", "dev": true, - "optional": true, "requires": { "@smithy/types": "^2.10.0", "tslib": "^2.5.0" @@ -55233,7 +55227,6 @@ "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.1.2.tgz", "integrity": "sha512-wk6QpuvBBLJF5w8aADsZOtxaHY9cF5MZe1Ry3hSqqBxARdUrMoXi/jukUz5W0ftXGlbA398IN8dIIUj3WXqJXg==", "dev": true, - "optional": true, "requires": { "@smithy/types": "^2.10.0", "@smithy/util-uri-escape": "^2.1.1", @@ -55474,7 +55467,6 @@ "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.1.1.tgz", "integrity": "sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==", "dev": true, - "optional": true, "requires": { "tslib": "^2.5.0" } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json b/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json index e56340d657..2dc65202bb 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/package.json @@ -58,6 +58,7 @@ "@aws-sdk/client-sns": "3.85.0", "@aws-sdk/client-sqs": "3.85.0", "@aws-sdk/types": "3.78.0", + "@smithy/node-http-handler": "2.4.0", "@opentelemetry/api": "^1.3.0", "@opentelemetry/contrib-test-utils": "^0.41.0", "@opentelemetry/sdk-trace-base": "^1.8.0", diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts index 25f0f4df77..cdd4d92cfa 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/kinesis.test.ts @@ -23,8 +23,8 @@ import { AttributeNames } from '../src/enums'; registerInstrumentationTesting(new AwsInstrumentation()); import { DescribeStreamCommand, KinesisClient } from '@aws-sdk/client-kinesis'; -import * as AWS from 'aws-sdk'; -import { AWSError } from 'aws-sdk'; +import { NodeHttpHandler } from '@smithy/node-http-handler'; +import * as fs from 'fs'; import * as nock from 'nock'; import { SpanKind } from '@opentelemetry/api'; @@ -33,66 +33,31 @@ import { expect } from 'expect'; const region = 'us-east-1'; -describe('Kinesis - v2', () => { - let kinesis: AWS.Kinesis; - beforeEach(() => { - AWS.config.credentials = { - accessKeyId: 'test key id', - expired: false, - expireTime: new Date(), - secretAccessKey: 'test acc key', - sessionToken: 'test token', - }; - }); - - describe('DescribeStream', () => { - it('adds Stream Name', async () => { - kinesis = new AWS.Kinesis({ region: region }); - const dummyStreamName = 'dummy-stream-name'; - - nock(`https://kinesis.${region}.amazonaws.com`) - .get('/') - .reply(200, 'null'); - - await kinesis - .describeStream( - { - StreamName: dummyStreamName, - }, - (err: AWSError) => { - expect(err).toBeFalsy(); - } - ) - .promise(); - - const testSpans = getTestSpans(); - const describeSpans = testSpans.filter((s: ReadableSpan) => { - return s.name === 'Kinesis.DescribeStream'; - }); - expect(describeSpans.length).toBe(1); - const describeSpan = describeSpans[0]; - expect( - describeSpan.attributes[AttributeNames.AWS_KINESIS_STREAM_NAME] - ).toBe(dummyStreamName); - expect(describeSpan.kind).toBe(SpanKind.CLIENT); - }); - }); -}); - describe('Kinesis - v3', () => { describe('DescribeStream', () => { - it('adds Stream Name', async () => { + it('Request span attributes - adds Stream Name', async () => { const dummyStreamName = 'dummy-stream-name'; - nock(`https://kinesis.${region}.amazonaws.com/`) + nock(`https://kinesis.${region}.amazonaws.com`) .post('/') - .reply(200, 'null'); + .reply( + 200, + fs.readFileSync( + './test/mock-responses/kinesis-describe-stream.json', + 'utf8' + ) + ); const params = { StreamName: dummyStreamName, }; - const client = new KinesisClient({ region }); - await client.send(new DescribeStreamCommand(params)).catch(() => {}); + + // Use NodeHttpHandler to use HTTP instead of HTTP2 because nock does not support HTTP2 + const client = new KinesisClient({ + region: region, + requestHandler: new NodeHttpHandler(), + }); + await client.send(new DescribeStreamCommand(params)); const testSpans: ReadableSpan[] = getTestSpans(); const describeSpans: ReadableSpan[] = testSpans.filter( diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/mock-responses/kinesis-describe-stream.json b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/mock-responses/kinesis-describe-stream.json new file mode 100644 index 0000000000..7d60744f59 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/mock-responses/kinesis-describe-stream.json @@ -0,0 +1 @@ +{"StreamDescription":{"EncryptionType":"NONE","EnhancedMonitoring":[{"ShardLevelMetrics":[]}],"HasMoreShards":false,"RetentionPeriodHours":24,"Shards":[{"HashKeyRange":{"EndingHashKey":"113238940823489329203432849230874303284","StartingHashKey":"0"},"SequenceNumberRange":{"StartingSequenceNumber":"43987583475293457385930053489574375382543783454534789435"},"ShardId":"shardId-000000000000"},{"HashKeyRange":{"EndingHashKey":"226854911280625642308916401214512140969","StartingHashKey":"113427455579312821154458202477256070485"},"SequenceNumberRange":{"StartingSequenceNumber":"49654869303348141538950437146463849462533012903803486226"},"ShardId":"shardId-000000000001"},{"HashKeyRange":{"EndingHashKey":"340282366920284953463374607431768211455","StartingHashKey":"226854911280625642308916382954512140970"},"SequenceNumberRange":{"StartingSequenceNumber":"49654869303370442228501967769610713180805661265309466658"},"ShardId":"shardId-000000000002"}],"StreamARN":"arn:aws:kinesis:us-east-1:123456789012:stream/dummy-stream-name","StreamCreationTimestamp":1.723630733E9,"StreamModeDetails":{"StreamMode":"PROVISIONED"},"StreamName":"dummy-stream-name","StreamStatus":"ACTIVE"}} \ No newline at end of file diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts index 7ca1eda3cb..47795dd466 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/s3.test.ts @@ -23,8 +23,6 @@ import { AttributeNames } from '../src/enums'; registerInstrumentationTesting(new AwsInstrumentation()); import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; -import * as AWS from 'aws-sdk'; -import { AWSError } from 'aws-sdk'; import * as fs from 'fs'; import * as nock from 'nock'; @@ -34,53 +32,9 @@ import { expect } from 'expect'; const region = 'us-east-1'; -describe('S3 - v2', () => { - let s3: AWS.S3; - beforeEach(() => { - AWS.config.credentials = { - accessKeyId: 'test key id', - expired: false, - expireTime: new Date(), - secretAccessKey: 'test acc key', - sessionToken: 'test token', - }; - }); - - describe('ListObjects', () => { - it('adds bucket Name', async () => { - s3 = new AWS.S3({ region: region }); - const dummyBucketName = 'dummy-bucket-name'; - - nock(`https://s3.${region}.amazonaws.com`).get('/').reply(200, 'null'); - - await s3 - .listObjects( - { - Bucket: dummyBucketName, - }, - (err: AWSError) => { - expect(err).toBeFalsy(); - } - ) - .promise(); - - const testSpans = getTestSpans(); - const listObjectsSpans = testSpans.filter((s: ReadableSpan) => { - return s.name === 'S3.ListObjects'; - }); - expect(listObjectsSpans.length).toBe(1); - const listObjectsSpan = listObjectsSpans[0]; - expect(listObjectsSpan.attributes[AttributeNames.AWS_S3_BUCKET]).toBe( - dummyBucketName - ); - expect(listObjectsSpan.kind).toBe(SpanKind.CLIENT); - }); - }); -}); - describe('S3 - v3', () => { describe('PutObject', () => { - it('adds bucket Name', async () => { + it('Request span attributes - adds bucket Name', async () => { const dummyBucketName = 'ot-demo-test'; nock(`https://${dummyBucketName}.s3.${region}.amazonaws.com/`)