Skip to content

Commit f553f21

Browse files
committed
fixed merge conflict
2 parents acc770f + aef6b27 commit f553f21

File tree

19 files changed

+2378
-252
lines changed

19 files changed

+2378
-252
lines changed

aws-distro-opentelemetry-node-autoinstrumentation/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@
7373
"@aws-sdk/client-bedrock-agent-runtime": "3.632.0",
7474
"@aws-sdk/client-bedrock-runtime": "3.632.0",
7575
"@aws-sdk/client-kinesis": "3.632.0",
76+
"@aws-sdk/client-lambda": "^3.632.0",
7677
"@aws-sdk/client-s3": "3.632.0",
78+
"@aws-sdk/client-secrets-manager": "^3.632.0",
79+
"@aws-sdk/client-sfn": "^3.632.0",
80+
"@aws-sdk/client-sns": "^3.632.0",
7781
"@opentelemetry/contrib-test-utils": "0.41.0",
7882
"@types/mocha": "7.0.2",
7983
"@types/node": "18.6.5",

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-attribute-keys.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const AWS_ATTRIBUTE_KEYS: { [key: string]: string } = {
1414
AWS_REMOTE_RESOURCE_IDENTIFIER: 'aws.remote.resource.identifier',
1515
AWS_SDK_DESCENDANT: 'aws.sdk.descendant',
1616
AWS_CONSUMER_PARENT_SPAN_KIND: 'aws.consumer.parent.span.kind',
17+
AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER: 'aws.remote.resource.cfn.primary.identifier',
1718

1819
AWS_REMOTE_TARGET: 'aws.remote.target',
1920
AWS_REMOTE_DB_USER: 'aws.remote.db.user',
@@ -35,4 +36,12 @@ export const AWS_ATTRIBUTE_KEYS: { [key: string]: string } = {
3536
AWS_BEDROCK_KNOWLEDGE_BASE_ID: 'aws.bedrock.knowledge_base.id',
3637
AWS_BEDROCK_AGENT_ID: 'aws.bedrock.agent.id',
3738
AWS_BEDROCK_GUARDRAIL_ID: 'aws.bedrock.guardrail.id',
39+
AWS_BEDROCK_GUARDRAIL_ARN: 'aws.bedrock.guardrail.arn',
40+
AWS_SNS_TOPIC_ARN: 'aws.sns.topic.arn',
41+
AWS_SECRETSMANAGER_SECRET_ARN: 'aws.secretsmanager.secret.arn',
42+
AWS_STEPFUNCTIONS_STATEMACHINE_ARN: 'aws.stepfunctions.state_machine.arn',
43+
AWS_STEPFUNCTIONS_ACTIVITY_ARN: 'aws.stepfunctions.activity.arn',
44+
AWS_LAMBDA_FUNCTION_NAME: 'aws.lambda.function.name',
45+
AWS_LAMBDA_RESOURCE_MAPPING_ID: 'aws.lambda.resource_mapping.id',
46+
AWS_LAMBDA_FUNCTION_ARN: 'aws.lambda.function.arn',
3847
};

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ const NORMALIZED_DYNAMO_DB_SERVICE_NAME: string = 'AWS::DynamoDB';
5555
const NORMALIZED_KINESIS_SERVICE_NAME: string = 'AWS::Kinesis';
5656
const NORMALIZED_S3_SERVICE_NAME: string = 'AWS::S3';
5757
const NORMALIZED_SQS_SERVICE_NAME: string = 'AWS::SQS';
58+
const NORMALIZED_SNS_SERVICE_NAME: string = 'AWS::SNS';
59+
const NORMALIZED_SECRETSMANAGER_SERVICE_NAME = 'AWS::SecretsManager';
60+
const NORMALIZED_STEPFUNCTIONS_SERVICE_NAME = 'AWS::StepFunctions';
61+
const NORMALIZED_LAMBDA_SERVICE_NAME = 'AWS::Lambda';
5862
const NORMALIZED_BEDROCK_SERVICE_NAME: string = 'AWS::Bedrock';
5963
const NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME: string = 'AWS::BedrockRuntime';
6064

@@ -330,6 +334,8 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
330334
BedrockAgent: NORMALIZED_BEDROCK_SERVICE_NAME,
331335
BedrockAgentRuntime: NORMALIZED_BEDROCK_SERVICE_NAME,
332336
BedrockRuntime: NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME,
337+
SecretsManager: NORMALIZED_SECRETSMANAGER_SERVICE_NAME,
338+
SFN: NORMALIZED_STEPFUNCTIONS_SERVICE_NAME,
333339
};
334340
return awsSdkServiceMapping[serviceName] || 'AWS::' + serviceName;
335341
}
@@ -350,6 +356,7 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
350356
private static setRemoteResourceTypeAndIdentifier(span: ReadableSpan, attributes: Attributes): void {
351357
let remoteResourceType: AttributeValue | undefined;
352358
let remoteResourceIdentifier: AttributeValue | undefined;
359+
let cloudFormationIdentifier: AttributeValue | undefined;
353360

354361
if (AwsSpanProcessingUtil.isAwsSDKSpan(span)) {
355362
const awsTableNames: AttributeValue | undefined = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES];
@@ -370,16 +377,56 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
370377
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
371378
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_S3_BUCKET]
372379
);
380+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN)) {
381+
const snsArn = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN];
382+
383+
remoteResourceType = NORMALIZED_SNS_SERVICE_NAME + '::Topic';
384+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
385+
this.extractResourceNameFromArn(snsArn)
386+
);
387+
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(snsArn);
388+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN)) {
389+
const secretsArn = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN];
390+
391+
remoteResourceType = NORMALIZED_SECRETSMANAGER_SERVICE_NAME + '::Secret';
392+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
393+
this.extractResourceNameFromArn(secretsArn)
394+
);
395+
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(secretsArn);
396+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN)) {
397+
const stateMachineArn = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN];
398+
399+
remoteResourceType = NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + '::StateMachine';
400+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
401+
this.extractResourceNameFromArn(stateMachineArn)
402+
);
403+
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(stateMachineArn);
404+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN)) {
405+
const activityArn = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN];
406+
407+
remoteResourceType = NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + '::Activity';
408+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
409+
this.extractResourceNameFromArn(activityArn)
410+
);
411+
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(activityArn);
412+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID)) {
413+
remoteResourceType = NORMALIZED_LAMBDA_SERVICE_NAME + '::EventSourceMapping';
414+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
415+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID]
416+
);
373417
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME)) {
374418
remoteResourceType = NORMALIZED_SQS_SERVICE_NAME + '::Queue';
375419
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
376420
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME]
377421
);
378422
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL)) {
379-
remoteResourceType = NORMALIZED_SQS_SERVICE_NAME + '::Queue';
380-
remoteResourceIdentifier = SqsUrlParser.getQueueName(
381-
AwsMetricAttributeGenerator.escapeDelimiters(span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL])
423+
const sqsQueueUrl = AwsMetricAttributeGenerator.escapeDelimiters(
424+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL]
382425
);
426+
427+
remoteResourceType = NORMALIZED_SQS_SERVICE_NAME + '::Queue';
428+
remoteResourceIdentifier = SqsUrlParser.getQueueName(sqsQueueUrl);
429+
cloudFormationIdentifier = sqsQueueUrl;
383430
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_AGENT_ID)) {
384431
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::Agent';
385432
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
@@ -390,11 +437,17 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
390437
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
391438
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID]
392439
);
440+
cloudFormationIdentifier = `${AwsMetricAttributeGenerator.escapeDelimiters(
441+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID]
442+
)}|${remoteResourceIdentifier}`;
393443
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID)) {
394444
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::Guardrail';
395445
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
396446
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID]
397447
);
448+
cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
449+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN]
450+
);
398451
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID)) {
399452
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::KnowledgeBase';
400453
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
@@ -414,6 +467,14 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
414467
if (remoteResourceType !== undefined && remoteResourceIdentifier !== undefined) {
415468
attributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_TYPE] = remoteResourceType;
416469
attributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_IDENTIFIER] = remoteResourceIdentifier;
470+
471+
if (AwsSpanProcessingUtil.isAwsSDKSpan(span)) {
472+
if (cloudFormationIdentifier === undefined) {
473+
cloudFormationIdentifier = remoteResourceIdentifier;
474+
}
475+
476+
attributes[AWS_ATTRIBUTE_KEYS.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER] = cloudFormationIdentifier;
477+
}
417478
}
418479
}
419480

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

