@@ -879,6 +879,13 @@ public void TestSdkClientSpanWithRemoteResourceAttributes()
879879 attributesCombination [ AttributeAWSSQSQueueUrl ] = "invalidUrl" ;
880880 this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::SQS::Queue" , "aws_queue_name" , "invalidUrl" ) ;
881881
882+ // Validate SQS behavior when QueueName isn't available
883+ attributesCombination = new Dictionary < string , object >
884+ {
885+ { AttributeAWSSQSQueueUrl , "https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue" } ,
886+ } ;
887+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::SQS::Queue" , "MyQueue" , "https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue" ) ;
888+
882889 attributesCombination = new Dictionary < string , object >
883890 {
884891 { AttributeAWSKinesisStreamName , "aws_stream_name" } ,
@@ -1043,6 +1050,128 @@ public void TestSdkClientSpanWithRemoteResourceAttributes()
10431050 this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::Bedrock::DataSource" , "aws_data_source_^^id" , "aws_knowledge_base_^^id|aws_data_source_^^id" ) ;
10441051 }
10451052
1053+ [ Fact ]
1054+ public void TestCloudformationPrimaryIdentifierFallbackToRemoteResourceIdentifier ( )
1055+ {
1056+ // Test case 1: S3 Bucket (no ARN available, should use bucket name for both)
1057+ Dictionary < string , object > attributesCombination = new Dictionary < string , object >
1058+ {
1059+ { AttributeRpcService , "S3" } ,
1060+ { AttributeAWSS3Bucket , "my-test-bucket" } ,
1061+ } ;
1062+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::S3::Bucket" , "my-test-bucket" , "my-test-bucket" ) ;
1063+
1064+ // Test S3 Bucket with speicial characters
1065+ attributesCombination [ AttributeAWSS3Bucket ] = "my-test|bucket^name" ;
1066+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::S3::Bucket" , "my-test^|bucket^^name" , "my-test^|bucket^^name" ) ;
1067+
1068+ // Test case 2: SQS Queue (no ARN, should use queue name for both)
1069+ attributesCombination = new Dictionary < string , object >
1070+ {
1071+ { AttributeRpcService , "SQS" } ,
1072+ { AttributeAWSSQSQueueName , "my-test-queue" } ,
1073+ } ;
1074+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::SQS::Queue" , "my-test-queue" , "my-test-queue" ) ;
1075+
1076+ // Test SQS Queue with special characters
1077+ attributesCombination [ AttributeAWSSQSQueueName ] = "my^queue|name" ;
1078+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::SQS::Queue" , "my^^queue^|name" , "my^^queue^|name" ) ;
1079+
1080+ // Test case 3: DynamoDB Table (no ARN, should use table name for both)
1081+ attributesCombination = new Dictionary < string , object >
1082+ {
1083+ { AttributeRpcService , "DynamoDB" } ,
1084+ { AttributeAWSDynamoTableName , "my-test-table" } ,
1085+ } ;
1086+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::DynamoDB::Table" , "my-test-table" , "my-test-table" ) ;
1087+
1088+ // Test DynamoDB Table with special characters
1089+ attributesCombination [ AttributeAWSDynamoTableName ] = "my|table^name" ;
1090+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::DynamoDB::Table" , "my^|table^^name" , "my^|table^^name" ) ;
1091+
1092+ // Test case 4: Kinesis Stream (no ARN, should use stream name for both)
1093+ attributesCombination = new Dictionary < string , object >
1094+ {
1095+ { AttributeRpcService , "Kinesis" } ,
1096+ { AttributeAWSKinesisStreamName , "my-test-stream" } ,
1097+ } ;
1098+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::Kinesis::Stream" , "my-test-stream" , "my-test-stream" ) ;
1099+
1100+ // Test Kinesis Stream with special characters
1101+ attributesCombination [ AttributeAWSKinesisStreamName ] = "my|stream^name" ;
1102+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::Kinesis::Stream" , "my^|stream^^name" , "my^|stream^^name" ) ;
1103+
1104+ // Test case 5: Lambda Function (non-invoke operation, no ARN)
1105+ attributesCombination = new Dictionary < string , object >
1106+ {
1107+ { AttributeRpcService , "Lambda" } ,
1108+ { AttributeRpcMethod , "GetFunction" } ,
1109+ { AttributeAWSLambdaFunctionName , "my-test-function" } ,
1110+ } ;
1111+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::Lambda::Function" , "my-test-function" , "my-test-function" ) ;
1112+
1113+ // Test Lambda Function with special characters
1114+ attributesCombination [ AttributeAWSLambdaFunctionName ] = "my|lambda^function" ;
1115+ this . ValidateRemoteResourceAttributes ( attributesCombination , "AWS::Lambda::Function" , "my^|lambda^^function" , "my^|lambda^^function" ) ;
1116+ }
1117+
1118+ [ Fact ]
1119+ public void TestSetRemoteEnvironment ( )
1120+ {
1121+ // Test 1: Setting remote environment when all relevant attributes are present
1122+ Activity ? spanDataMock = this . testSource . StartActivity ( "test" , ActivityKind . Client ) ;
1123+ spanDataMock . SetTag ( AttributeRpcSystem , "aws-api" ) ;
1124+ spanDataMock . SetTag ( AttributeRpcService , "Lambda" ) ;
1125+ spanDataMock . SetTag ( AttributeRpcMethod , "Invoke" ) ;
1126+ spanDataMock . SetTag ( AttributeAWSLambdaFunctionName , "testFunction" ) ;
1127+
1128+ this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource )
1129+ . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out ActivityTagsCollection ? dependencyMetric ) ;
1130+ dependencyMetric . TryGetValue ( AttributeAWSRemoteEnvironment , out var remoteEnvironment ) ;
1131+ Assert . Equal ( remoteEnvironment , "lambda:default" ) ;
1132+
1133+ // Test 2: NOT setting remote environment when rpc.system is missing
1134+ spanDataMock . SetTag ( AttributeRpcSystem , null ) ;
1135+ this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource )
1136+ . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out dependencyMetric ) ;
1137+ dependencyMetric . TryGetValue ( AttributeAWSRemoteEnvironment , out remoteEnvironment ) ;
1138+ Assert . Null ( remoteEnvironment ) ;
1139+ spanDataMock . SetTag ( AttributeRpcSystem , "aws-api" ) ;
1140+
1141+ // Test 3: NOT setting remote environment when rpc.method is missing
1142+ spanDataMock . SetTag ( AttributeRpcMethod , null ) ;
1143+ this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource )
1144+ . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out dependencyMetric ) ;
1145+ dependencyMetric . TryGetValue ( AttributeAWSRemoteEnvironment , out remoteEnvironment ) ;
1146+ Assert . Null ( remoteEnvironment ) ;
1147+ spanDataMock . SetTag ( AttributeRpcMethod , "Invoke" ) ;
1148+
1149+ // Test 4: setting remote environment to lambda:default when FunctionName is missing
1150+ spanDataMock . SetTag ( AttributeAWSLambdaFunctionName , null ) ;
1151+ this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource )
1152+ . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out dependencyMetric ) ;
1153+ dependencyMetric . TryGetValue ( AttributeAWSRemoteEnvironment , out remoteEnvironment ) ;
1154+ Assert . Equal ( remoteEnvironment , "lambda:default" ) ;
1155+
1156+ // Test 5: NOT setting remote environment for non-Lambda services
1157+ spanDataMock . SetTag ( AttributeRpcService , "S3" ) ;
1158+ spanDataMock . SetTag ( AttributeRpcMethod , "GetObject" ) ;
1159+ this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource )
1160+ . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out dependencyMetric ) ;
1161+ dependencyMetric . TryGetValue ( AttributeAWSRemoteEnvironment , out remoteEnvironment ) ;
1162+ Assert . Null ( remoteEnvironment ) ;
1163+
1164+ // Test 6: NOT setting remote environment for Lambda non-Invoke operations
1165+ spanDataMock . SetTag ( AttributeRpcService , "Lambda" ) ;
1166+ spanDataMock . SetTag ( AttributeRpcMethod , "GetFunction" ) ;
1167+ this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource )
1168+ . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out dependencyMetric ) ;
1169+ dependencyMetric . TryGetValue ( AttributeAWSRemoteEnvironment , out remoteEnvironment ) ;
1170+ Assert . Null ( remoteEnvironment ) ;
1171+
1172+ spanDataMock . Dispose ( ) ;
1173+ }
1174+
10461175 [ Fact ]
10471176 public void TestNormalizeRemoteServiceName_NoNormalization ( )
10481177 {
@@ -1074,6 +1203,31 @@ public void TestNormalizeRemoteServiceName_AwsSdk()
10741203 this . TestAwsSdkServiceNormalization ( "Kinesis" , "AWS::Kinesis" ) ;
10751204 this . TestAwsSdkServiceNormalization ( "S3" , "AWS::S3" ) ;
10761205 this . TestAwsSdkServiceNormalization ( "Sqs" , "AWS::SQS" ) ;
1206+
1207+ // Lambda: non-Invoke operations
1208+ this . TestAwsSdkServiceNormalization ( "Lambda" , "AWS::Lambda" ) ;
1209+
1210+ // Lambda: Invoke with function name
1211+ Activity ? spanDataMock = this . testSource . StartActivity ( "test" , ActivityKind . Client ) ;
1212+ spanDataMock . SetTag ( AttributeRpcSystem , "aws-api" ) ;
1213+ spanDataMock . SetTag ( AttributeRpcService , "Lambda" ) ;
1214+
1215+ spanDataMock . SetTag ( AttributeRpcMethod , "Invoke" ) ;
1216+ spanDataMock . SetTag ( AttributeAWSLambdaFunctionName , "testFunction" ) ;
1217+
1218+ var attributeMap = this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource ) ;
1219+ attributeMap . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out ActivityTagsCollection ? dependencyMetric ) ;
1220+ dependencyMetric . TryGetValue ( AttributeAWSRemoteService , out var actualServiceName ) ;
1221+ Assert . Equal ( "testFunction" , actualServiceName ) ;
1222+
1223+ // Lambda: Invoke without function name - should fall back to UnknownRemoteService
1224+ spanDataMock . SetTag ( AttributeAWSLambdaFunctionName , null ) ;
1225+ attributeMap = this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource ) ;
1226+ attributeMap . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out dependencyMetric ) ;
1227+ dependencyMetric . TryGetValue ( AttributeAWSRemoteService , out actualServiceName ) ;
1228+ Assert . Equal ( AutoInstrumentation . AwsSpanProcessingUtil . UnknownRemoteService , actualServiceName ) ;
1229+
1230+ spanDataMock . Dispose ( ) ;
10771231 }
10781232
10791233 [ Fact ]
@@ -1105,6 +1259,7 @@ private void TestAwsSdkServiceNormalization(string serviceName, string expectedR
11051259 Activity ? spanDataMock = this . testSource . StartActivity ( "test" , ActivityKind . Client ) ;
11061260 spanDataMock . SetTag ( AttributeRpcSystem , "aws-api" ) ;
11071261 spanDataMock . SetTag ( AttributeRpcService , serviceName ) ;
1262+
11081263 var attributeMap = this . generator . GenerateMetricAttributeMapFromSpan ( spanDataMock , this . resource ) ;
11091264 attributeMap . TryGetValue ( MetricAttributeGeneratorConstants . DependencyMetric , out ActivityTagsCollection ? dependencyMetric ) ;
11101265 dependencyMetric . TryGetValue ( AttributeAWSRemoteService , out var actualServiceName ) ;
0 commit comments