From 13e48e3f4cbc88ba4b22a4b3449267c235fe2e2a Mon Sep 17 00:00:00 2001 From: Carol Abadeer Date: Thu, 1 Jun 2023 18:50:47 -0700 Subject: [PATCH 1/3] feat(opentelemetry-instrumentation-aws-sdk): add missing spec-defined DynamoDB attributes --- .../src/services/dynamodb.ts | 172 +++++++++++++++++- .../test/dynamodb.test.ts | 103 +++++++++++ 2 files changed, 274 insertions(+), 1 deletion(-) 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 dd797b5af7..28e49575e6 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts @@ -26,6 +26,10 @@ import { } from '../types'; export class DynamodbServiceExtension implements ServiceExtension { + toArray(values: T | T[]): T[] { + return Array.isArray(values) ? values : [values]; + } + requestPreSpanHook(normalizedRequest: NormalizedRequest): RequestMetadata { const spanKind: SpanKind = SpanKind.CLIENT; let spanName: string | undefined; @@ -41,12 +45,140 @@ export class DynamodbServiceExtension implements ServiceExtension { ), }; - if (operation === 'BatchGetItem') { + // normalizedRequest.commandInput.RequestItems) is undefined when no table names are returned + // keys in this object are the table names + if (normalizedRequest.commandInput?.TableName) { + // Necessary for commands with only 1 table name (example: CreateTable). Attribute is TableName not keys of RequestItems + // single table name returned for operations like CreateTable + spanAttributes[SemanticAttributes.AWS_DYNAMODB_TABLE_NAMES] = [ + normalizedRequest.commandInput.TableName, + ]; + } else if (normalizedRequest.commandInput?.RequestItems) { spanAttributes[SemanticAttributes.AWS_DYNAMODB_TABLE_NAMES] = Object.keys( normalizedRequest.commandInput.RequestItems ); } + if (operation === 'CreateTable' || operation === 'UpdateTable') { + // only check for ProvisionedThroughput since ReadCapacityUnits and WriteCapacity units are required attributes + if (normalizedRequest.commandInput?.ProvisionedThroughput) { + spanAttributes[ + SemanticAttributes.AWS_DYNAMODB_PROVISIONED_READ_CAPACITY + ] = + normalizedRequest.commandInput.ProvisionedThroughput.ReadCapacityUnits; + spanAttributes[ + SemanticAttributes.AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY + ] = + normalizedRequest.commandInput.ProvisionedThroughput.WriteCapacityUnits; + } + } + + if ( + operation === 'GetItem' || + operation === 'Scan' || + operation === 'Query' + ) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_CONSISTENT_READ] = + normalizedRequest.commandInput.ConsistentRead; + } + + if (operation === 'Query' || operation === 'Scan') { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_PROJECTION] = + normalizedRequest.commandInput.ProjectionExpression; + } + + if (operation === 'CreateTable') { + if (normalizedRequest.commandInput?.GlobalSecondaryIndexes) { + spanAttributes[ + SemanticAttributes.AWS_DYNAMODB_GLOBAL_SECONDARY_INDEXES + ] = this.toArray( + normalizedRequest.commandInput.GlobalSecondaryIndexes + ).map((x: { [DictionaryKey: string]: any }) => JSON.stringify(x)); + } + + if (normalizedRequest.commandInput?.LocalSecondaryIndexes) { + spanAttributes[ + SemanticAttributes.AWS_DYNAMODB_LOCAL_SECONDARY_INDEXES + ] = this.toArray( + normalizedRequest.commandInput.LocalSecondaryIndexes + ).map((x: { [DictionaryKey: string]: any }) => JSON.stringify(x)); + } + } + + if ( + operation === 'ListTables' || + operation === 'Query' || + operation === 'Scan' + ) { + if (normalizedRequest.commandInput?.Limit) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_LIMIT] = + normalizedRequest.commandInput.Limit; + } + } + + if (operation === 'ListTables') { + if (normalizedRequest.commandInput?.ExclusiveStartTableName) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_EXCLUSIVE_START_TABLE] = + normalizedRequest.commandInput.ExclusiveStartTableName; + } + } + + if (operation === 'Query') { + if (normalizedRequest.commandInput?.ScanIndexForward) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_SCAN_FORWARD] = + normalizedRequest.commandInput.ScanIndexForward; + } + + if (normalizedRequest.commandInput?.IndexName) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_INDEX_NAME] = + normalizedRequest.commandInput.IndexName; + } + + if (normalizedRequest.commandInput?.Select) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_SELECT] = + normalizedRequest.commandInput.Select; + } + } + + if (operation === 'Scan') { + if (normalizedRequest.commandInput?.Segment) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_SEGMENT] = + normalizedRequest.commandInput?.Segment; + } + + if (normalizedRequest.commandInput?.TotalSegments) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_TOTAL_SEGMENTS] = + normalizedRequest.commandInput?.TotalSegments; + } + + if (normalizedRequest.commandInput?.IndexName) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_INDEX_NAME] = + normalizedRequest.commandInput.IndexName; + } + + if (normalizedRequest.commandInput?.Select) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_SELECT] = + normalizedRequest.commandInput.Select; + } + } + + if (operation === 'UpdateTable') { + if (normalizedRequest.commandInput?.AttributeDefinitions) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_ATTRIBUTE_DEFINITIONS] = + this.toArray(normalizedRequest.commandInput.AttributeDefinitions).map( + (x: { [DictionaryKey: string]: any }) => JSON.stringify(x) + ); + } + + if (normalizedRequest.commandInput?.GlobalSecondaryIndexUpdates) { + spanAttributes[ + SemanticAttributes.AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES + ] = this.toArray( + normalizedRequest.commandInput.GlobalSecondaryIndexUpdates + ).map((x: { [DictionaryKey: string]: any }) => JSON.stringify(x)); + } + } + return { isIncoming, spanAttributes, @@ -73,5 +205,43 @@ export class DynamodbServiceExtension implements ServiceExtension { ); } } + + if ( + operation === 'BatchWriteItem' || + operation === 'CreateTable' || + operation === 'DeleteItem' || + operation === 'PutItem' || + operation === 'UpdateItem' + ) { + span.setAttribute( + SemanticAttributes.AWS_DYNAMODB_ITEM_COLLECTION_METRICS, + response.data.ItemCollectionMetrics + ); + } + + if (operation === 'ListTables') { + if (response.data?.TableNames) { + span.setAttribute( + SemanticAttributes.AWS_DYNAMODB_TABLE_COUNT, + response.data?.TableNames.length + ); + } + } + + if (operation === 'Scan') { + if (response.data?.Count) { + span.setAttribute( + SemanticAttributes.AWS_DYNAMODB_COUNT, + response.data?.Count + ); + } + + if (response.data?.ScannedCount) { + span.setAttribute( + SemanticAttributes.AWS_DYNAMODB_SCANNED_COUNT, + response.data?.ScannedCount + ); + } + } } } 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 5ff0c2b0ab..1ce31e614e 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts @@ -69,7 +69,14 @@ describe('DynamoDB', () => { 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) => { @@ -81,6 +88,102 @@ describe('DynamoDB', () => { ); expect(attrs[SemanticAttributes.DB_NAME]).toStrictEqual('test-table'); expect(attrs[SemanticAttributes.DB_OPERATION]).toStrictEqual('Query'); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_SCAN_FORWARD] + ).toStrictEqual(true); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_CONSISTENT_READ] + ).toStrictEqual(true); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_INDEX_NAME] + ).toStrictEqual('name_to_group'); + expect(attrs[SemanticAttributes.AWS_DYNAMODB_SELECT]).toStrictEqual( + 'ALL_ATTRIBUTES' + ); + expect(attrs[SemanticAttributes.AWS_DYNAMODB_LIMIT]).toStrictEqual( + 10 + ); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_TABLE_NAMES] + ).toStrictEqual(['test-table']); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_PROJECTION] + ).toStrictEqual('id'); + expect( + JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) + ).toEqual(params); + expect(err).toBeFalsy(); + done(); + } + ); + }); + }); + + describe('Scan', () => { + beforeEach(() => + mockV2AwsSend(responseMockSuccess, { + ConsumedCapacity: { + TableName: 'test-table', + CapacityUnits: 0.5, + Table: { CapacityUnits: 0.5 }, + }, + Count: 10, + ScannedCount: 50, + } as AWS.DynamoDB.Types.ScanOutput) + ); + + it('should populate specific Scan attributes', done => { + const dynamodb = new AWS.DynamoDB.DocumentClient(); + const params = { + TableName: 'test-table', + Item: { key1: 'val1' }, + ProjectionExpression: 'id', + ConsistentRead: true, + Segment: 10, + TotalSegments: 100, + IndexName: 'index_name', + Limit: 10, + Select: 'ALL_ATTRIBUTES', + }; + + dynamodb.scan( + params, + (err: AWSError, data: AWS.DynamoDB.DocumentClient.ScanOutput) => { + const spans = getTestSpans(); + expect(spans.length).toStrictEqual(1); + const attrs = spans[0].attributes; + expect(attrs[SemanticAttributes.DB_SYSTEM]).toStrictEqual( + DbSystemValues.DYNAMODB + ); + expect(attrs[SemanticAttributes.DB_NAME]).toStrictEqual('test-table'); + expect(attrs[SemanticAttributes.DB_OPERATION]).toStrictEqual('Scan'); + expect(attrs[SemanticAttributes.AWS_DYNAMODB_SEGMENT]).toStrictEqual( + 10 + ); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_TOTAL_SEGMENTS] + ).toStrictEqual(100); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_INDEX_NAME] + ).toStrictEqual('index_name'); + expect(attrs[SemanticAttributes.AWS_DYNAMODB_SELECT]).toStrictEqual( + 'ALL_ATTRIBUTES' + ); + expect(attrs[SemanticAttributes.AWS_DYNAMODB_COUNT]).toStrictEqual( + 10 + ); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_SCANNED_COUNT] + ).toStrictEqual(50); + expect(attrs[SemanticAttributes.AWS_DYNAMODB_LIMIT]).toStrictEqual( + 10 + ); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_TABLE_NAMES] + ).toStrictEqual(['test-table']); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_PROJECTION] + ).toStrictEqual('id'); expect( JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) ).toEqual(params); From ba7dc4cff2eeba2dcf2602e6f9ee0d743f23981c Mon Sep 17 00:00:00 2001 From: Carol Abadeer Date: Tue, 13 Jun 2023 18:57:54 -0700 Subject: [PATCH 2/3] feat(opentelemetry-instrumentation-aws-sdk): add checks for input attributes and additional unit tests --- .../src/services/dynamodb.ts | 60 ++-- .../test/dynamodb.test.ts | 268 ++++++++++++++++++ 2 files changed, 296 insertions(+), 32 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 28e49575e6..424cab5fa4 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts @@ -78,13 +78,17 @@ export class DynamodbServiceExtension implements ServiceExtension { operation === 'Scan' || operation === 'Query' ) { - spanAttributes[SemanticAttributes.AWS_DYNAMODB_CONSISTENT_READ] = - normalizedRequest.commandInput.ConsistentRead; + if (normalizedRequest.commandInput?.ConsistentRead) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_CONSISTENT_READ] = + normalizedRequest.commandInput.ConsistentRead; + } } if (operation === 'Query' || operation === 'Scan') { - spanAttributes[SemanticAttributes.AWS_DYNAMODB_PROJECTION] = - normalizedRequest.commandInput.ProjectionExpression; + if (normalizedRequest.commandInput?.ProjectionExpression) { + spanAttributes[SemanticAttributes.AWS_DYNAMODB_PROJECTION] = + normalizedRequest.commandInput.ProjectionExpression; + } } if (operation === 'CreateTable') { @@ -206,42 +210,34 @@ export class DynamodbServiceExtension implements ServiceExtension { } } - if ( - operation === 'BatchWriteItem' || - operation === 'CreateTable' || - operation === 'DeleteItem' || - operation === 'PutItem' || - operation === 'UpdateItem' - ) { + if (response.data?.ItemCollectionMetrics) { span.setAttribute( SemanticAttributes.AWS_DYNAMODB_ITEM_COLLECTION_METRICS, - response.data.ItemCollectionMetrics + this.toArray(response.data.ItemCollectionMetrics).map( + (x: { [DictionaryKey: string]: any }) => JSON.stringify(x) + ) ); } - if (operation === 'ListTables') { - if (response.data?.TableNames) { - span.setAttribute( - SemanticAttributes.AWS_DYNAMODB_TABLE_COUNT, - response.data?.TableNames.length - ); - } + if (response.data?.TableNames) { + span.setAttribute( + SemanticAttributes.AWS_DYNAMODB_TABLE_COUNT, + response.data?.TableNames.length + ); } - if (operation === 'Scan') { - if (response.data?.Count) { - span.setAttribute( - SemanticAttributes.AWS_DYNAMODB_COUNT, - response.data?.Count - ); - } + if (response.data?.Count) { + span.setAttribute( + SemanticAttributes.AWS_DYNAMODB_COUNT, + response.data?.Count + ); + } - if (response.data?.ScannedCount) { - span.setAttribute( - SemanticAttributes.AWS_DYNAMODB_SCANNED_COUNT, - response.data?.ScannedCount - ); - } + if (response.data?.ScannedCount) { + span.setAttribute( + SemanticAttributes.AWS_DYNAMODB_SCANNED_COUNT, + response.data?.ScannedCount + ); } } } 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 1ce31e614e..5371ef9649 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts @@ -194,6 +194,274 @@ describe('DynamoDB', () => { }); }); + describe('BatchWriteItem', () => { + beforeEach(() => + mockV2AwsSend(responseMockSuccess, { + UnprocessedItems: {}, + ItemCollectionMetrics: {"ItemCollectionKey": [], "SizeEstimateRangeGB": [0]}, + ConsumedCapacity: undefined, + } as AWS.DynamoDB.Types.BatchWriteItemOutput) + ); + + it('should populate specific BatchWriteItem attributes', done => { + 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_SYSTEM]).toStrictEqual( + DbSystemValues.DYNAMODB + ); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_ITEM_COLLECTION_METRICS] + ).toStrictEqual([ + JSON.stringify({"ItemCollectionKey": [], "SizeEstimateRangeGB": [0]}), + ]); + + expect( + JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) + ).toEqual(params); + expect(err).toBeFalsy(); + done(); + } + ); + }); + }); + + describe('CreateTable', () => { + beforeEach(() => + mockV2AwsSend(responseMockSuccess, { + TableName: "test_table", + ItemCollectionMetrics: {"ItemCollectionKey": [], "SizeEstimateRangeGB": [0]}, + ConsumedCapacity: undefined, + } as AWS.DynamoDB.Types.CreateTableOutput) + ); + + it('should populate specific CreateTable attributes', done => { + + 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_SYSTEM]).toStrictEqual( + DbSystemValues.DYNAMODB + ); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_ITEM_COLLECTION_METRICS] + ).toStrictEqual([ + JSON.stringify({"ItemCollectionKey": [], "SizeEstimateRangeGB": [0]}), + ]); + + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_GLOBAL_SECONDARY_INDEXES] + ).toStrictEqual([JSON.stringify(globalSecondaryIndexMockData)]); + + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_LOCAL_SECONDARY_INDEXES] + ).toStrictEqual([JSON.stringify(localSecondaryIndexMockData)]); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_PROVISIONED_READ_CAPACITY] + ).toStrictEqual(20); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY] + ).toStrictEqual(30); + expect( + JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) + ).toEqual(params); + expect(err).toBeFalsy(); + done(); + } + ); + }); + }); + + describe('UpdateTable', () => { + beforeEach(() => + mockV2AwsSend(responseMockSuccess, { + TableName: "test_table" + } as AWS.DynamoDB.Types.UpdateTableOutput) + ); + + it('should populate specific CreateTable attributes', done => { + 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_SYSTEM]).toStrictEqual( + DbSystemValues.DYNAMODB + ); + + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES] + ).toStrictEqual([JSON.stringify({ + Update: { + IndexName: "test_index", + ProvisionedThroughput: { + ReadCapacityUnits: 1, + WriteCapacityUnits: 5, + }, + }, + })]); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_ATTRIBUTE_DEFINITIONS] + ).toStrictEqual([JSON.stringify( + { + AttributeName: "test_attr", + AttributeType: "S", + } + )]); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_PROVISIONED_READ_CAPACITY] + ).toStrictEqual(10); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY] + ).toStrictEqual(15); + expect( + JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) + ).toEqual(params); + expect(err).toBeFalsy(); + done(); + } + ); + }); + }); + + describe('ListTables', () => { + beforeEach(() => + mockV2AwsSend(responseMockSuccess, { + TableNames: ["test_table", "test_table_2", "start_table"] + } as AWS.DynamoDB.Types.ListTablesOutput) + ); + + it('should populate specific ListTables attributes', done => { + 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_SYSTEM]).toStrictEqual( + DbSystemValues.DYNAMODB + ); + + expect(attrs[SemanticAttributes.AWS_DYNAMODB_EXCLUSIVE_START_TABLE]).toStrictEqual("start_table") + expect(attrs[SemanticAttributes.AWS_DYNAMODB_LIMIT]).toStrictEqual(10); + expect(attrs[SemanticAttributes.AWS_DYNAMODB_TABLE_COUNT]).toStrictEqual(3); + + expect( + JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string) + ).toEqual(params); + expect(err).toBeFalsy(); + done(); + } + ); + }); + }); + describe('BatchGetItem', () => { const consumedCapacityResponseMockData: ConsumedCapacity[] = [ { From 52ebd502bc503680fa135bc0a5ea7e32184091d4 Mon Sep 17 00:00:00 2001 From: Carol Abadeer Date: Mon, 26 Jun 2023 09:49:03 -0700 Subject: [PATCH 3/3] feat(opentelemetry-instrumentation-aws-sdk): run lint on dynamoDB unit tests --- .../test/dynamodb.test.ts | 176 ++++++++++-------- 1 file changed, 98 insertions(+), 78 deletions(-) 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 5371ef9649..b8504d4010 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/dynamodb.test.ts @@ -198,8 +198,11 @@ describe('DynamoDB', () => { beforeEach(() => mockV2AwsSend(responseMockSuccess, { UnprocessedItems: {}, - ItemCollectionMetrics: {"ItemCollectionKey": [], "SizeEstimateRangeGB": [0]}, - ConsumedCapacity: undefined, + ItemCollectionMetrics: { + ItemCollectionKey: [], + SizeEstimateRangeGB: [0], + }, + ConsumedCapacity: undefined, } as AWS.DynamoDB.Types.BatchWriteItemOutput) ); @@ -208,12 +211,15 @@ describe('DynamoDB', () => { const params = { RequestItems: {}, ReturnConsumedCapacity: 'INDEXES', - ReturnItemCollectionMetrics: 'SIZE' + ReturnItemCollectionMetrics: 'SIZE', }; dynamodb.batchWrite( params, - (err: AWSError, data: AWS.DynamoDB.DocumentClient.BatchWriteItemOutput) => { + ( + err: AWSError, + data: AWS.DynamoDB.DocumentClient.BatchWriteItemOutput + ) => { const spans = getTestSpans(); expect(spans.length).toStrictEqual(1); const attrs = spans[0].attributes; @@ -223,7 +229,7 @@ describe('DynamoDB', () => { expect( attrs[SemanticAttributes.AWS_DYNAMODB_ITEM_COLLECTION_METRICS] ).toStrictEqual([ - JSON.stringify({"ItemCollectionKey": [], "SizeEstimateRangeGB": [0]}), + JSON.stringify({ ItemCollectionKey: [], SizeEstimateRangeGB: [0] }), ]); expect( @@ -239,77 +245,78 @@ describe('DynamoDB', () => { describe('CreateTable', () => { beforeEach(() => mockV2AwsSend(responseMockSuccess, { - TableName: "test_table", - ItemCollectionMetrics: {"ItemCollectionKey": [], "SizeEstimateRangeGB": [0]}, - ConsumedCapacity: undefined, + TableName: 'test_table', + ItemCollectionMetrics: { + ItemCollectionKey: [], + SizeEstimateRangeGB: [0], + }, + ConsumedCapacity: undefined, } as AWS.DynamoDB.Types.CreateTableOutput) ); it('should populate specific CreateTable attributes', done => { - - const globalSecondaryIndexMockData = { - IndexName: "test_index", - KeySchema: [ + const globalSecondaryIndexMockData = { + IndexName: 'test_index', + KeySchema: [ { - AttributeName: "attribute1", - KeyType: "HASH", + AttributeName: 'attribute1', + KeyType: 'HASH', }, ], Projection: { - ProjectionType: "ALL", - NonKeyAttributes: [ - "non_key_attr", - ], + ProjectionType: 'ALL', + NonKeyAttributes: ['non_key_attr'], }, ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 10, }, - } + }; - const localSecondaryIndexMockData = { - IndexName: "test_index", + const localSecondaryIndexMockData = { + IndexName: 'test_index', KeySchema: [ { - AttributeName: "test_attribute", - KeyType: "HASH", + AttributeName: 'test_attribute', + KeyType: 'HASH', }, ], - Projection: { - ProjectionType: "ALL", - NonKeyAttributes: [ - "STRING_VALUE", - ], + Projection: { + ProjectionType: 'ALL', + NonKeyAttributes: ['STRING_VALUE'], }, - } + }; const dynamodb = new AWS.DynamoDB(); const params = { - AttributeDefinitions: [ - { - AttributeName: "test_attribute", - AttributeType: "S", + AttributeDefinitions: [ + { + AttributeName: 'test_attribute', + AttributeType: 'S', }, ], - TableName: "test_table", - KeySchema: [ - { - AttributeName: "test_attribute", - KeyType: "HASH", + TableName: 'test_table', + KeySchema: [ + { + AttributeName: 'test_attribute', + KeyType: 'HASH', }, ], LocalSecondaryIndexes: [localSecondaryIndexMockData], GlobalSecondaryIndexes: [globalSecondaryIndexMockData], - BillingMode: "PROVISIONED", + BillingMode: 'PROVISIONED', ProvisionedThroughput: { - ReadCapacityUnits: 20, + ReadCapacityUnits: 20, WriteCapacityUnits: 30, }, }; dynamodb.createTable( params, - (err: AWSError, data: AWS.DynamoDB.DocumentClient.CreateTableOutput) => { + ( + err: AWSError, + data: AWS.DynamoDB.DocumentClient.CreateTableOutput + ) => { const spans = getTestSpans(); expect(spans.length).toStrictEqual(1); const attrs = spans[0].attributes; @@ -319,7 +326,7 @@ describe('DynamoDB', () => { expect( attrs[SemanticAttributes.AWS_DYNAMODB_ITEM_COLLECTION_METRICS] ).toStrictEqual([ - JSON.stringify({"ItemCollectionKey": [], "SizeEstimateRangeGB": [0]}), + JSON.stringify({ ItemCollectionKey: [], SizeEstimateRangeGB: [0] }), ]); expect( @@ -348,31 +355,31 @@ describe('DynamoDB', () => { describe('UpdateTable', () => { beforeEach(() => mockV2AwsSend(responseMockSuccess, { - TableName: "test_table" + TableName: 'test_table', } as AWS.DynamoDB.Types.UpdateTableOutput) ); it('should populate specific CreateTable attributes', done => { const dynamodb = new AWS.DynamoDB(); - const params = { - AttributeDefinitions: [ - { - AttributeName: "test_attr", - AttributeType: "S", + const params = { + AttributeDefinitions: [ + { + AttributeName: 'test_attr', + AttributeType: 'S', }, ], - TableName: "test_table", - ProvisionedThroughput: { - ReadCapacityUnits: 10, - WriteCapacityUnits: 15, + TableName: 'test_table', + ProvisionedThroughput: { + ReadCapacityUnits: 10, + WriteCapacityUnits: 15, }, GlobalSecondaryIndexUpdates: [ - { - Update: { - IndexName: "test_index", + { + Update: { + IndexName: 'test_index', ProvisionedThroughput: { - ReadCapacityUnits: 1, - WriteCapacityUnits: 5, + ReadCapacityUnits: 1, + WriteCapacityUnits: 5, }, }, }, @@ -381,7 +388,10 @@ describe('DynamoDB', () => { dynamodb.updateTable( params, - (err: AWSError, data: AWS.DynamoDB.DocumentClient.UpdateTableOutput) => { + ( + err: AWSError, + data: AWS.DynamoDB.DocumentClient.UpdateTableOutput + ) => { const spans = getTestSpans(); expect(spans.length).toStrictEqual(1); const attrs = spans[0].attributes; @@ -390,24 +400,28 @@ describe('DynamoDB', () => { ); expect( - attrs[SemanticAttributes.AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES] - ).toStrictEqual([JSON.stringify({ - Update: { - IndexName: "test_index", - ProvisionedThroughput: { - ReadCapacityUnits: 1, - WriteCapacityUnits: 5, + attrs[ + SemanticAttributes.AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES + ] + ).toStrictEqual([ + JSON.stringify({ + Update: { + IndexName: 'test_index', + ProvisionedThroughput: { + ReadCapacityUnits: 1, + WriteCapacityUnits: 5, + }, }, - }, - })]); + }), + ]); expect( attrs[SemanticAttributes.AWS_DYNAMODB_ATTRIBUTE_DEFINITIONS] - ).toStrictEqual([JSON.stringify( - { - AttributeName: "test_attr", - AttributeType: "S", - } - )]); + ).toStrictEqual([ + JSON.stringify({ + AttributeName: 'test_attr', + AttributeType: 'S', + }), + ]); expect( attrs[SemanticAttributes.AWS_DYNAMODB_PROVISIONED_READ_CAPACITY] ).toStrictEqual(10); @@ -427,14 +441,14 @@ describe('DynamoDB', () => { describe('ListTables', () => { beforeEach(() => mockV2AwsSend(responseMockSuccess, { - TableNames: ["test_table", "test_table_2", "start_table"] + TableNames: ['test_table', 'test_table_2', 'start_table'], } as AWS.DynamoDB.Types.ListTablesOutput) ); it('should populate specific ListTables attributes', done => { const dynamodb = new AWS.DynamoDB(); const params = { - ExclusiveStartTableName: "start_table", + ExclusiveStartTableName: 'start_table', Limit: 10, }; @@ -448,9 +462,15 @@ describe('DynamoDB', () => { DbSystemValues.DYNAMODB ); - expect(attrs[SemanticAttributes.AWS_DYNAMODB_EXCLUSIVE_START_TABLE]).toStrictEqual("start_table") - expect(attrs[SemanticAttributes.AWS_DYNAMODB_LIMIT]).toStrictEqual(10); - expect(attrs[SemanticAttributes.AWS_DYNAMODB_TABLE_COUNT]).toStrictEqual(3); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_EXCLUSIVE_START_TABLE] + ).toStrictEqual('start_table'); + expect(attrs[SemanticAttributes.AWS_DYNAMODB_LIMIT]).toStrictEqual( + 10 + ); + expect( + attrs[SemanticAttributes.AWS_DYNAMODB_TABLE_COUNT] + ).toStrictEqual(3); expect( JSON.parse(attrs[SemanticAttributes.DB_STATEMENT] as string)