Skip to content

Commit

Permalink
feat: [.NET and JS Feature Parity] Support for new AWS Resources in J…
Browse files Browse the repository at this point in the history
…S SDK (#121)

*Description of changes:*

Adding support for new AWS resources in JS SDK. Part of an ongoing
project to increase the ADOT SDK support in Node and .NET.

Changes in this PR support the exact same features as the Python
version:

aws-observability/aws-otel-python-instrumentation#265

Manual Testing:
<img width="1236" alt="Screenshot 2024-11-15 at 1 36 01 PM"
src="https://github.com/user-attachments/assets/7480f865-2927-4376-91b5-76048b0bcdf4">
<img width="1234" alt="Screenshot 2024-11-15 at 2 07 05 PM"
src="https://github.com/user-attachments/assets/1a5d00b4-9ac8-45e9-b51d-02d7c669f5f1">
<img width="939" alt="Screenshot 2024-11-15 at 2 26 10 PM"
src="https://github.com/user-attachments/assets/120892ec-03cf-4b70-80c7-167369cd9e27">
<img width="996" alt="Screenshot 2024-11-18 at 9 47 33 AM"
src="https://github.com/user-attachments/assets/08019f4c-507c-46cf-baa0-db77a4175d02">
<img width="934" alt="Screenshot 2024-11-18 at 9 57 22 AM"
src="https://github.com/user-attachments/assets/3fb79fa9-689f-4361-b671-79e23c68193d">
<img width="852" alt="Screenshot 2024-11-18 at 10 00 34 AM"
src="https://github.com/user-attachments/assets/bde63f88-cdbc-43c9-aa16-068790556ebe">

Unit Tests for Instrumentation Patches and Metric Attribute Generators:

<img width="1070" alt="image"
src="https://github.com/user-attachments/assets/df01814c-49fb-4561-879b-c88cedb35e5c">

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
  • Loading branch information
liustve authored Dec 16, 2024
1 parent a9375ff commit c58112e
Show file tree
Hide file tree
Showing 14 changed files with 1,641 additions and 225 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@
"@aws-sdk/client-bedrock-agent-runtime": "3.632.0",
"@aws-sdk/client-bedrock-runtime": "3.632.0",
"@aws-sdk/client-kinesis": "3.632.0",
"@aws-sdk/client-lambda": "^3.632.0",
"@aws-sdk/client-s3": "3.632.0",
"@aws-sdk/client-secrets-manager": "^3.632.0",
"@aws-sdk/client-sfn": "^3.632.0",
"@aws-sdk/client-sns": "^3.632.0",
"@opentelemetry/contrib-test-utils": "0.41.0",
"@types/mocha": "7.0.2",
"@types/node": "18.6.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const AWS_ATTRIBUTE_KEYS: { [key: string]: string } = {
AWS_REMOTE_RESOURCE_IDENTIFIER: 'aws.remote.resource.identifier',
AWS_SDK_DESCENDANT: 'aws.sdk.descendant',
AWS_CONSUMER_PARENT_SPAN_KIND: 'aws.consumer.parent.span.kind',
AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER: 'aws.remote.resource.cfn.primary.identifier',

AWS_REMOTE_TARGET: 'aws.remote.target',
AWS_REMOTE_DB_USER: 'aws.remote.db.user',
Expand All @@ -35,4 +36,12 @@ export const AWS_ATTRIBUTE_KEYS: { [key: string]: string } = {
AWS_BEDROCK_KNOWLEDGE_BASE_ID: 'aws.bedrock.knowledge_base.id',
AWS_BEDROCK_AGENT_ID: 'aws.bedrock.agent.id',
AWS_BEDROCK_GUARDRAIL_ID: 'aws.bedrock.guardrail.id',
AWS_BEDROCK_GUARDRAIL_ARN: 'aws.bedrock.guardrail.arn',
AWS_SNS_TOPIC_ARN: 'aws.sns.topic.arn',
AWS_SECRETSMANAGER_SECRET_ARN: 'aws.secretsmanager.secret.arn',
AWS_STEPFUNCTIONS_STATEMACHINE_ARN: 'aws.stepfunctions.state_machine.arn',
AWS_STEPFUNCTIONS_ACTIVITY_ARN: 'aws.stepfunctions.activity.arn',
AWS_LAMBDA_FUNCTION_NAME: 'aws.lambda.function.name',
AWS_LAMBDA_RESOURCE_MAPPING_ID: 'aws.lambda.resource_mapping.id',
AWS_LAMBDA_FUNCTION_ARN: 'aws.lambda.function.arn',
};
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ const NORMALIZED_DYNAMO_DB_SERVICE_NAME: string = 'AWS::DynamoDB';
const NORMALIZED_KINESIS_SERVICE_NAME: string = 'AWS::Kinesis';
const NORMALIZED_S3_SERVICE_NAME: string = 'AWS::S3';
const NORMALIZED_SQS_SERVICE_NAME: string = 'AWS::SQS';
const NORMALIZED_SNS_SERVICE_NAME: string = 'AWS::SNS';
const NORMALIZED_SECRETSMANAGER_SERVICE_NAME = 'AWS::SecretsManager';
const NORMALIZED_STEPFUNCTIONS_SERVICE_NAME = 'AWS::StepFunctions';
const NORMALIZED_LAMBDA_SERVICE_NAME = 'AWS::Lambda';
const NORMALIZED_BEDROCK_SERVICE_NAME: string = 'AWS::Bedrock';
const NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME: string = 'AWS::BedrockRuntime';

Expand Down Expand Up @@ -330,6 +334,8 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
BedrockAgent: NORMALIZED_BEDROCK_SERVICE_NAME,
BedrockAgentRuntime: NORMALIZED_BEDROCK_SERVICE_NAME,
BedrockRuntime: NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME,
SecretsManager: NORMALIZED_SECRETSMANAGER_SERVICE_NAME,
SFN: NORMALIZED_STEPFUNCTIONS_SERVICE_NAME,
};
return awsSdkServiceMapping[serviceName] || 'AWS::' + serviceName;
}
Expand All @@ -350,6 +356,7 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
private static setRemoteResourceTypeAndIdentifier(span: ReadableSpan, attributes: Attributes): void {
let remoteResourceType: AttributeValue | undefined;
let remoteResourceIdentifier: AttributeValue | undefined;
let cloudFormationIdentifier: AttributeValue | undefined;

if (AwsSpanProcessingUtil.isAwsSDKSpan(span)) {
const awsTableNames: AttributeValue | undefined = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES];
Expand All @@ -370,16 +377,56 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_S3_BUCKET]
);
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN)) {
const snsArn = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN];