596+
// Extracts the name of the resource from an arn
597+
private static extractResourceNameFromArn(attribute: AttributeValue | undefined): string | undefined {
598+
if (typeof attribute === 'string' && attribute.startsWith('arn:aws:')) {
599+
const split = attribute.split(':');
600+
return split[split.length - 1];
601+
}
602+
603+
return undefined;
604+
}
605+
535606
/** Span kind is needed for differentiating metrics in the EMF exporter */
536607
private static setSpanKindForService(span: ReadableSpan, attributes: Attributes): void {
537608
let spanKind: string = SpanKind[span.kind];

aws-distro-opentelemetry-node-autoinstrumentation/src/patches/aws/services/bedrock.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const AGENT_ID: string = 'agentId';
1515
const KNOWLEDGE_BASE_ID: string = 'knowledgeBaseId';
1616
const DATA_SOURCE_ID: string = 'dataSourceId';
1717
const GUARDRAIL_ID: string = 'guardrailId';
18+
const GUARDRAIL_ARN: string = 'guardrailArn';
1819
const MODEL_ID: string = 'modelId';
1920
const AWS_BEDROCK_SYSTEM: string = 'aws.bedrock';
2021

@@ -60,6 +61,7 @@ const knowledgeBaseOperationAttributeKeyMapping = {
6061
};
6162
const dataSourceOperationAttributeKeyMapping = {
6263
[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID]: DATA_SOURCE_ID,
64+
[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID]: KNOWLEDGE_BASE_ID,
6365
};
6466

6567
// This map allows us to get all relevant attribute key mappings for a given operation
@@ -182,10 +184,15 @@ export class BedrockServiceExtension implements ServiceExtension {
182184
};
183185
}
184186
responseHook(response: NormalizedResponse, span: Span, tracer: Tracer, config: AwsSdkInstrumentationConfig): void {
185-
const guardrail_id = response.data[GUARDRAIL_ID];
187+
const guardrailId = response.data[GUARDRAIL_ID];
188+
const guardrailArn = response.data[GUARDRAIL_ARN];
189+
190+
if (guardrailId) {
191+
span.setAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, guardrailId);
192+
}
186193

