@@ -745,7 +745,11 @@ describe('AwsMetricAttributeGeneratorTest', () => {
745745 // them. Queue name is more reliable than queue URL, so we prefer to use name over URL.
746746 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_URL , 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue' ) ;
747747 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_NAME , 'aws_queue_name' ) ;
748- validateRemoteResourceAttributes ( 'AWS::SQS::Queue' , 'aws_queue_name' , 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue' ) ;
748+ validateRemoteResourceAttributes (
749+ 'AWS::SQS::Queue' ,
750+ 'aws_queue_name' ,
751+ 'https://sqs.us-east-2.amazonaws.com/123456789012/Queue'
752+ ) ;
749753 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_URL , undefined ) ;
750754 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_NAME , undefined ) ;
751755
@@ -758,7 +762,11 @@ describe('AwsMetricAttributeGeneratorTest', () => {
758762
759763 // Validate behaviour of AWS_SQS_QUEUE_URL attribute without queue name, then remove it.
760764 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_URL , 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue' ) ;
761- validateRemoteResourceAttributes ( 'AWS::SQS::Queue' , 'MyQueue' , 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue' ) ;
765+ validateRemoteResourceAttributes (
766+ 'AWS::SQS::Queue' ,
767+ 'MyQueue' ,
768+ 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue'
769+ ) ;
762770 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_URL , undefined ) ;
763771
764772 // Validate behaviour of AWS_KINESIS_STREAM_NAME attribute, then remove it.
@@ -776,7 +784,11 @@ describe('AwsMetricAttributeGeneratorTest', () => {
776784 AWS_ATTRIBUTE_KEYS . AWS_SECRETSMANAGER_SECRET_ARN ,
777785 'arn:aws:secretsmanager:us-east-1:123456789123:secret:testSecret'
778786 ) ;
779- validateRemoteResourceAttributes ( 'AWS::SecretsManager::Secret' , 'testSecret' , 'arn:aws:secretsmanager:us-east-1:123456789123:secret:testSecret' ) ;
787+ validateRemoteResourceAttributes (
788+ 'AWS::SecretsManager::Secret' ,
789+ 'testSecret' ,
790+ 'arn:aws:secretsmanager:us-east-1:123456789123:secret:testSecret'
791+ ) ;
780792 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SECRETSMANAGER_SECRET_ARN , undefined ) ;
781793
782794 // Validate behaviour of AWS_LAMBDA_FUNCTION_NAME and AWS_LAMBDA_FUNCTION_ARN
@@ -785,7 +797,11 @@ describe('AwsMetricAttributeGeneratorTest', () => {
785797 AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_ARN ,
786798 'arn:aws:lambda:us-east-1:123456789012:function:aws_lambda_function_name'
787799 ) ;
788- validateRemoteResourceAttributes ( 'AWS::Lambda::Function' , 'aws_lambda_function_name' , 'arn:aws:lambda:us-east-1:123456789012:function:aws_lambda_function_name' ) ;
800+ validateRemoteResourceAttributes (
801+ 'AWS::Lambda::Function' ,
802+ 'aws_lambda_function_name' ,
803+ 'arn:aws:lambda:us-east-1:123456789012:function:aws_lambda_function_name'
804+ ) ;
789805 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME , undefined ) ;
790806 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_ARN , undefined ) ;
791807
@@ -799,14 +815,22 @@ describe('AwsMetricAttributeGeneratorTest', () => {
799815 AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_STATEMACHINE_ARN ,
800816 'arn:aws:states:us-east-1:123456789123:stateMachine:testStateMachine'
801817 ) ;
802- validateRemoteResourceAttributes ( 'AWS::StepFunctions::StateMachine' , 'testStateMachine' , 'arn:aws:states:us-east-1:123456789123:stateMachine:testStateMachine' ) ;
818+ validateRemoteResourceAttributes (
819+ 'AWS::StepFunctions::StateMachine' ,
820+ 'testStateMachine' ,
821+ 'arn:aws:states:us-east-1:123456789123:stateMachine:testStateMachine'
822+ ) ;
803823 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_STATEMACHINE_ARN , undefined ) ;
804824
805825 mockAttribute (
806826 AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_ACTIVITY_ARN ,
807827 'arn:aws:states:us-east-1:123456789123:activity:testActivity'
808828 ) ;
809- validateRemoteResourceAttributes ( 'AWS::StepFunctions::Activity' , 'testActivity' , 'arn:aws:states:us-east-1:123456789123:activity:testActivity' ) ;
829+ validateRemoteResourceAttributes (
830+ 'AWS::StepFunctions::Activity' ,
831+ 'testActivity' ,
832+ 'arn:aws:states:us-east-1:123456789123:activity:testActivity'
833+ ) ;
810834 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_ACTIVITY_ARN , undefined ) ;
811835
812836 // Validate behaviour of AWS_TABLE_NAMES attribute with one table name, then remove it.
@@ -854,21 +878,39 @@ describe('AwsMetricAttributeGeneratorTest', () => {
854878 // Validate behaviour of AWS_BEDROCK_DATA_SOURCE_ID attribute with special chars(^), then remove it.
855879 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_DATA_SOURCE_ID , 'test_datasource_^id' ) ;
856880 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_KNOWLEDGE_BASE_ID , 'test_kb_^id' ) ;
857- validateRemoteResourceAttributes ( 'AWS::Bedrock::DataSource' , 'test_datasource_^^id' , 'test_kb_^^id|test_datasource_^^id' ) ;
881+ validateRemoteResourceAttributes (
882+ 'AWS::Bedrock::DataSource' ,
883+ 'test_datasource_^^id' ,
884+ 'test_kb_^^id|test_datasource_^^id'
885+ ) ;
858886 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_DATA_SOURCE_ID , undefined ) ;
859887 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_KNOWLEDGE_BASE_ID , undefined ) ;
860888
861889 // Validate behaviour of AWS_BEDROCK_GUARDRAIL_ID attribute, then remove it.
862890 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ID , 'test_guardrail_id' ) ;
863- mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ARN , 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id' ) ;
864- validateRemoteResourceAttributes ( 'AWS::Bedrock::Guardrail' , 'test_guardrail_id' , 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id' ) ;
891+ mockAttribute (
892+ AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ARN ,
893+ 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id'
894+ ) ;
895+ validateRemoteResourceAttributes (
896+ 'AWS::Bedrock::Guardrail' ,
897+ 'test_guardrail_id' ,
898+ 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_id'
899+ ) ;
865900 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ID , undefined ) ;
866901 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ARN , undefined ) ;
867902
868903 // Validate behaviour of AWS_BEDROCK_GUARDRAIL_ID attribute with special chars(^), then remove it.
869904 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ID , 'test_guardrail_^id' ) ;
870- mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ARN , 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^id' ) ;
871- validateRemoteResourceAttributes ( 'AWS::Bedrock::Guardrail' , 'test_guardrail_^^id' , 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^^id' ) ;
905+ mockAttribute (
906+ AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ARN ,
907+ 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^id'
908+ ) ;
909+ validateRemoteResourceAttributes (
910+ 'AWS::Bedrock::Guardrail' ,
911+ 'test_guardrail_^^id' ,
912+ 'arn:aws:bedrock:us-east-1:123456789012:guardrail/test_guardrail_^^id'
913+ ) ;
872914 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ID , undefined ) ;
873915 mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ARN , undefined ) ;
874916
@@ -1127,7 +1169,11 @@ describe('AwsMetricAttributeGeneratorTest', () => {
11271169 mockAttribute ( SEMATTRS_PEER_SERVICE , undefined ) ;
11281170 }
11291171
1130- function validateRemoteResourceAttributes ( type : string | undefined , identifier : string | undefined , cfnPrimaryId : string | undefined = undefined ) : void {
1172+ function validateRemoteResourceAttributes (
1173+ type : string | undefined ,
1174+ identifier : string | undefined ,
1175+ cfnPrimaryId : string | undefined = undefined
1176+ ) : void {
11311177 // If cfnPrimaryId is not provided, it defaults to identifier
11321178 if ( cfnPrimaryId === undefined ) {
11331179 cfnPrimaryId = identifier ;
@@ -1283,6 +1329,129 @@ describe('AwsMetricAttributeGeneratorTest', () => {
12831329 expect ( attributeMap [ DEPENDENCY_METRIC ] ) . toEqual ( dependencyAttributes ) ;
12841330 } ) ;
12851331
1332+ it ( 'testCloudformationPrimaryIdentifierFallbackToRemoteResourceIdentifier' , ( ) => {
1333+ // Test that when cloudformationPrimaryIdentifier is not explicitly set,
1334+ // it falls back to use the same value as remoteResourceIdentifier.
1335+ mockAttribute ( SEMATTRS_RPC_SYSTEM , 'aws-api' ) ;
1336+ ( spanDataMock as any ) . kind = SpanKind . CLIENT ;
1337+
1338+ // Test case 1: S3 Bucket (no ARN available, should use bucket name for both)
1339+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'S3' ) ;
1340+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_S3_BUCKET , 'my-test-bucket' ) ;
1341+ validateRemoteResourceAttributes ( 'AWS::S3::Bucket' , 'my-test-bucket' ) ;
1342+
1343+ // Test S3 bucket with special characters
1344+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_S3_BUCKET , 'my-test|bucket^name' ) ;
1345+ validateRemoteResourceAttributes ( 'AWS::S3::Bucket' , 'my-test^|bucket^^name' ) ;
1346+ mockAttribute ( SEMATTRS_RPC_SERVICE , undefined ) ;
1347+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_S3_BUCKET , undefined ) ;
1348+
1349+ // Test case 2: SQS Queue by name (no ARN, should use queue name for both)
1350+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'SQS' ) ;
1351+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_NAME , 'my-test-queue' ) ;
1352+ validateRemoteResourceAttributes ( 'AWS::SQS::Queue' , 'my-test-queue' ) ;
1353+
1354+ // Test SQS queue with special characters
1355+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_NAME , 'my^queue|name' ) ;
1356+ validateRemoteResourceAttributes ( 'AWS::SQS::Queue' , 'my^^queue^|name' ) ;
1357+ mockAttribute ( SEMATTRS_RPC_SERVICE , undefined ) ;
1358+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_NAME , undefined ) ;
1359+
1360+ // Test case 3: DynamoDB Table (no ARN, should use table name for both)
1361+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'DynamoDB' ) ;
1362+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_DYNAMODB_TABLE_NAMES , [ 'my-test-table' ] ) ;
1363+ validateRemoteResourceAttributes ( 'AWS::DynamoDB::Table' , 'my-test-table' ) ;
1364+
1365+ // Test DynamoDB table with special characters
1366+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_DYNAMODB_TABLE_NAMES , [ 'my|test^table' ] ) ;
1367+ validateRemoteResourceAttributes ( 'AWS::DynamoDB::Table' , 'my^|test^^table' ) ;
1368+ mockAttribute ( SEMATTRS_RPC_SERVICE , undefined ) ;
1369+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_DYNAMODB_TABLE_NAMES , undefined ) ;
1370+
1371+ // Test case 4: Kinesis Stream
1372+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'Kinesis' ) ;
1373+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_NAME , 'my-test-stream' ) ;
1374+ validateRemoteResourceAttributes ( 'AWS::Kinesis::Stream' , 'my-test-stream' ) ;
1375+
1376+ // Test Kinesis stream with special characters
1377+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_NAME , 'my-stream^with|chars' ) ;
1378+ validateRemoteResourceAttributes ( 'AWS::Kinesis::Stream' , 'my-stream^^with^|chars' ) ;
1379+ mockAttribute ( SEMATTRS_RPC_SERVICE , undefined ) ;
1380+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_NAME , undefined ) ;
1381+
1382+ // Test case 5: Lambda Function (non-invoke operation, no ARN)
1383+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'Lambda' ) ;
1384+ mockAttribute ( SEMATTRS_RPC_METHOD , 'GetFunction' ) ;
1385+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME , 'my-test-function' ) ;
1386+ validateRemoteResourceAttributes ( 'AWS::Lambda::Function' , 'my-test-function' ) ;
1387+
1388+ // Test Lambda function with special characters
1389+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME , 'my-function|with^chars' ) ;
1390+ validateRemoteResourceAttributes ( 'AWS::Lambda::Function' , 'my-function^|with^^chars' ) ;
1391+ mockAttribute ( SEMATTRS_RPC_SERVICE , undefined ) ;
1392+ mockAttribute ( SEMATTRS_RPC_METHOD , undefined ) ;
1393+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME , undefined ) ;
1394+
1395+ mockAttribute ( SEMATTRS_RPC_SYSTEM , undefined ) ;
1396+ } ) ;
1397+
1398+ it ( 'testSetRemoteEnvironment' , ( ) => {
1399+ // Test remote environment setting for Lambda invoke operations.
1400+
1401+ // Test 1: Setting remote environment when all relevant attributes are present
1402+ ( spanDataMock as any ) . kind = SpanKind . CLIENT ;
1403+ mockAttribute ( SEMATTRS_RPC_SYSTEM , 'aws-api' ) ;
1404+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'Lambda' ) ;
1405+ mockAttribute ( SEMATTRS_RPC_METHOD , 'Invoke' ) ;
1406+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME , 'testFunction' ) ;
1407+
1408+ let actualAttributes : Attributes = GENERATOR . generateMetricAttributeMapFromSpan ( spanDataMock , resource ) [
1409+ DEPENDENCY_METRIC
1410+ ] ;
1411+ expect ( actualAttributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_ENVIRONMENT ] ) . toEqual ( 'lambda:default' ) ;
1412+
1413+ // Test 2: NOT setting it when RPC_SYSTEM is missing
1414+ mockAttribute ( SEMATTRS_RPC_SYSTEM , undefined ) ;
1415+ actualAttributes = GENERATOR . generateMetricAttributeMapFromSpan ( spanDataMock , resource ) [ DEPENDENCY_METRIC ] ;
1416+ expect ( actualAttributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_ENVIRONMENT ] ) . toBeUndefined ( ) ;
1417+ mockAttribute ( SEMATTRS_RPC_SYSTEM , 'aws-api' ) ;
1418+
1419+ // Test 3: NOT setting it when RPC_METHOD is missing
1420+ mockAttribute ( SEMATTRS_RPC_METHOD , undefined ) ;
1421+ actualAttributes = GENERATOR . generateMetricAttributeMapFromSpan ( spanDataMock , resource ) [ DEPENDENCY_METRIC ] ;
1422+ expect ( actualAttributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_ENVIRONMENT ] ) . toBeUndefined ( ) ;
1423+ mockAttribute ( SEMATTRS_RPC_METHOD , 'Invoke' ) ;
1424+
1425+ // Test 4: Still setting it to lambda:default when AWS_LAMBDA_FUNCTION_NAME is missing
1426+ // Keep the other attributes but remove AWS_LAMBDA_FUNCTION_NAME
1427+ mockAttribute ( SEMATTRS_RPC_SYSTEM , 'aws-api' ) ;
1428+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'Lambda' ) ;
1429+ mockAttribute ( SEMATTRS_RPC_METHOD , 'Invoke' ) ;
1430+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME , undefined ) ;
1431+
1432+ actualAttributes = GENERATOR . generateMetricAttributeMapFromSpan ( spanDataMock , resource ) [ DEPENDENCY_METRIC ] ;
1433+ expect ( actualAttributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_ENVIRONMENT ] ) . toEqual ( 'lambda:default' ) ;
1434+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME , 'testFunction' ) ;
1435+
1436+ // Test 5: NOT setting it for non-Lambda services
1437+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'S3' ) ;
1438+ mockAttribute ( SEMATTRS_RPC_METHOD , 'GetObject' ) ;
1439+ actualAttributes = GENERATOR . generateMetricAttributeMapFromSpan ( spanDataMock , resource ) [ DEPENDENCY_METRIC ] ;
1440+ expect ( actualAttributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_ENVIRONMENT ] ) . toBeUndefined ( ) ;
1441+
1442+ // Test 6: NOT setting it for Lambda non-Invoke operations
1443+ mockAttribute ( SEMATTRS_RPC_SERVICE , 'Lambda' ) ;
1444+ mockAttribute ( SEMATTRS_RPC_METHOD , 'GetFunction' ) ;
1445+ actualAttributes = GENERATOR . generateMetricAttributeMapFromSpan ( spanDataMock , resource ) [ DEPENDENCY_METRIC ] ;
1446+ expect ( actualAttributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_ENVIRONMENT ] ) . toBeUndefined ( ) ;
1447+
1448+ // Clean up
1449+ mockAttribute ( SEMATTRS_RPC_SYSTEM , undefined ) ;
1450+ mockAttribute ( SEMATTRS_RPC_SERVICE , undefined ) ;
1451+ mockAttribute ( SEMATTRS_RPC_METHOD , undefined ) ;
1452+ mockAttribute ( AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME , undefined ) ;
1453+ } ) ;
1454+
12861455 it ( 'testJdbcDbConnectionString' , ( ) => {
12871456 mockAttribute ( SEMATTRS_DB_SYSTEM , 'mysql' ) ;
12881457
0 commit comments