Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [.NET and JS Feature Parity] Support for new AWS Resources in JS SDK #121

Merged
merged 55 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
7e70a46
Merge pull request #1 from aws-observability/main
liustve Nov 1, 2024
f168ced
initial start for sns and secretsmanager
liustve Nov 13, 2024
85747f2
secretsmanager attributes added
liustve Nov 14, 2024
7ab675f
added step functions and lambda
liustve Nov 15, 2024
d684596
added instrumentation patching unit tests + linting fix
liustve Nov 18, 2024
e95134b
metric attribute generator tests
liustve Nov 18, 2024
2249fa0
lint fix
liustve Nov 18, 2024
d22fd56
Merge branch 'main' into aws_resource_support
liustve Nov 18, 2024
d95b754
prettier fix
liustve Nov 18, 2024
d5077e0
Merge branch 'aws_resource_support' of https://github.com/liustve/aws…
liustve Nov 18, 2024
be8ba40
lint fix
liustve Nov 18, 2024
581db39
lint fix
liustve Nov 18, 2024
9aca704
added guardrail arn to bedrock
liustve Nov 19, 2024
d8bffd5
fixed cloudformation primary id attribute
liustve Nov 19, 2024
2e130d5
Merge branch 'main' of https://github.com/liustve/aws-otel-js-instrum…
liustve Nov 22, 2024
d9b811e
Merge branch 'main' into aws_resource_support
liustve Nov 22, 2024
e387583
removed lambda function name/arn attributes and tests
liustve Nov 26, 2024
f2cd6a2
Merge branch 'aws_resource_support' of https://github.com/liustve/aws…
liustve Nov 26, 2024
9a9a7d6
lint fix
liustve Nov 26, 2024
7a9f4cf
removed lambda and sns and added them to instrumentation patch as ext…
liustve Nov 27, 2024
229ab21
lint fix
liustve Nov 27, 2024
57ed9b4
removed lambda and sns tests, addressed PR comments
liustve Nov 28, 2024
756de5b
resolving package dependency conflicts
liustve Nov 28, 2024
a17cd30
Merge branch 'aws-observability:main' into aws_resource_support
liustve Nov 28, 2024
4687a2a
adding dependencies
liustve Nov 28, 2024
478b1d8
Merge branch 'aws_resource_support' of https://github.com/liustve/aws…
liustve Nov 28, 2024
76a2acb
changed stepfunctions to SFN
liustve Nov 29, 2024
9c2ba36
lint fix
liustve Nov 29, 2024
c3e4e6b
mapped SFN to StepFunctions
liustve Nov 29, 2024
1e3ff4f
added '===' and removed redundant normalized sns mapping
liustve Nov 30, 2024
9d8f39a
rerun
liustve Dec 2, 2024
e3c3a3e
only setting cfn attribute for aws resources
liustve Dec 2, 2024
9236434
linting fix
liustve Dec 2, 2024
46afde1
Merge branch 'aws_resource_support' of https://github.com/liustve/aws…
liustve Dec 2, 2024
63a61ad
Merge branch 'aws-observability:main' into main
liustve Dec 2, 2024
dedaebe
added bedrock agent id cfa and sqs queue url
liustve Dec 2, 2024
2ca20b9
setting mysql2 version to 3.11.4
liustve Dec 3, 2024
5bb0d04
Merge branch 'main' into aws_resource_support
liustve Dec 3, 2024
9a111dd
misplaced cfn attribute
liustve Dec 3, 2024
818e0d8
merge conflict
liustve Dec 3, 2024
a22c3f0
Merge branch 'aws_resource_support' of https://github.com/liustve/aws…
liustve Dec 3, 2024
a5b97b6
added knowledge base id to span
liustve Dec 3, 2024
99db1d8
rerun
liustve Dec 3, 2024
f094a39
formatting
liustve Dec 4, 2024
1a79678
Merge branch 'main' of https://github.com/liustve/aws-otel-js-instrum…
liustve Dec 5, 2024
27468e5
Merge branch 'aws-observability:main' into main
liustve Dec 5, 2024
bbdb0df
Merge branch 'aws-observability:main' into aws_resource_support
liustve Dec 5, 2024
d66cd10
fixed cfa logic and getdatasource test
liustve Dec 6, 2024
164c863
fixed cfa logic and getdatasource test
liustve Dec 6, 2024
b2633af
lint fix
liustve Dec 6, 2024
cfe0bd3
Merge branch 'main' into aws_resource_support
liustve Dec 9, 2024
0f51034
Merge branch 'main' into aws_resource_support
liustve Dec 16, 2024
03aa3b5
Merge branch 'aws-observability:main' into main
liustve Dec 16, 2024
35785a1
merge main
liustve Dec 16, 2024
461e0bb
merge conflict fix
liustve Dec 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,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',
};
liustve marked this conversation as resolved.
Show resolved Hide resolved
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) {
liustve marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -26,6 +26,8 @@ import {
import { KinesisServiceExtension } from './aws/services/kinesis';
import { S3ServiceExtension } from './aws/services/s3';
import { AwsLambdaInstrumentationPatch } from './aws/services/aws-lambda';
import { SecretsManagerServiceExtension } from './aws/services/secretsmanager';
import { StepFunctionsServiceExtension } from './aws/services/step-functions';

export const traceContextEnvironmentKey = '_X_AMZN_TRACE_ID';
const awsPropagator = new AWSXRayPropagator();
Expand Down Expand Up @@ -57,11 +59,15 @@ export function applyInstrumentationPatches(instrumentations: Instrumentation[])
if (services) {
services.set('S3', new S3ServiceExtension());
services.set('Kinesis', new KinesisServiceExtension());
services.set('SecretsManager', new SecretsManagerServiceExtension());
services.set('SFN', new StepFunctionsServiceExtension());
jj22ee marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -143,3 +149,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