187-
if (guardrail_id) {
188-
span.setAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, guardrail_id);
194+
if (guardrailArn) {
195+
span.setAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, guardrailArn);
189196
}
190197
}
191198
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Attributes, Span, SpanKind, Tracer } from '@opentelemetry/api';
5+
import {
6+
AwsSdkInstrumentationConfig,
7+
NormalizedRequest,
8+
NormalizedResponse,
9+
} from '@opentelemetry/instrumentation-aws-sdk';
10+
import { AWS_ATTRIBUTE_KEYS } from '../../../aws-attribute-keys';
11+
import { RequestMetadata, ServiceExtension } from '../../../third-party/otel/aws/services/ServiceExtension';
12+
13+
export class SecretsManagerServiceExtension implements ServiceExtension {
14+
requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata {
15+
const secretId = request.commandInput?.SecretId;
16+
17+
const spanKind: SpanKind = SpanKind.CLIENT;
18+
let spanName: string | undefined;
19+
20+
const spanAttributes: Attributes = {};
21+
22+
if (typeof secretId === 'string' && secretId.startsWith('arn:aws:secretsmanager:')) {
23+
spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN] = secretId;
24+
}
25+
26+
const isIncoming = false;
27+
28+
return {
29+
isIncoming,
30+
spanAttributes,
31+
spanKind,
32+
spanName,
33+
};
34+
}
35+
36+
responseHook(response: NormalizedResponse, span: Span, tracer: Tracer, config: AwsSdkInstrumentationConfig): void {
37+
const secretArn = response.data.ARN;
38+
39+
if (secretArn) {
40+
span.setAttribute(AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, secretArn);
41+
}
42+
}
43+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Attributes, SpanKind } from '@opentelemetry/api';
5+
import { AwsSdkInstrumentationConfig, NormalizedRequest } from '@opentelemetry/instrumentation-aws-sdk';
6+
import { AWS_ATTRIBUTE_KEYS } from '../../../aws-attribute-keys';
7+
import { RequestMetadata, ServiceExtension } from '../../../third-party/otel/aws/services/ServiceExtension';
8+
9+
export class StepFunctionsServiceExtension implements ServiceExtension {
10+
requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata {
11+
const stateMachineArn = request.commandInput?.stateMachineArn;
12+
const activityArn = request.commandInput?.activityArn;
13+
14+
const spanKind: SpanKind = SpanKind.CLIENT;
15+
let spanName: string | undefined;
16+
17+
const spanAttributes: Attributes = {};
18+
19+
if (stateMachineArn) {
20+
spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN] = stateMachineArn;
21+
}
22+
23+
if (activityArn) {
24+
spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN] = activityArn;
25+
}
26+
27+
const isIncoming = false;
28+
29+
return {
30+
isIncoming,
31+
spanAttributes,
32+
spanKind,
33+
spanName,
34+
};
35+
}
36+
}

aws-distro-opentelemetry-node-autoinstrumentation/src/patches/instrumentation-patch.ts

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ import {
2525
} from './aws/services/bedrock';
2626
import { KinesisServiceExtension } from './aws/services/kinesis';
2727
import { S3ServiceExtension } from './aws/services/s3';
28-
import { AwsLambdaInstrumentationPatch } from './extended-instrumentations/aws-lambda';
28+
import { SecretsManagerServiceExtension } from './aws/services/secretsmanager';
29+
import { StepFunctionsServiceExtension } from './aws/services/step-functions';
2930
import { InstrumentationConfigMap } from '@opentelemetry/auto-instrumentations-node';
3031
import { AwsSdkInstrumentationExtended } from './extended-instrumentations/aws-sdk-instrumentation-extended';
32+
import { AwsLambdaInstrumentationPatch } from './extended-instrumentations/aws-lambda';
3133

