From 051bcf95dad394d734f995352373830a6afa6167 Mon Sep 17 00:00:00 2001 From: Michael He Date: Sun, 8 Jun 2025 18:28:13 +0000 Subject: [PATCH 01/15] refactor lambda support changes --- .../src/aws-metric-attribute-generator.ts | 67 ++++++++++++++----- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index fe546e27..a8a0457e 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -50,6 +50,9 @@ const _GRAPHQL_OPERATION_TYPE: string = 'graphql.operation.type'; // Special DEPENDENCY attribute value if GRAPHQL_OPERATION_TYPE attribute key is present. const GRAPHQL: string = 'graphql'; +const LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT: string = 'LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT'; +const LAMBDA_INVOKE_OPERATION: string = 'Invoke'; + // Normalized remote service names for supported AWS services const NORMALIZED_DYNAMO_DB_SERVICE_NAME: string = 'AWS::DynamoDB'; const NORMALIZED_KINESIS_SERVICE_NAME: string = 'AWS::Kinesis'; @@ -109,6 +112,7 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { AwsMetricAttributeGenerator.setEgressOperation(span, attributes); AwsMetricAttributeGenerator.setRemoteServiceAndOperation(span, attributes); AwsMetricAttributeGenerator.setRemoteResourceTypeAndIdentifier(span, attributes); + AwsMetricAttributeGenerator.setRemoteEnvironment(span, attributes); AwsMetricAttributeGenerator.setSpanKindForDependency(span, attributes); AwsMetricAttributeGenerator.setRemoteDbUser(span, attributes); @@ -336,7 +340,20 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { BedrockRuntime: NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME, SecretsManager: NORMALIZED_SECRETSMANAGER_SERVICE_NAME, SFN: NORMALIZED_STEPFUNCTIONS_SERVICE_NAME, + Lambda: NORMALIZED_LAMBDA_SERVICE_NAME, }; + + // Special handling for Lambda invoke operations + if (AwsMetricAttributeGenerator.isLambdaInvokeOperation(span)) { + // AWS_LAMBDA_FUNCTION_NAME is guaranteed to contain function name (not ARN) + // due to logic in Lambda botocore patches during instrumentation + const lambdaFunctionName = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME]; + // If Lambda name is not present, use UnknownRemoteService + // This is intentional - we want to clearly indicate when the Lambda function name + // is missing rather than falling back to a generic service name + return lambdaFunctionName ? String(lambdaFunctionName) : AwsSpanProcessingUtil.UNKNOWN_REMOTE_SERVICE; + } + return awsSdkServiceMapping[serviceName] || 'AWS::' + serviceName; } return serviceName; @@ -410,25 +427,12 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { ); cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(activityArn); } else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME)) { - // Handling downstream Lambda as a service vs. an AWS resource: - // - If the method call is "Invoke", we treat downstream Lambda as a service. - // - Otherwise, we treat it as an AWS resource. - // - // This addresses a Lambda topology issue in Application Signals. - // More context in PR: https://github.com/aws-observability/aws-otel-python-instrumentation/pull/319 - // - // NOTE: The env var LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT was introduced as part of this fix. - // It is optional and allow users to override the default value if needed. - if (AwsMetricAttributeGenerator.getRemoteOperation(span, SEMATTRS_RPC_METHOD) === 'Invoke') { - attributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_SERVICE] = AwsMetricAttributeGenerator.escapeDelimiters( - span.attributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME] - ); - - attributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_ENVIRONMENT] = `lambda:${ - process.env.LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT || 'default' - }`; - } else { + // For non-Invoke Lambda operations, treat Lambda as a resource, + // see normalize_remote_service_name for more information. + if (!AwsMetricAttributeGenerator.isLambdaInvokeOperation(span)) { remoteResourceType = NORMALIZED_LAMBDA_SERVICE_NAME + '::Function'; + // AWS_LAMBDA_FUNCTION_NAME is guaranteed to contain function name (not ARN) + // due to logic in Lambda botocore patches during instrumentation remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters( span.attributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME] ); @@ -505,6 +509,21 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { } } + private static setRemoteEnvironment(span: ReadableSpan, attributes: Attributes): void { + // We want to treat downstream Lambdas as a service rather than a resource because + // Application Signals topology map gets disconnected due to conflicting Lambda Entity + // definitions + // Additional context can be found in + // https://github.com/aws-observability/aws-otel-python-instrumentation/pull/319 + if (AwsMetricAttributeGenerator.isLambdaInvokeOperation(span)) { + let remoteEnvironment = process.env[LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT]?.trim() || ''; + if (!remoteEnvironment) { + remoteEnvironment = 'default'; + } + attributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_ENVIRONMENT] = `lambda:${remoteEnvironment}`; + } + } + /** * RemoteResourceIdentifier is populated with rule * ^[{db.name}|]?{address}[|{port}]? @@ -620,6 +639,18 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { return input.split('^').join('^^').split('|').join('^|'); } + /** + * Check if the span represents a Lambda Invoke operation. + */ + private static isLambdaInvokeOperation(span: ReadableSpan): boolean { + if (!AwsSpanProcessingUtil.isAwsSDKSpan(span)) { + return false; + } + + const rpcService = AwsMetricAttributeGenerator.getRemoteService(span, SEMATTRS_RPC_SERVICE); + return rpcService === 'Lambda' && span.attributes[SEMATTRS_RPC_METHOD] === LAMBDA_INVOKE_OPERATION; + } + // 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:')) { From 120a2a8434fd73c24d919587f7b2b6d785e3dd1b Mon Sep 17 00:00:00 2001 From: Michael He Date: Sun, 8 Jun 2025 20:23:17 +0000 Subject: [PATCH 02/15] add missing logic to extract queue url for cfn primary id if available in queue name case --- .../src/aws-metric-attribute-generator.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index a8a0457e..394955a2 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -450,6 +450,12 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters( span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME] ); + // If queue URL is also present, use it as the CloudFormation primary identifier + if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL)) { + cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters( + span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL] + ); + } } else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL)) { const sqsQueueUrl = AwsMetricAttributeGenerator.escapeDelimiters( span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL] From f90295e24283dee43b0ef5dd49f4771b279b1205 Mon Sep 17 00:00:00 2001 From: Michael He Date: Sun, 8 Jun 2025 20:55:56 +0000 Subject: [PATCH 03/15] add cfn primary id assertions in sdk client test case --- .../aws-metric-attribute-generator.test.ts | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts index c51c03ec..83fa7083 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts @@ -745,17 +745,22 @@ describe('AwsMetricAttributeGeneratorTest', () => { // them. Queue name is more reliable than queue URL, so we prefer to use name over URL. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, 'aws_queue_name'); - validateRemoteResourceAttributes('AWS::SQS::Queue', 'aws_queue_name'); + validateRemoteResourceAttributes('AWS::SQS::Queue', 'aws_queue_name', 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, undefined); // Valid queue name with invalid queue URL, we should default to using the queue name. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, 'invalidUrl'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, 'aws_queue_name'); - validateRemoteResourceAttributes('AWS::SQS::Queue', 'aws_queue_name'); + validateRemoteResourceAttributes('AWS::SQS::Queue', 'aws_queue_name', 'invalidUrl'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, undefined); + // Validate behaviour of AWS_SQS_QUEUE_URL attribute without queue name, then remove it. + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue'); + validateRemoteResourceAttributes('AWS::SQS::Queue', 'MyQueue', 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, undefined); + // Validate behaviour of AWS_KINESIS_STREAM_NAME attribute, then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, 'AWS_KINESIS_STREAM_NAME'); validateRemoteResourceAttributes('AWS::Kinesis::Stream', 'AWS_KINESIS_STREAM_NAME'); @@ -763,7 +768,7 @@ describe('AwsMetricAttributeGeneratorTest', () => { // Validate behaviour of AWS_SNS_TOPIC_ARN attribute then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, 'arn:aws:sns:us-east-1:123456789012:testTopic'); - validateRemoteResourceAttributes('AWS::SNS::Topic', 'testTopic'); + validateRemoteResourceAttributes('AWS::SNS::Topic', 'testTopic', 'arn:aws:sns:us-east-1:123456789012:testTopic'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, undefined); // Validate behaviour of AWS_SECRETSMANAGER_SECRET_ARN attributes then remove it. @@ -771,7 +776,7 @@ describe('AwsMetricAttributeGeneratorTest', () => { AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, 'arn:aws:secretsmanager:us-east-1:123456789123:secret:testSecret' ); - validateRemoteResourceAttributes('AWS::SecretsManager::Secret', 'testSecret'); + validateRemoteResourceAttributes('AWS::SecretsManager::Secret', 'testSecret', 'arn:aws:secretsmanager:us-east-1:123456789123:secret:testSecret'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, undefined); // Validate behaviour of AWS_LAMBDA_FUNCTION_NAME and AWS_LAMBDA_FUNCTION_ARN @@ -780,7 +785,7 @@ describe('AwsMetricAttributeGeneratorTest', () => { AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, 'arn:aws:lambda:us-east-1:123456789012:function:aws_lambda_function_name' ); - validateRemoteResourceAttributes('AWS::Lambda::Function', 'aws_lambda_function_name'); + validateRemoteResourceAttributes('AWS::Lambda::Function', 'aws_lambda_function_name', 'arn:aws:lambda:us-east-1:123456789012:function:aws_lambda_function_name'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, undefined); @@ -794,14 +799,14 @@ describe('AwsMetricAttributeGeneratorTest', () => { AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, 'arn:aws:states:us-east-1:123456789123:stateMachine:testStateMachine' ); - validateRemoteResourceAttributes('AWS::StepFunctions::StateMachine', 'testStateMachine'); + validateRemoteResourceAttributes('AWS::StepFunctions::StateMachine', 'testStateMachine', 'arn:aws:states:us-east-1:123456789123:stateMachine:testStateMachine'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, undefined); mockAttribute( AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, 'arn:aws:states:us-east-1:123456789123:activity:testActivity' ); - validateRemoteResourceAttributes('AWS::StepFunctions::Activity', 'testActivity'); + validateRemoteResourceAttributes('AWS::StepFunctions::Activity', 'testActivity', 'arn:aws:states:us-east-1:123456789123:activity:testActivity'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, undefined); // Validate behaviour of AWS_TABLE_NAMES attribute with one table name, then remove it. @@ -841,23 +846,31 @@ describe('AwsMetricAttributeGeneratorTest', () => { // Validate behaviour of AWS_BEDROCK_DATA_SOURCE_ID attribute, then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID, 'test_datasource_id'); - validateRemoteResourceAttributes('AWS::Bedrock::DataSource', 'test_datasource_id'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID, 'test_kb_id'); + validateRemoteResourceAttributes('AWS::Bedrock::DataSource', 'test_datasource_id', 'test_kb_id|test_datasource_id'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID, undefined); // Validate behaviour of AWS_BEDROCK_DATA_SOURCE_ID attribute with special chars(^), then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID, 'test_datasource_^id'); - validateRemoteResourceAttributes('AWS::Bedrock::DataSource', 'test_datasource_^^id'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID, 'test_kb_^id'); + validateRemoteResourceAttributes('AWS::Bedrock::DataSource', 'test_datasource_^^id', 'test_kb_^^id|test_datasource_^^id'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID, undefined); // Validate behaviour of AWS_BEDROCK_GUARDRAIL_ID attribute, then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, 'test_guardrail_id'); - validateRemoteResourceAttributes('AWS::Bedrock::Guardrail', 'test_guardrail_id'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id'); + validateRemoteResourceAttributes('AWS::Bedrock::Guardrail', 'test_guardrail_id', 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, undefined); // Validate behaviour of AWS_BEDROCK_GUARDRAIL_ID attribute with special chars(^), then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, 'test_guardrail_^id'); - validateRemoteResourceAttributes('AWS::Bedrock::Guardrail', 'test_guardrail_^^id'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^id'); + validateRemoteResourceAttributes('AWS::Bedrock::Guardrail', 'test_guardrail_^^id', 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^^id'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, undefined); // Validate behaviour of AWS_BEDROCK_KNOWLEDGE_BASE_ID attribute, then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID, 'test_knowledgeBase_id'); @@ -1114,7 +1127,12 @@ describe('AwsMetricAttributeGeneratorTest', () => { mockAttribute(SEMATTRS_PEER_SERVICE, undefined); } - function validateRemoteResourceAttributes(type: string | undefined, identifier: string | undefined): void { + function validateRemoteResourceAttributes(type: string | undefined, identifier: string | undefined, cfnPrimaryId: string | undefined = undefined): void { + // If cfnPrimaryId is not provided, it defaults to identifier + if (cfnPrimaryId === undefined) { + cfnPrimaryId = identifier; + } + // Client, Producer and Consumer spans should generate the expected remote resource attributes (spanDataMock as any).kind = SpanKind.CLIENT; let actualAttributes: Attributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[ @@ -1122,22 +1140,26 @@ describe('AwsMetricAttributeGeneratorTest', () => { ]; expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_TYPE]).toEqual(type); expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_IDENTIFIER]).toEqual(identifier); + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER]).toEqual(cfnPrimaryId); (spanDataMock as any).kind = SpanKind.PRODUCER; actualAttributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[DEPENDENCY_METRIC]; expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_TYPE]).toEqual(type); expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_IDENTIFIER]).toEqual(identifier); + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER]).toEqual(cfnPrimaryId); (spanDataMock as any).kind = SpanKind.CONSUMER; actualAttributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[DEPENDENCY_METRIC]; expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_TYPE]).toEqual(type); expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_IDENTIFIER]).toEqual(identifier); + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER]).toEqual(cfnPrimaryId); // Server span should not generate remote resource attributes (spanDataMock as any).kind = SpanKind.SERVER; actualAttributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[SERVICE_METRIC]; expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_TYPE]).toEqual(undefined); expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_RESOURCE_IDENTIFIER]).toEqual(undefined); + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER]).toEqual(undefined); } it('testDBUserAttribute', () => { From 0ce0b3fc3e511246b4deafe9e357d8b7c8c3016d Mon Sep 17 00:00:00 2001 From: Michael He Date: Sun, 8 Jun 2025 21:30:02 +0000 Subject: [PATCH 04/15] align cfn primary id fallback behavior with java and python --- .../src/aws-metric-attribute-generator.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index 394955a2..d305e49c 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -501,17 +501,14 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { remoteResourceIdentifier = AwsMetricAttributeGenerator.getDbConnection(span); } + if (cloudFormationIdentifier === undefined) { + cloudFormationIdentifier = remoteResourceIdentifier; + } + 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; - } + attributes[AWS_ATTRIBUTE_KEYS.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER] = cloudFormationIdentifier; } } From 2d85020a218db6b553c82b3f80361179da6fb38d Mon Sep 17 00:00:00 2001 From: Michael He Date: Sun, 8 Jun 2025 21:45:15 +0000 Subject: [PATCH 05/15] add tests for cfn primary id fallback and set remote environment --- .../aws-metric-attribute-generator.test.ts | 193 ++++++++++++++++-- 1 file changed, 181 insertions(+), 12 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts index 83fa7083..0253a898 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts @@ -745,7 +745,11 @@ describe('AwsMetricAttributeGeneratorTest', () => { // them. Queue name is more reliable than queue URL, so we prefer to use name over URL. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, 'aws_queue_name'); - validateRemoteResourceAttributes('AWS::SQS::Queue', 'aws_queue_name', 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue'); + validateRemoteResourceAttributes( + 'AWS::SQS::Queue', + 'aws_queue_name', + 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, undefined); @@ -758,7 +762,11 @@ describe('AwsMetricAttributeGeneratorTest', () => { // Validate behaviour of AWS_SQS_QUEUE_URL attribute without queue name, then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue'); - validateRemoteResourceAttributes('AWS::SQS::Queue', 'MyQueue', 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue'); + validateRemoteResourceAttributes( + 'AWS::SQS::Queue', + 'MyQueue', + 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, undefined); // Validate behaviour of AWS_KINESIS_STREAM_NAME attribute, then remove it. @@ -776,7 +784,11 @@ describe('AwsMetricAttributeGeneratorTest', () => { AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, 'arn:aws:secretsmanager:us-east-1:123456789123:secret:testSecret' ); - validateRemoteResourceAttributes('AWS::SecretsManager::Secret', 'testSecret', 'arn:aws:secretsmanager:us-east-1:123456789123:secret:testSecret'); + validateRemoteResourceAttributes( + 'AWS::SecretsManager::Secret', + 'testSecret', + 'arn:aws:secretsmanager:us-east-1:123456789123:secret:testSecret' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, undefined); // Validate behaviour of AWS_LAMBDA_FUNCTION_NAME and AWS_LAMBDA_FUNCTION_ARN @@ -785,7 +797,11 @@ describe('AwsMetricAttributeGeneratorTest', () => { AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, 'arn:aws:lambda:us-east-1:123456789012:function:aws_lambda_function_name' ); - validateRemoteResourceAttributes('AWS::Lambda::Function', 'aws_lambda_function_name', 'arn:aws:lambda:us-east-1:123456789012:function:aws_lambda_function_name'); + validateRemoteResourceAttributes( + 'AWS::Lambda::Function', + 'aws_lambda_function_name', + 'arn:aws:lambda:us-east-1:123456789012:function:aws_lambda_function_name' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, undefined); @@ -799,14 +815,22 @@ describe('AwsMetricAttributeGeneratorTest', () => { AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, 'arn:aws:states:us-east-1:123456789123:stateMachine:testStateMachine' ); - validateRemoteResourceAttributes('AWS::StepFunctions::StateMachine', 'testStateMachine', 'arn:aws:states:us-east-1:123456789123:stateMachine:testStateMachine'); + validateRemoteResourceAttributes( + 'AWS::StepFunctions::StateMachine', + 'testStateMachine', + 'arn:aws:states:us-east-1:123456789123:stateMachine:testStateMachine' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, undefined); mockAttribute( AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, 'arn:aws:states:us-east-1:123456789123:activity:testActivity' ); - validateRemoteResourceAttributes('AWS::StepFunctions::Activity', 'testActivity', 'arn:aws:states:us-east-1:123456789123:activity:testActivity'); + validateRemoteResourceAttributes( + 'AWS::StepFunctions::Activity', + 'testActivity', + 'arn:aws:states:us-east-1:123456789123:activity:testActivity' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, undefined); // Validate behaviour of AWS_TABLE_NAMES attribute with one table name, then remove it. @@ -854,21 +878,39 @@ describe('AwsMetricAttributeGeneratorTest', () => { // Validate behaviour of AWS_BEDROCK_DATA_SOURCE_ID attribute with special chars(^), then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID, 'test_datasource_^id'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID, 'test_kb_^id'); - validateRemoteResourceAttributes('AWS::Bedrock::DataSource', 'test_datasource_^^id', 'test_kb_^^id|test_datasource_^^id'); + validateRemoteResourceAttributes( + 'AWS::Bedrock::DataSource', + 'test_datasource_^^id', + 'test_kb_^^id|test_datasource_^^id' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID, undefined); // Validate behaviour of AWS_BEDROCK_GUARDRAIL_ID attribute, then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, 'test_guardrail_id'); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id'); - validateRemoteResourceAttributes('AWS::Bedrock::Guardrail', 'test_guardrail_id', 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id'); + mockAttribute( + AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, + 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id' + ); + validateRemoteResourceAttributes( + 'AWS::Bedrock::Guardrail', + 'test_guardrail_id', + 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, undefined); // Validate behaviour of AWS_BEDROCK_GUARDRAIL_ID attribute with special chars(^), then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, 'test_guardrail_^id'); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^id'); - validateRemoteResourceAttributes('AWS::Bedrock::Guardrail', 'test_guardrail_^^id', 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^^id'); + mockAttribute( + AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, + 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^id' + ); + validateRemoteResourceAttributes( + 'AWS::Bedrock::Guardrail', + 'test_guardrail_^^id', + 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^^id' + ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ARN, undefined); @@ -1127,7 +1169,11 @@ describe('AwsMetricAttributeGeneratorTest', () => { mockAttribute(SEMATTRS_PEER_SERVICE, undefined); } - function validateRemoteResourceAttributes(type: string | undefined, identifier: string | undefined, cfnPrimaryId: string | undefined = undefined): void { + function validateRemoteResourceAttributes( + type: string | undefined, + identifier: string | undefined, + cfnPrimaryId: string | undefined = undefined + ): void { // If cfnPrimaryId is not provided, it defaults to identifier if (cfnPrimaryId === undefined) { cfnPrimaryId = identifier; @@ -1283,6 +1329,129 @@ describe('AwsMetricAttributeGeneratorTest', () => { expect(attributeMap[DEPENDENCY_METRIC]).toEqual(dependencyAttributes); }); + it('testCloudformationPrimaryIdentifierFallbackToRemoteResourceIdentifier', () => { + // Test that when cloudformationPrimaryIdentifier is not explicitly set, + // it falls back to use the same value as remoteResourceIdentifier. + mockAttribute(SEMATTRS_RPC_SYSTEM, 'aws-api'); + (spanDataMock as any).kind = SpanKind.CLIENT; + + // Test case 1: S3 Bucket (no ARN available, should use bucket name for both) + mockAttribute(SEMATTRS_RPC_SERVICE, 'S3'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_S3_BUCKET, 'my-test-bucket'); + validateRemoteResourceAttributes('AWS::S3::Bucket', 'my-test-bucket'); + + // Test S3 bucket with special characters + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_S3_BUCKET, 'my-test|bucket^name'); + validateRemoteResourceAttributes('AWS::S3::Bucket', 'my-test^|bucket^^name'); + mockAttribute(SEMATTRS_RPC_SERVICE, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_S3_BUCKET, undefined); + + // Test case 2: SQS Queue by name (no ARN, should use queue name for both) + mockAttribute(SEMATTRS_RPC_SERVICE, 'SQS'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, 'my-test-queue'); + validateRemoteResourceAttributes('AWS::SQS::Queue', 'my-test-queue'); + + // Test SQS queue with special characters + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, 'my^queue|name'); + validateRemoteResourceAttributes('AWS::SQS::Queue', 'my^^queue^|name'); + mockAttribute(SEMATTRS_RPC_SERVICE, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, undefined); + + // Test case 3: DynamoDB Table (no ARN, should use table name for both) + mockAttribute(SEMATTRS_RPC_SERVICE, 'DynamoDB'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES, ['my-test-table']); + validateRemoteResourceAttributes('AWS::DynamoDB::Table', 'my-test-table'); + + // Test DynamoDB table with special characters + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES, ['my|test^table']); + validateRemoteResourceAttributes('AWS::DynamoDB::Table', 'my^|test^^table'); + mockAttribute(SEMATTRS_RPC_SERVICE, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES, undefined); + + // Test case 4: Kinesis Stream + mockAttribute(SEMATTRS_RPC_SERVICE, 'Kinesis'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, 'my-test-stream'); + validateRemoteResourceAttributes('AWS::Kinesis::Stream', 'my-test-stream'); + + // Test Kinesis stream with special characters + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, 'my-stream^with|chars'); + validateRemoteResourceAttributes('AWS::Kinesis::Stream', 'my-stream^^with^|chars'); + mockAttribute(SEMATTRS_RPC_SERVICE, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, undefined); + + // Test case 5: Lambda Function (non-invoke operation, no ARN) + mockAttribute(SEMATTRS_RPC_SERVICE, 'Lambda'); + mockAttribute(SEMATTRS_RPC_METHOD, 'GetFunction'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, 'my-test-function'); + validateRemoteResourceAttributes('AWS::Lambda::Function', 'my-test-function'); + + // Test Lambda function with special characters + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, 'my-function|with^chars'); + validateRemoteResourceAttributes('AWS::Lambda::Function', 'my-function^|with^^chars'); + mockAttribute(SEMATTRS_RPC_SERVICE, undefined); + mockAttribute(SEMATTRS_RPC_METHOD, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); + + mockAttribute(SEMATTRS_RPC_SYSTEM, undefined); + }); + + it('testSetRemoteEnvironment', () => { + // Test remote environment setting for Lambda invoke operations. + + // Test 1: Setting remote environment when all relevant attributes are present + (spanDataMock as any).kind = SpanKind.CLIENT; + mockAttribute(SEMATTRS_RPC_SYSTEM, 'aws-api'); + mockAttribute(SEMATTRS_RPC_SERVICE, 'Lambda'); + mockAttribute(SEMATTRS_RPC_METHOD, 'Invoke'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, 'testFunction'); + + let actualAttributes: Attributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[ + DEPENDENCY_METRIC + ]; + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_ENVIRONMENT]).toEqual('lambda:default'); + + // Test 2: NOT setting it when RPC_SYSTEM is missing + mockAttribute(SEMATTRS_RPC_SYSTEM, undefined); + actualAttributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[DEPENDENCY_METRIC]; + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_ENVIRONMENT]).toBeUndefined(); + mockAttribute(SEMATTRS_RPC_SYSTEM, 'aws-api'); + + // Test 3: NOT setting it when RPC_METHOD is missing + mockAttribute(SEMATTRS_RPC_METHOD, undefined); + actualAttributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[DEPENDENCY_METRIC]; + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_ENVIRONMENT]).toBeUndefined(); + mockAttribute(SEMATTRS_RPC_METHOD, 'Invoke'); + + // Test 4: Still setting it to lambda:default when AWS_LAMBDA_FUNCTION_NAME is missing + // Keep the other attributes but remove AWS_LAMBDA_FUNCTION_NAME + mockAttribute(SEMATTRS_RPC_SYSTEM, 'aws-api'); + mockAttribute(SEMATTRS_RPC_SERVICE, 'Lambda'); + mockAttribute(SEMATTRS_RPC_METHOD, 'Invoke'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); + + actualAttributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[DEPENDENCY_METRIC]; + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_ENVIRONMENT]).toEqual('lambda:default'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, 'testFunction'); + + // Test 5: NOT setting it for non-Lambda services + mockAttribute(SEMATTRS_RPC_SERVICE, 'S3'); + mockAttribute(SEMATTRS_RPC_METHOD, 'GetObject'); + actualAttributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[DEPENDENCY_METRIC]; + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_ENVIRONMENT]).toBeUndefined(); + + // Test 6: NOT setting it for Lambda non-Invoke operations + mockAttribute(SEMATTRS_RPC_SERVICE, 'Lambda'); + mockAttribute(SEMATTRS_RPC_METHOD, 'GetFunction'); + actualAttributes = GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource)[DEPENDENCY_METRIC]; + expect(actualAttributes[AWS_ATTRIBUTE_KEYS.AWS_REMOTE_ENVIRONMENT]).toBeUndefined(); + + // Clean up + mockAttribute(SEMATTRS_RPC_SYSTEM, undefined); + mockAttribute(SEMATTRS_RPC_SERVICE, undefined); + mockAttribute(SEMATTRS_RPC_METHOD, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); + }); + it('testJdbcDbConnectionString', () => { mockAttribute(SEMATTRS_DB_SYSTEM, 'mysql'); From 0584a6669cbadadc6a74ca6a53bffa5d3fd871b2 Mon Sep 17 00:00:00 2001 From: Michael He Date: Sun, 8 Jun 2025 21:52:03 +0000 Subject: [PATCH 06/15] add docstring for set remote environment method --- .../src/aws-metric-attribute-generator.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index d305e49c..768a082a 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -512,6 +512,10 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { } } + /** + * Remote environment is used to identify the environment of downstream services. Currently only + * set to "lambda:default" for Lambda Invoke operations when aws-api system is detected. + */ private static setRemoteEnvironment(span: ReadableSpan, attributes: Attributes): void { // We want to treat downstream Lambdas as a service rather than a resource because // Application Signals topology map gets disconnected due to conflicting Lambda Entity From 57e7ff45ba3e89866fc124ee6b04db39b9e355a3 Mon Sep 17 00:00:00 2001 From: Michael He Date: Sun, 8 Jun 2025 21:58:39 +0000 Subject: [PATCH 07/15] add missing special char assertions for new aws resources --- .../aws-metric-attribute-generator.test.ts | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts index 0253a898..a958f055 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts @@ -774,11 +774,25 @@ describe('AwsMetricAttributeGeneratorTest', () => { validateRemoteResourceAttributes('AWS::Kinesis::Stream', 'AWS_KINESIS_STREAM_NAME'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, undefined); + // Validate behaviour of AWS_KINESIS_STREAM_NAME attribute with special chars, then remove it. + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, 'kinesis-stream|with^chars'); + validateRemoteResourceAttributes('AWS::Kinesis::Stream', 'kinesis-stream^|with^^chars'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, undefined); + // Validate behaviour of AWS_SNS_TOPIC_ARN attribute then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, 'arn:aws:sns:us-east-1:123456789012:testTopic'); validateRemoteResourceAttributes('AWS::SNS::Topic', 'testTopic', 'arn:aws:sns:us-east-1:123456789012:testTopic'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, undefined); + // Validate behaviour of AWS_SNS_TOPIC_ARN attribute with special chars, then remove it. + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, 'arn:aws:sns:us-east-1:123456789012:test|Topic^name'); + validateRemoteResourceAttributes( + 'AWS::SNS::Topic', + 'test^|Topic^^name', + 'arn:aws:sns:us-east-1:123456789012:test^|Topic^^name' + ); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, undefined); + // Validate behaviour of AWS_SECRETSMANAGER_SECRET_ARN attributes then remove it. mockAttribute( AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, @@ -791,6 +805,18 @@ describe('AwsMetricAttributeGeneratorTest', () => { ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, undefined); + // Validate behaviour of AWS_SECRETSMANAGER_SECRET_ARN attribute with special chars, then remove it. + mockAttribute( + AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, + 'arn:aws:secretsmanager:us-east-1:123456789123:secret:test|Secret^name' + ); + validateRemoteResourceAttributes( + 'AWS::SecretsManager::Secret', + 'test^|Secret^^name', + 'arn:aws:secretsmanager:us-east-1:123456789123:secret:test^|Secret^^name' + ); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, undefined); + // Validate behaviour of AWS_LAMBDA_FUNCTION_NAME and AWS_LAMBDA_FUNCTION_ARN mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, 'aws_lambda_function_name'); mockAttribute( @@ -805,11 +831,30 @@ describe('AwsMetricAttributeGeneratorTest', () => { mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, undefined); + // Validate behaviour of AWS_LAMBDA_FUNCTION_NAME with special chars + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, 'lambda|function^name'); + mockAttribute( + AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, + 'arn:aws:lambda:us-east-1:123456789012:function:lambda|function^name' + ); + validateRemoteResourceAttributes( + 'AWS::Lambda::Function', + 'lambda^|function^^name', + 'arn:aws:lambda:us-east-1:123456789012:function:lambda^|function^^name' + ); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, undefined); + // Validate behaviour of AWS_LAMBDA_RESOURCE_MAPPING_ID attribute then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID, 'aws_lambda_resource_mapping_id'); validateRemoteResourceAttributes('AWS::Lambda::EventSourceMapping', 'aws_lambda_resource_mapping_id'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID, undefined); + // Validate behaviour of AWS_LAMBDA_RESOURCE_MAPPING_ID attribute with special chars, then remove it. + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID, 'mapping|id^test'); + validateRemoteResourceAttributes('AWS::Lambda::EventSourceMapping', 'mapping^|id^^test'); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID, undefined); + // Validate behaviour of AWS_STEPFUNCTIONS_STATEMACHINE_ARN and AWS_STEPFUNCTIONS_ACTIVITY_ARN attributes then remove them. mockAttribute( AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, @@ -822,6 +867,18 @@ describe('AwsMetricAttributeGeneratorTest', () => { ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, undefined); + // Validate behaviour of AWS_STEPFUNCTIONS_STATEMACHINE_ARN attribute with special chars, then remove it. + mockAttribute( + AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, + 'arn:aws:states:us-east-1:123456789123:stateMachine:test|State^Machine' + ); + validateRemoteResourceAttributes( + 'AWS::StepFunctions::StateMachine', + 'test^|State^^Machine', + 'arn:aws:states:us-east-1:123456789123:stateMachine:test^|State^^Machine' + ); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, undefined); + mockAttribute( AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, 'arn:aws:states:us-east-1:123456789123:activity:testActivity' @@ -833,6 +890,18 @@ describe('AwsMetricAttributeGeneratorTest', () => { ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, undefined); + // Validate behaviour of AWS_STEPFUNCTIONS_ACTIVITY_ARN attribute with special chars, then remove it. + mockAttribute( + AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, + 'arn:aws:states:us-east-1:123456789123:activity:test|Activity^name' + ); + validateRemoteResourceAttributes( + 'AWS::StepFunctions::Activity', + 'test^|Activity^^name', + 'arn:aws:states:us-east-1:123456789123:activity:test^|Activity^^name' + ); + mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, undefined); + // Validate behaviour of AWS_TABLE_NAMES attribute with one table name, then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES, ['aws_table_name']); validateRemoteResourceAttributes('AWS::DynamoDB::Table', 'aws_table_name'); From 25bd798a661da67115ecc7e3c7a22970abbcca7e Mon Sep 17 00:00:00 2001 From: Michael He Date: Tue, 10 Jun 2025 15:52:06 +0000 Subject: [PATCH 08/15] Revert "add missing logic to extract queue url for cfn primary id if available in queue name case" to scope down PR This reverts commit 120a2a8434fd73c24d919587f7b2b6d785e3dd1b. --- .../src/aws-metric-attribute-generator.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index 768a082a..173a0536 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -450,12 +450,6 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters( span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME] ); - // If queue URL is also present, use it as the CloudFormation primary identifier - if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL)) { - cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters( - span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL] - ); - } } else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL)) { const sqsQueueUrl = AwsMetricAttributeGenerator.escapeDelimiters( span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL] From 3cf9d2af9f2f8f52852f1ef374b23f991795617e Mon Sep 17 00:00:00 2001 From: Michael He Date: Tue, 10 Jun 2025 15:52:28 +0000 Subject: [PATCH 09/15] Revert "add missing special char assertions for new aws resources" to scope down PR This reverts commit 57e7ff45ba3e89866fc124ee6b04db39b9e355a3. --- .../aws-metric-attribute-generator.test.ts | 69 ------------------- 1 file changed, 69 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts index a958f055..0253a898 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts @@ -774,25 +774,11 @@ describe('AwsMetricAttributeGeneratorTest', () => { validateRemoteResourceAttributes('AWS::Kinesis::Stream', 'AWS_KINESIS_STREAM_NAME'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, undefined); - // Validate behaviour of AWS_KINESIS_STREAM_NAME attribute with special chars, then remove it. - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, 'kinesis-stream|with^chars'); - validateRemoteResourceAttributes('AWS::Kinesis::Stream', 'kinesis-stream^|with^^chars'); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME, undefined); - // Validate behaviour of AWS_SNS_TOPIC_ARN attribute then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, 'arn:aws:sns:us-east-1:123456789012:testTopic'); validateRemoteResourceAttributes('AWS::SNS::Topic', 'testTopic', 'arn:aws:sns:us-east-1:123456789012:testTopic'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, undefined); - // Validate behaviour of AWS_SNS_TOPIC_ARN attribute with special chars, then remove it. - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, 'arn:aws:sns:us-east-1:123456789012:test|Topic^name'); - validateRemoteResourceAttributes( - 'AWS::SNS::Topic', - 'test^|Topic^^name', - 'arn:aws:sns:us-east-1:123456789012:test^|Topic^^name' - ); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SNS_TOPIC_ARN, undefined); - // Validate behaviour of AWS_SECRETSMANAGER_SECRET_ARN attributes then remove it. mockAttribute( AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, @@ -805,18 +791,6 @@ describe('AwsMetricAttributeGeneratorTest', () => { ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, undefined); - // Validate behaviour of AWS_SECRETSMANAGER_SECRET_ARN attribute with special chars, then remove it. - mockAttribute( - AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, - 'arn:aws:secretsmanager:us-east-1:123456789123:secret:test|Secret^name' - ); - validateRemoteResourceAttributes( - 'AWS::SecretsManager::Secret', - 'test^|Secret^^name', - 'arn:aws:secretsmanager:us-east-1:123456789123:secret:test^|Secret^^name' - ); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SECRETSMANAGER_SECRET_ARN, undefined); - // Validate behaviour of AWS_LAMBDA_FUNCTION_NAME and AWS_LAMBDA_FUNCTION_ARN mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, 'aws_lambda_function_name'); mockAttribute( @@ -831,30 +805,11 @@ describe('AwsMetricAttributeGeneratorTest', () => { mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, undefined); - // Validate behaviour of AWS_LAMBDA_FUNCTION_NAME with special chars - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, 'lambda|function^name'); - mockAttribute( - AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, - 'arn:aws:lambda:us-east-1:123456789012:function:lambda|function^name' - ); - validateRemoteResourceAttributes( - 'AWS::Lambda::Function', - 'lambda^|function^^name', - 'arn:aws:lambda:us-east-1:123456789012:function:lambda^|function^^name' - ); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME, undefined); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_ARN, undefined); - // Validate behaviour of AWS_LAMBDA_RESOURCE_MAPPING_ID attribute then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID, 'aws_lambda_resource_mapping_id'); validateRemoteResourceAttributes('AWS::Lambda::EventSourceMapping', 'aws_lambda_resource_mapping_id'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID, undefined); - // Validate behaviour of AWS_LAMBDA_RESOURCE_MAPPING_ID attribute with special chars, then remove it. - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID, 'mapping|id^test'); - validateRemoteResourceAttributes('AWS::Lambda::EventSourceMapping', 'mapping^|id^^test'); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_RESOURCE_MAPPING_ID, undefined); - // Validate behaviour of AWS_STEPFUNCTIONS_STATEMACHINE_ARN and AWS_STEPFUNCTIONS_ACTIVITY_ARN attributes then remove them. mockAttribute( AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, @@ -867,18 +822,6 @@ describe('AwsMetricAttributeGeneratorTest', () => { ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, undefined); - // Validate behaviour of AWS_STEPFUNCTIONS_STATEMACHINE_ARN attribute with special chars, then remove it. - mockAttribute( - AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, - 'arn:aws:states:us-east-1:123456789123:stateMachine:test|State^Machine' - ); - validateRemoteResourceAttributes( - 'AWS::StepFunctions::StateMachine', - 'test^|State^^Machine', - 'arn:aws:states:us-east-1:123456789123:stateMachine:test^|State^^Machine' - ); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_STATEMACHINE_ARN, undefined); - mockAttribute( AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, 'arn:aws:states:us-east-1:123456789123:activity:testActivity' @@ -890,18 +833,6 @@ describe('AwsMetricAttributeGeneratorTest', () => { ); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, undefined); - // Validate behaviour of AWS_STEPFUNCTIONS_ACTIVITY_ARN attribute with special chars, then remove it. - mockAttribute( - AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, - 'arn:aws:states:us-east-1:123456789123:activity:test|Activity^name' - ); - validateRemoteResourceAttributes( - 'AWS::StepFunctions::Activity', - 'test^|Activity^^name', - 'arn:aws:states:us-east-1:123456789123:activity:test^|Activity^^name' - ); - mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_STEPFUNCTIONS_ACTIVITY_ARN, undefined); - // Validate behaviour of AWS_TABLE_NAMES attribute with one table name, then remove it. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES, ['aws_table_name']); validateRemoteResourceAttributes('AWS::DynamoDB::Table', 'aws_table_name'); From a9aa1b955ee33a44e9d4a487fdfa6b7454308ea6 Mon Sep 17 00:00:00 2001 From: Michael He Date: Tue, 10 Jun 2025 15:53:53 +0000 Subject: [PATCH 10/15] remove unecessary comments about aws lambda name attribute --- .../src/aws-metric-attribute-generator.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index 173a0536..1ed76e3e 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -345,8 +345,6 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { // Special handling for Lambda invoke operations if (AwsMetricAttributeGenerator.isLambdaInvokeOperation(span)) { - // AWS_LAMBDA_FUNCTION_NAME is guaranteed to contain function name (not ARN) - // due to logic in Lambda botocore patches during instrumentation const lambdaFunctionName = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME]; // If Lambda name is not present, use UnknownRemoteService // This is intentional - we want to clearly indicate when the Lambda function name @@ -431,8 +429,6 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { // see normalize_remote_service_name for more information. if (!AwsMetricAttributeGenerator.isLambdaInvokeOperation(span)) { remoteResourceType = NORMALIZED_LAMBDA_SERVICE_NAME + '::Function'; - // AWS_LAMBDA_FUNCTION_NAME is guaranteed to contain function name (not ARN) - // due to logic in Lambda botocore patches during instrumentation remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters( span.attributes[AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME] ); From ec07a040d0d4299678b870cba3426160ae2e88cf Mon Sep 17 00:00:00 2001 From: Michael He Date: Tue, 10 Jun 2025 15:56:46 +0000 Subject: [PATCH 11/15] update sqs unit tests to align with existing behavior in js to scope down pr --- .../test/aws-metric-attribute-generator.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts index 0253a898..f860e270 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/test/aws-metric-attribute-generator.test.ts @@ -745,18 +745,14 @@ describe('AwsMetricAttributeGeneratorTest', () => { // them. Queue name is more reliable than queue URL, so we prefer to use name over URL. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, 'aws_queue_name'); - validateRemoteResourceAttributes( - 'AWS::SQS::Queue', - 'aws_queue_name', - 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue' - ); + validateRemoteResourceAttributes('AWS::SQS::Queue', 'aws_queue_name'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, undefined); // Valid queue name with invalid queue URL, we should default to using the queue name. mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, 'invalidUrl'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, 'aws_queue_name'); - validateRemoteResourceAttributes('AWS::SQS::Queue', 'aws_queue_name', 'invalidUrl'); + validateRemoteResourceAttributes('AWS::SQS::Queue', 'aws_queue_name'); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL, undefined); mockAttribute(AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME, undefined); From e0466836b5a21f06769e29a9806ad2f33218ea32 Mon Sep 17 00:00:00 2001 From: Michael He Date: Tue, 10 Jun 2025 16:17:38 +0000 Subject: [PATCH 12/15] move lambda app signals remote environment env var to aws-opentelemetry-configurator.ts --- .../src/aws-metric-attribute-generator.ts | 2 +- .../src/aws-opentelemetry-configurator.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index 1ed76e3e..c89bc39c 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -33,6 +33,7 @@ import { SERVICE_METRIC, } from './metric-attribute-generator'; import { SqsUrlParser } from './sqs-url-parser'; +import { LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT } from './aws-opentelemetry-configurator'; // Does not exist in @opentelemetry/semantic-conventions const _SERVER_SOCKET_ADDRESS: string = 'server.socket.address'; @@ -50,7 +51,6 @@ const _GRAPHQL_OPERATION_TYPE: string = 'graphql.operation.type'; // Special DEPENDENCY attribute value if GRAPHQL_OPERATION_TYPE attribute key is present. const GRAPHQL: string = 'graphql'; -const LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT: string = 'LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT'; const LAMBDA_INVOKE_OPERATION: string = 'Invoke'; // Normalized remote service names for supported AWS services diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts index 4d4938fe..dac8e45d 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts @@ -75,6 +75,7 @@ const FORMAT_OTEL_UNSAMPLED_TRACES_BINARY_PREFIX = 'T1U'; // Follow Python SDK Impl to set the max span batch size // which will reduce the chance of UDP package size is larger than 64KB const LAMBDA_SPAN_EXPORT_BATCH_SIZE = 10; +export const LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT: string = 'LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT'; /** * Aws Application Signals Config Provider creates a configuration object that can be provided to From 896278e7b871a9a2b133565f82acd91c4d0cba58 Mon Sep 17 00:00:00 2001 From: Michael He Date: Tue, 10 Jun 2025 17:16:27 +0000 Subject: [PATCH 13/15] add comment for lambda constant --- .../src/aws-metric-attribute-generator.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index c89bc39c..f3b688ee 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -51,6 +51,7 @@ const _GRAPHQL_OPERATION_TYPE: string = 'graphql.operation.type'; // Special DEPENDENCY attribute value if GRAPHQL_OPERATION_TYPE attribute key is present. const GRAPHQL: string = 'graphql'; +// Constants for Lambda operations const LAMBDA_INVOKE_OPERATION: string = 'Invoke'; // Normalized remote service names for supported AWS services From 5d6c893915b20a8522a60e9faea46ce762e396f4 Mon Sep 17 00:00:00 2001 From: Michael He Date: Thu, 12 Jun 2025 17:07:32 +0000 Subject: [PATCH 14/15] update comment: normalize_remote_service -> normalizeRemoteService --- .../src/aws-metric-attribute-generator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index f3b688ee..f8f3a8fe 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -427,7 +427,7 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { cloudFormationIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(activityArn); } else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_LAMBDA_FUNCTION_NAME)) { // For non-Invoke Lambda operations, treat Lambda as a resource, - // see normalize_remote_service_name for more information. + // see normalizeRemoteServiceName for more information. if (!AwsMetricAttributeGenerator.isLambdaInvokeOperation(span)) { remoteResourceType = NORMALIZED_LAMBDA_SERVICE_NAME + '::Function'; remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters( From 8e6ca5d7335c003c46307a1f016cd2839d8f2999 Mon Sep 17 00:00:00 2001 From: Michael He Date: Thu, 12 Jun 2025 17:09:41 +0000 Subject: [PATCH 15/15] remove unecessary || after .trim() --- .../src/aws-metric-attribute-generator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts index f8f3a8fe..c717fe7b 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts @@ -514,7 +514,7 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator { // Additional context can be found in // https://github.com/aws-observability/aws-otel-python-instrumentation/pull/319 if (AwsMetricAttributeGenerator.isLambdaInvokeOperation(span)) { - let remoteEnvironment = process.env[LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT]?.trim() || ''; + let remoteEnvironment = process.env[LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT]?.trim(); if (!remoteEnvironment) { remoteEnvironment = 'default'; }