remoteResourceType = NORMALIZED_SNS_SERVICE_NAME + '::Topic';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
this.extractResourceNameFromArn(snsArn)
);
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(snsArn);
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN)) {
const secretsArn = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN];

remoteResourceType = NORMALIZED_SECRETSMANAGER_SERVICE_NAME + '::Secret';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
this.extractResourceNameFromArn(secretsArn)
);
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(secretsArn);
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN)) {
const stateMachineArn = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN];

remoteResourceType = NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + '::StateMachine';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
this.extractResourceNameFromArn(stateMachineArn)
);
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(stateMachineArn);
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN)) {
const activityArn = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN];

remoteResourceType = NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + '::Activity';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
this.extractResourceNameFromArn(activityArn)
);
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(activityArn);
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID)) {
remoteResourceType = NORMALIZED_LAMBDA_SERVICE_NAME + '::EventSourceMapping';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID]
);
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME)) {
remoteResourceType = NORMALIZED_SQS_SERVICE_NAME + '::Queue';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME]
);
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL)) {
remoteResourceType = NORMALIZED_SQS_SERVICE_NAME + '::Queue';
remoteResourceIdentifier = SqsUrlParser.getQueueName(
AwsMetricAttributeGenerator.escapeDelimiters(span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL])
const sqsQueueUrl = AwsMetricAttributeGenerator.escapeDelimiters(
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL]
);

remoteResourceType = NORMALIZED_SQS_SERVICE_NAME + '::Queue';
remoteResourceIdentifier = SqsUrlParser.getQueueName(sqsQueueUrl);
cloudFormationIdentifier = sqsQueueUrl;
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_AGENT_ID)) {
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::Agent';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
Expand All @@ -390,11 +437,17 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID]
);
cloudFormationIdentifier = `${AwsMetricAttributeGenerator.escapeDelimiters(
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID]
)}|${remoteResourceIdentifier}`;
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID)) {
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::Guardrail';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID]
);
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN]
);
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID)) {
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::KnowledgeBase';
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
Expand All @@ -414,6 +467,14 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
if (remoteResourceType !== undefined && remoteResourceIdentifier !== undefined) {
attributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_TYPE] = remoteResourceType;
attributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_IDENTIFIER] = remoteResourceIdentifier;