3234
export const traceContextEnvironmentKey = '_X_AMZN_TRACE_ID';
3335
const awsPropagator = new AWSXRayPropagator();
@@ -68,11 +70,15 @@ export function applyInstrumentationPatches(
6870
if (services) {
6971
services.set('S3', new S3ServiceExtension());
7072
services.set('Kinesis', new KinesisServiceExtension());
73+
services.set('SecretsManager', new SecretsManagerServiceExtension());
74+
services.set('SFN', new StepFunctionsServiceExtension());
7175
services.set('Bedrock', new BedrockServiceExtension());
7276
services.set('BedrockAgent', new BedrockAgentServiceExtension());
7377
services.set('BedrockAgentRuntime', new BedrockAgentRuntimeServiceExtension());
7478
services.set('BedrockRuntime', new BedrockRuntimeServiceExtension());
7579
patchSqsServiceExtension(services.get('SQS'));
80+
patchSnsServiceExtension(services.get('SNS'));
81+
patchLambdaServiceExtension(services.get('Lambda'));
7682
}
7783
} else if (instrumentation.instrumentationName === '@opentelemetry/instrumentation-aws-lambda') {
7884
diag.debug('Overriding aws lambda instrumentation');
@@ -154,3 +160,65 @@ function patchSqsServiceExtension(sqsServiceExtension: any): void {
154160
sqsServiceExtension.requestPreSpanHook = patchedRequestPreSpanHook;
155161
}
156162
}
163+
164+
/*
165+
* This patch extends the existing upstream extension for SNS. Extensions allow for custom logic for adding
166+
* service-specific information to spans, such as attributes. Specifically, we are adding logic to add
167+
* `aws.sns.topic.arn` attribute, to be used to generate RemoteTarget and achieve parity with the Java/Python instrumentation.
168+
*
169+
*
170+
* @param snsServiceExtension SNS Service Extension obtained the service extension list from the AWS SDK OTel Instrumentation
171+
*/
172+
function patchSnsServiceExtension(snsServiceExtension: any): void {
173+
if (snsServiceExtension) {
174+
const requestPreSpanHook = snsServiceExtension.requestPreSpanHook;
175+
snsServiceExtension._requestPreSpanHook = requestPreSpanHook;
176+
177+
const patchedRequestPreSpanHook = (
178+
request: NormalizedRequest,
179+
_config: AwsSdkInstrumentationConfig
180+
): RequestMetadata => {
181+
const requestMetadata: RequestMetadata = snsServiceExtension._requestPreSpanHook(request, _config);
182+
if (requestMetadata.spanAttributes) {
183+
const topicArn = request.commandInput?.TopicArn;
184+
if (topicArn) {
185+
requestMetadata.spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN] = topicArn;
186+
}
187+
}
188+
return requestMetadata;
189+
};
190+
191+
snsServiceExtension.requestPreSpanHook = patchedRequestPreSpanHook;
192+
}
193+
}
194+
195+
/*
196+
* This patch extends the existing upstream extension for Lambda. Extensions allow for custom logic for adding
197+
* service-specific information to spans, such as attributes. Specifically, we are adding logic to add
198+
* `aws.lambda.resource_mapping.id` attribute, to be used to generate RemoteTarget and achieve parity with the Java/Python instrumentation.
199+
*
200+
*
201+
* @param lambdaServiceExtension Lambda Service Extension obtained the service extension list from the AWS SDK OTel Instrumentation
202+
*/
203+
function patchLambdaServiceExtension(lambdaServiceExtension: any): void {
204+
if (lambdaServiceExtension) {
205+
const requestPreSpanHook = lambdaServiceExtension.requestPreSpanHook;
206+
lambdaServiceExtension._requestPreSpanHook = requestPreSpanHook;
207+
208+
const patchedRequestPreSpanHook = (
209+
request: NormalizedRequest,
210+
_config: AwsSdkInstrumentationConfig
211+
): RequestMetadata => {
212+
const requestMetadata: RequestMetadata = lambdaServiceExtension._requestPreSpanHook(request, _config);
213+
if (requestMetadata.spanAttributes) {
214+
const resourceMappingId = request.commandInput?.UUID;
215+
if (resourceMappingId) {
216+
requestMetadata.spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID] = resourceMappingId;
217+
}
218+
}
219+
return requestMetadata;
220+
};
221+
222+
lambdaServiceExtension.requestPreSpanHook = patchedRequestPreSpanHook;
223+
}
224+
}

0 commit comments

Comments
 (0)