Skip to content

Commit

Permalink
feat(opentelemetry-instrumentation-aws-sdk): add missing spec-defined…
Browse files Browse the repository at this point in the history
… DynamoDB attributes (#1524)

* feat(opentelemetry-instrumentation-aws-sdk): add missing spec-defined DynamoDB attributes

* feat(opentelemetry-instrumentation-aws-sdk): add checks for input attributes and additional unit tests

* feat(opentelemetry-instrumentation-aws-sdk): run lint on dynamoDB unit tests

---------

Co-authored-by: Haddas Bronfman <85441461+haddasbronfman@users.noreply.github.com>
Co-authored-by: Marc Pichler <marc.pichler@dynatrace.com>
  • Loading branch information
3 people authored Jun 27, 2023
1 parent de17f77 commit f7c4324
Show file tree
Hide file tree
Showing 2 changed files with 558 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import {
} from '../types';

export class DynamodbServiceExtension implements ServiceExtension {
toArray<T>(values: T | T[]): T[] {
return Array.isArray(values) ? values : [values];
}

requestPreSpanHook(normalizedRequest: NormalizedRequest): RequestMetadata {
const spanKind: SpanKind = SpanKind.CLIENT;
let spanName: string | undefined;
Expand All @@ -41,12 +45,144 @@ 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'
) {
if (normalizedRequest.commandInput?.ConsistentRead) {
spanAttributes[SemanticAttributes.AWS_DYNAMODB_CONSISTENT_READ] =
normalizedRequest.commandInput.ConsistentRead;
}
}

if (operation === 'Query' || operation === 'Scan') {
if (normalizedRequest.commandInput?.ProjectionExpression) {
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,
Expand All @@ -73,5 +209,35 @@ export class DynamodbServiceExtension implements ServiceExtension {
);
}
}

if (response.data?.ItemCollectionMetrics) {
span.setAttribute(
SemanticAttributes.AWS_DYNAMODB_ITEM_COLLECTION_METRICS,
this.toArray(response.data.ItemCollectionMetrics).map(
(x: { [DictionaryKey: string]: any }) => JSON.stringify(x)
)
);
}

if (response.data?.TableNames) {
span.setAttribute(
SemanticAttributes.AWS_DYNAMODB_TABLE_COUNT,
response.data?.TableNames.length
);
}

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
);
}
}
}
Loading

0 comments on commit f7c4324

Please sign in to comment.