if (AwsSpanProcessingUtil.isAwsSDKSpan(span)) {
if (cloudFormationIdentifier === undefined) {
cloudFormationIdentifier = remoteResourceIdentifier;
}

attributes[AWS_ATTRIBUTE_KEYS.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER] = cloudFormationIdentifier;
}
}
}

Expand Down Expand Up @@ -532,6 +593,16 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
return input.split('^').join('^^').split('|').join('^|');
}

// Extracts the name of the resource from an arn
private static extractResourceNameFromArn(attribute: AttributeValue | undefined): string | undefined {
if (typeof attribute === 'string' && attribute.startsWith('arn:aws:')) {
const split = attribute.split(':');
return split[split.length - 1];
}

return undefined;
}

/** Span kind is needed for differentiating metrics in the EMF exporter */
private static setSpanKindForService(span: ReadableSpan, attributes: Attributes): void {
let spanKind: string = SpanKind[span.kind];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const AGENT_ID: string = 'agentId';
const KNOWLEDGE_BASE_ID: string = 'knowledgeBaseId';
const DATA_SOURCE_ID: string = 'dataSourceId';
const GUARDRAIL_ID: string = 'guardrailId';
const GUARDRAIL_ARN: string = 'guardrailArn';
const MODEL_ID: string = 'modelId';
const AWS_BEDROCK_SYSTEM: string = 'aws.bedrock';

Expand Down Expand Up @@ -60,6 +61,7 @@ const knowledgeBaseOperationAttributeKeyMapping = {
};
const dataSourceOperationAttributeKeyMapping = {
[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID]: DATA_SOURCE_ID,
[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID]: KNOWLEDGE_BASE_ID,
};

// This map allows us to get all relevant attribute key mappings for a given operation
Expand Down Expand Up @@ -182,10 +184,15 @@ export class BedrockServiceExtension implements ServiceExtension {
};
}
responseHook(response: NormalizedResponse, span: Span, tracer: Tracer, config: AwsSdkInstrumentationConfig): void {
const guardrail_id = response.data[GUARDRAIL_ID];
const guardrailId = response.data[GUARDRAIL_ID];
const guardrailArn = response.data[GUARDRAIL_ARN];

if (guardrailId) {
span.setAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, guardrailId);
}

if (guardrail_id) {
span.setAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, guardrail_id);
if (guardrailArn) {
span.setAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, guardrailArn);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { Attributes, Span, SpanKind, Tracer } from '@opentelemetry/api';
import {
AwsSdkInstrumentationConfig,
NormalizedRequest,
NormalizedResponse,
} from '@opentelemetry/instrumentation-aws-sdk';
import { AWS_ATTRIBUTE_KEYS } from '../../../aws-attribute-keys';
import { RequestMetadata, ServiceExtension } from '../../../third-party/otel/aws/services/ServiceExtension';

export class SecretsManagerServiceExtension implements ServiceExtension {
requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata {
const secretId = request.commandInput?.SecretId;

const spanKind: SpanKind = SpanKind.CLIENT;
let spanName: string | undefined;

const spanAttributes: Attributes = {};

if (typeof secretId === 'string' && secretId.startsWith('arn:aws:secretsmanager:')) {
spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN] = secretId;
}

const isIncoming = false;

return {
isIncoming,
spanAttributes,
spanKind,
spanName,
};
}

responseHook(response: NormalizedResponse, span: Span, tracer: Tracer, config: AwsSdkInstrumentationConfig): void {
const secretArn = response.data.ARN;

if (secretArn) {
span.setAttribute(AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, secretArn);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { Attributes, SpanKind } from '@opentelemetry/api';
import { AwsSdkInstrumentationConfig, NormalizedRequest } from '@opentelemetry/instrumentation-aws-sdk';
import { AWS_ATTRIBUTE_KEYS } from '../../../aws-attribute-keys';
import { RequestMetadata, ServiceExtension } from '../../../third-party/otel/aws/services/ServiceExtension';

export class StepFunctionsServiceExtension implements ServiceExtension {
requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata {
const stateMachineArn = request.commandInput?.stateMachineArn;
const activityArn = request.commandInput?.activityArn;

const spanKind: SpanKind = SpanKind.CLIENT;
let spanName: string | undefined;

const spanAttributes: Attributes = {};

if (stateMachineArn) {
spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN] = stateMachineArn;
}

if (activityArn) {
spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN] = activityArn;
}

const isIncoming = false;

return {
isIncoming,
spanAttributes,
spanKind,
spanName,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ import {
} from './aws/services/bedrock';
import { KinesisServiceExtension } from './aws/services/kinesis';
import { S3ServiceExtension } from './aws/services/s3';
import { AwsLambdaInstrumentationPatch } from './extended-instrumentations/aws-lambda';
import { SecretsManagerServiceExtension } from './aws/services/secretsmanager';
import { StepFunctionsServiceExtension } from './aws/services/step-functions';
import { InstrumentationConfigMap } from '@opentelemetry/auto-instrumentations-node';
import { AwsSdkInstrumentationExtended } from './extended-instrumentations/aws-sdk-instrumentation-extended';
import { AwsLambdaInstrumentationPatch } from './extended-instrumentations/aws-lambda';

export const traceContextEnvironmentKey = '_X_AMZN_TRACE_ID';
const awsPropagator = new AWSXRayPropagator();
Expand Down Expand Up @@ -68,11 +70,15 @@ export function applyInstrumentationPatches(
if (services) {
services.set('S3', new S3ServiceExtension());
services.set('Kinesis', new KinesisServiceExtension());
services.set('SecretsManager', new SecretsManagerServiceExtension());
services.set('SFN', new StepFunctionsServiceExtension());
services.set('Bedrock', new BedrockServiceExtension());
services.set('BedrockAgent', new BedrockAgentServiceExtension());
services.set('BedrockAgentRuntime', new BedrockAgentRuntimeServiceExtension());
services.set('BedrockRuntime', new BedrockRuntimeServiceExtension());
patchSqsServiceExtension(services.get('SQS'));
patchSnsServiceExtension(services.get('SNS'));
patchLambdaServiceExtension(services.get('Lambda'));
}
} else if (instrumentation.instrumentationName === '@opentelemetry/instrumentation-aws-lambda') {
diag.debug('Overriding aws lambda instrumentation');
Expand Down Expand Up @@ -154,3 +160,65 @@ function patchSqsServiceExtension(sqsServiceExtension: any): void {
sqsServiceExtension.requestPreSpanHook = patchedRequestPreSpanHook;
}
}

/*
* This patch extends the existing upstream extension for SNS. Extensions allow for custom logic for adding
* service-specific information to spans, such as attributes. Specifically, we are adding logic to add
* `aws.sns.topic.arn` attribute, to be used to generate RemoteTarget and achieve parity with the Java/Python instrumentation.
*
*
* @param snsServiceExtension SNS Service Extension obtained the service extension list from the AWS SDK OTel Instrumentation
*/
function patchSnsServiceExtension(snsServiceExtension: any): void {
if (snsServiceExtension) {
const requestPreSpanHook = snsServiceExtension.requestPreSpanHook;
snsServiceExtension._requestPreSpanHook = requestPreSpanHook;

const patchedRequestPreSpanHook = (
request: NormalizedRequest,
_config: AwsSdkInstrumentationConfig
): RequestMetadata => {
const requestMetadata: RequestMetadata = snsServiceExtension._requestPreSpanHook(request, _config);
if (requestMetadata.spanAttributes) {
const topicArn = request.commandInput?.TopicArn;
if (topicArn) {
requestMetadata.spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN] = topicArn;
}
}
return requestMetadata;
};

snsServiceExtension.requestPreSpanHook = patchedRequestPreSpanHook;
}
}

/*
* This patch extends the existing upstream extension for Lambda. Extensions allow for custom logic for adding
* service-specific information to spans, such as attributes. Specifically, we are adding logic to add
* `aws.lambda.resource_mapping.id` attribute, to be used to generate RemoteTarget and achieve parity with the Java/Python instrumentation.
*
*
* @param lambdaServiceExtension Lambda Service Extension obtained the service extension list from the AWS SDK OTel Instrumentation
*/
function patchLambdaServiceExtension(lambdaServiceExtension: any): void {
if (lambdaServiceExtension) {
const requestPreSpanHook = lambdaServiceExtension.requestPreSpanHook;
lambdaServiceExtension._requestPreSpanHook = requestPreSpanHook;

const patchedRequestPreSpanHook = (
request: NormalizedRequest,
_config: AwsSdkInstrumentationConfig
): RequestMetadata => {
const requestMetadata: RequestMetadata = lambdaServiceExtension._requestPreSpanHook(request, _config);
if (requestMetadata.spanAttributes) {
const resourceMappingId = request.commandInput?.UUID;
if (resourceMappingId) {
requestMetadata.spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID] = resourceMappingId;
}
}
return requestMetadata;
};

lambdaServiceExtension.requestPreSpanHook = patchedRequestPreSpanHook;
}
}
Loading

0 comments on commit c58112e

Please sign in to comment.