Skip to content

Commit 976ffd0

Browse files
authored
Add CFN Primary Id to .NET ADOT Package (#142)
1 parent 4ae8bdf commit 976ffd0

File tree

6 files changed

+52
-25
lines changed

6 files changed

+52
-25
lines changed

src/AWS.Distro.OpenTelemetry.AutoInstrumentation/AwsAttributeKeys.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ internal sealed class AwsAttributeKeys
1414
internal static readonly string AttributeAWSRemoteOperation = "aws.remote.operation";
1515

1616
internal static readonly string AttributeAWSRemoteResourceIdentifier = "aws.remote.resource.identifier";
17+
internal static readonly string AttributeAWSCloudformationPrimaryIdentifier = "aws.remote.resource.cfn.primary.identifier";
1718
internal static readonly string AttributeAWSRemoteResourceType = "aws.remote.resource.type";
1819
internal static readonly string AttributeAWSSdkDescendant = "aws.sdk.descendant";
1920
internal static readonly string AttributeAWSConsumerParentSpanKind = "aws.consumer.parent.span.kind";

src/AWS.Distro.OpenTelemetry.AutoInstrumentation/AwsMetricAttributeGenerator.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ private static void SetRemoteResourceTypeAndIdentifier(Activity span, ActivityTa
389389
{
390390
string? remoteResourceType = null;
391391
string? remoteResourceIdentifier = null;
392+
string? cloudformationPrimaryIdentifier = null;
392393
if (IsAwsSDKSpan(span))
393394
{
394395
if (IsKeyPresent(span, AttributeAWSDynamoTableName))
@@ -410,11 +411,13 @@ private static void SetRemoteResourceTypeAndIdentifier(Activity span, ActivityTa
410411
{
411412
remoteResourceType = NormalizedSQSServiceName + "::Queue";
412413
remoteResourceIdentifier = EscapeDelimiters((string?)span.GetTagItem(AttributeAWSSQSQueueName));
414+
cloudformationPrimaryIdentifier = EscapeDelimiters((string?)span.GetTagItem(AttributeAWSSQSQueueUrl));
413415
}
414416
else if (IsKeyPresent(span, AttributeAWSSQSQueueUrl))
415417
{
416418
remoteResourceType = NormalizedSQSServiceName + "::Queue";
417419
remoteResourceIdentifier = EscapeDelimiters(GetQueueName((string?)span.GetTagItem(AttributeAWSSQSQueueUrl)));
420+
cloudformationPrimaryIdentifier = EscapeDelimiters((string?)span.GetTagItem(AttributeAWSSQSQueueUrl));
418421
}
419422
else if (IsKeyPresent(span, AttributeAWSBedrockGuardrailId))
420423
{
@@ -431,15 +434,19 @@ private static void SetRemoteResourceTypeAndIdentifier(Activity span, ActivityTa
431434
remoteResourceType = NormalizedBedrockServiceName + "::Agent";
432435
remoteResourceIdentifier = EscapeDelimiters((string?)span.GetTagItem(AttributeAWSBedrockAgentId));
433436
}
434-
else if (IsKeyPresent(span, AttributeAWSBedrockKnowledgeBaseId))
435-
{
436-
remoteResourceType = NormalizedBedrockServiceName + "::KnowledgeBase";
437-
remoteResourceIdentifier = EscapeDelimiters((string?)span.GetTagItem(AttributeAWSBedrockKnowledgeBaseId));
438-
}
439437
else if (IsKeyPresent(span, AttributeAWSBedrockDataSourceId))
440438
{
441439
remoteResourceType = NormalizedBedrockServiceName + "::DataSource";
442440
remoteResourceIdentifier = EscapeDelimiters((string?)span.GetTagItem(AttributeAWSBedrockDataSourceId));
441+
cloudformationPrimaryIdentifier =
442+
EscapeDelimiters((string?)span.GetTagItem(AttributeAWSBedrockKnowledgeBaseId))
443+
+ "|"
444+
+ remoteResourceIdentifier;
445+
}
446+
else if (IsKeyPresent(span, AttributeAWSBedrockKnowledgeBaseId))
447+
{
448+
remoteResourceType = NormalizedBedrockServiceName + "::KnowledgeBase";
449+
remoteResourceIdentifier = EscapeDelimiters((string?)span.GetTagItem(AttributeAWSBedrockKnowledgeBaseId));
443450
}
444451
}
445452
else if (IsDBSpan(span))
@@ -448,10 +455,16 @@ private static void SetRemoteResourceTypeAndIdentifier(Activity span, ActivityTa
448455
remoteResourceIdentifier = GetDbConnection(span);
449456
}
450457

451-
if (remoteResourceType != null && remoteResourceIdentifier != null)
458+
if (cloudformationPrimaryIdentifier == null)
459+
{
460+
cloudformationPrimaryIdentifier = remoteResourceIdentifier;
461+
}
462+
463+
if (remoteResourceType != null && remoteResourceIdentifier != null && cloudformationPrimaryIdentifier != null)
452464
{
453465
attributes.Add(AttributeAWSRemoteResourceType, remoteResourceType);
454466
attributes.Add(AttributeAWSRemoteResourceIdentifier, remoteResourceIdentifier);
467+
attributes.Add(AttributeAWSCloudformationPrimaryIdentifier, cloudformationPrimaryIdentifier);
455468
}
456469
}
457470

src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSServiceHelper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ internal class AWSServiceHelper
2020

2121
internal static IReadOnlyDictionary<string, List<string>> ServiceResponseParameterMap = new Dictionary<string, List<string>>()
2222
{
23+
{ AWSServiceType.SQSService, new List<string> { "QueueUrl" } },
2324
{ AWSServiceType.BedrockService, new List<string> { "GuardrailId" } },
2425
{ AWSServiceType.BedrockAgentService, new List<string> { "AgentId", "DataSourceId" } },
2526
};

src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,6 @@ private static void AddRequestSpecificInformation(Activity activity, IRequestCon
147147
{
148148
try
149149
{
150-
// for bedrock agent, we only extract one attribute based on the operation.
151-
if (AWSServiceType.IsBedrockAgentService(service))
152-
{
153-
if (AWSServiceHelper.OperationNameToResourceMap()[AWSServiceHelper.GetAWSOperationName(requestContext)] != parameter)
154-
{
155-
continue;
156-
}
157-
}
158-
159150
var property = request.GetType().GetProperty(parameter);
160151
if (property != null)
161152
{
@@ -216,16 +207,6 @@ private static void AddResponseSpecificInformation(Activity activity, IResponseC
216207
{
217208
try
218209
{
219-
// for bedrock agent, extract attribute from object in response.
220-
if (AWSServiceType.IsBedrockAgentService(service))
221-
{
222-
var operationName = Utils.RemoveSuffix(response.GetType().Name, "Response");
223-
if (AWSServiceHelper.OperationNameToResourceMap()[operationName] == parameter)
224-
{
225-
AddBedrockAgentResponseAttribute(activity, response, parameter);
226-
}
227-
}
228-
229210
var property = response.GetType().GetProperty(parameter);
230211
if (property != null)
231212
{

test/contract-tests/tests/test/amazon/awssdk/awssdk_test.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from amazon.base.contract_test_base import NETWORK_NAME, ContractTestBase
1111
from amazon.utils.application_signals_constants import (
1212
AWS_LOCAL_SERVICE,
13+
AWS_REMOTE_CLOUDFORMATION_PRIMARY_IDENTIFIER,
1314
AWS_REMOTE_OPERATION,
1415
AWS_REMOTE_RESOURCE_IDENTIFIER,
1516
AWS_REMOTE_RESOURCE_TYPE,
@@ -110,6 +111,7 @@ def test_s3_create_bucket(self):
110111
remote_operation="PutBucket",
111112
remote_resource_type="AWS::S3::Bucket",
112113
remote_resource_identifier="test-bucket-name",
114+
cloudformation_primary_identifier="test-bucket-name",
113115
request_response_specific_attributes={
114116
SpanAttributes.AWS_S3_BUCKET: "test-bucket-name",
115117
},
@@ -127,6 +129,7 @@ def test_s3_create_object(self):
127129
remote_operation="PutObject",
128130
remote_resource_type="AWS::S3::Bucket",
129131
remote_resource_identifier="test-bucket-name",
132+
cloudformation_primary_identifier="test-bucket-name",
130133
request_response_specific_attributes={
131134
SpanAttributes.AWS_S3_BUCKET: "test-bucket-name",
132135
},
@@ -144,6 +147,7 @@ def test_s3_delete_object(self):
144147
remote_operation="DeleteObject",
145148
remote_resource_type="AWS::S3::Bucket",
146149
remote_resource_identifier="test-bucket-name",
150+
cloudformation_primary_identifier="test-bucket-name",
147151
request_response_specific_attributes={
148152
SpanAttributes.AWS_S3_BUCKET: "test-bucket-name",
149153
},
@@ -161,6 +165,7 @@ def test_dynamodb_create_table(self):
161165
remote_operation="CreateTable",
162166
remote_resource_type="AWS::DynamoDB::Table",
163167
remote_resource_identifier="test_table",
168+
cloudformation_primary_identifier="test_table",
164169
request_response_specific_attributes={
165170
# SpanAttributes.AWS_DYNAMODB_TABLE_NAMES: ["test_table"],
166171
"aws.table_name": ["test_table"],
@@ -179,6 +184,7 @@ def test_dynamodb_put_item(self):
179184
remote_operation="PutItem",
180185
remote_resource_type="AWS::DynamoDB::Table",
181186
remote_resource_identifier="test_table",
187+
cloudformation_primary_identifier="test_table",
182188
request_response_specific_attributes={
183189
# SpanAttributes.AWS_DYNAMODB_TABLE_NAMES: ["test_table"],
184190
"aws.table_name": ["test_table"],
@@ -197,8 +203,10 @@ def test_sqs_create_queue(self):
197203
remote_operation="CreateQueue",
198204
remote_resource_type="AWS::SQS::Queue",
199205
remote_resource_identifier="test_queue",
206+
cloudformation_primary_identifier="http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/test_queue",
200207
request_response_specific_attributes={
201208
_AWS_SQS_QUEUE_NAME: "test_queue",
209+
_AWS_SQS_QUEUE_URL: "http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/test_queue",
202210
},
203211
span_name="SQS.CreateQueue",
204212
)
@@ -214,6 +222,7 @@ def test_sqs_send_message(self):
214222
remote_operation="SendMessage",
215223
remote_resource_type="AWS::SQS::Queue",
216224
remote_resource_identifier="test_queue",
225+
cloudformation_primary_identifier="http://sqs.us-east-1.localstack:4566/000000000000/test_queue",
217226
request_response_specific_attributes={
218227
_AWS_SQS_QUEUE_URL: "http://sqs.us-east-1.localstack:4566/000000000000/test_queue",
219228
},
@@ -231,6 +240,7 @@ def test_sqs_receive_message(self):
231240
remote_operation="ReceiveMessage",
232241
remote_resource_type="AWS::SQS::Queue",
233242
remote_resource_identifier="test_queue",
243+
cloudformation_primary_identifier="http://sqs.us-east-1.localstack:4566/000000000000/test_queue",
234244
request_response_specific_attributes={
235245
_AWS_SQS_QUEUE_URL: "http://sqs.us-east-1.localstack:4566/000000000000/test_queue",
236246
},
@@ -248,6 +258,7 @@ def test_kinesis_create_stream(self):
248258
remote_operation="CreateStream",
249259
remote_resource_type="AWS::Kinesis::Stream",
250260
remote_resource_identifier="test_stream",
261+
cloudformation_primary_identifier="test_stream",
251262
request_response_specific_attributes={
252263
_AWS_KINESIS_STREAM_NAME: "test_stream",
253264
},
@@ -265,6 +276,7 @@ def test_kinesis_put_record(self):
265276
remote_operation="PutRecord",
266277
remote_resource_type="AWS::Kinesis::Stream",
267278
remote_resource_identifier="test_stream",
279+
cloudformation_primary_identifier="test_stream",
268280
request_response_specific_attributes={
269281
_AWS_KINESIS_STREAM_NAME: "test_stream",
270282
},
@@ -282,6 +294,7 @@ def test_kinesis_error(self):
282294
remote_operation="DeleteStream",
283295
remote_resource_type="AWS::Kinesis::Stream",
284296
remote_resource_identifier="test_stream_error",
297+
cloudformation_primary_identifier="test_stream_error",
285298
request_response_specific_attributes={
286299
_AWS_KINESIS_STREAM_NAME: "test_stream_error",
287300
},
@@ -318,6 +331,7 @@ def test_bedrock_get_guardrail(self):
318331
remote_operation="GetGuardrail",
319332
remote_resource_type="AWS::Bedrock::Guardrail",
320333
remote_resource_identifier="test-guardrail",
334+
cloudformation_primiary_identifier="test-guardrail",
321335
request_response_specific_attributes={
322336
_AWS_BEDROCK_GUARDRAIL_ID: "test-guardrail",
323337
},
@@ -336,6 +350,7 @@ def test_bedrock_runtime_invoke_model_titan(self):
336350
remote_operation="InvokeModel",
337351
remote_resource_type="AWS::Bedrock::Model",
338352
remote_resource_identifier="amazon.titan-text-express-v1",
353+
cloudformation_primary_identifier="amazon.titan-text-express-v1",
339354
request_response_specific_attributes={
340355
_GEN_AI_SYSTEM: "aws_bedrock",
341356
_GEN_AI_REQUEST_MODEL: "amazon.titan-text-express-v1",
@@ -361,6 +376,7 @@ def test_bedrock_runtime_invoke_model_claude(self):
361376
remote_operation="InvokeModel",
362377
remote_resource_type="AWS::Bedrock::Model",
363378
remote_resource_identifier="us.anthropic.claude-3-5-haiku-20241022-v1:0",
379+
cloudformation_primary_identifier="us.anthropic.claude-3-5-haiku-20241022-v1:0",
364380
request_response_specific_attributes={
365381
_GEN_AI_SYSTEM: "aws_bedrock",
366382
_GEN_AI_REQUEST_MODEL: "us.anthropic.claude-3-5-haiku-20241022-v1:0",
@@ -386,6 +402,7 @@ def test_bedrock_runtime_invoke_model_llama(self):
386402
remote_operation="InvokeModel",
387403
remote_resource_type="AWS::Bedrock::Model",
388404
remote_resource_identifier="meta.llama3-8b-instruct-v1:0",
405+
cloudformation_primary_identifier="meta.llama3-8b-instruct-v1:0",
389406
request_response_specific_attributes={
390407
_GEN_AI_SYSTEM: "aws_bedrock",
391408
_GEN_AI_REQUEST_MODEL: "meta.llama3-8b-instruct-v1:0",
@@ -411,6 +428,7 @@ def test_bedrock_runtime_invoke_model_command(self):
411428
remote_operation="InvokeModel",
412429
remote_resource_type="AWS::Bedrock::Model",
413430
remote_resource_identifier="cohere.command-r-v1:0",
431+
cloudformation_primary_identifier="cohere.command-r-v1:0",
414432
request_response_specific_attributes={
415433
_GEN_AI_SYSTEM: "aws_bedrock",
416434
_GEN_AI_REQUEST_MODEL: "cohere.command-r-v1:0",
@@ -436,6 +454,7 @@ def test_bedrock_runtime_invoke_model_jamba(self):
436454
remote_operation="InvokeModel",
437455
remote_resource_type="AWS::Bedrock::Model",
438456
remote_resource_identifier="ai21.jamba-1-5-large-v1:0",
457+
cloudformation_primary_identifier="ai21.jamba-1-5-large-v1:0",
439458
request_response_specific_attributes={
440459
_GEN_AI_SYSTEM: "aws_bedrock",
441460
_GEN_AI_REQUEST_MODEL: "ai21.jamba-1-5-large-v1:0",
@@ -461,6 +480,7 @@ def test_bedrock_runtime_invoke_model_mistral(self):
461480
remote_operation="InvokeModel",
462481
remote_resource_type="AWS::Bedrock::Model",
463482
remote_resource_identifier="mistral.mistral-7b-instruct-v0:2",
483+
cloudformation_primary_identifier="mistral.mistral-7b-instruct-v0:2",
464484
request_response_specific_attributes={
465485
_GEN_AI_SYSTEM: "aws_bedrock",
466486
_GEN_AI_REQUEST_MODEL: "mistral.mistral-7b-instruct-v0:2",
@@ -486,6 +506,7 @@ def test_bedrock_agent_runtime_invoke_agent(self):
486506
remote_operation="InvokeAgent",
487507
remote_resource_type="AWS::Bedrock::Agent",
488508
remote_resource_identifier="test-agent",
509+
cloudformation_primary_identifier="test-agent",
489510
request_response_specific_attributes={
490511
_AWS_BEDROCK_AGENT_ID: "test-agent",
491512
},
@@ -504,6 +525,7 @@ def test_bedrock_agent_runtime_retrieve(self):
504525
remote_operation="Retrieve",
505526
remote_resource_type="AWS::Bedrock::KnowledgeBase",
506527
remote_resource_identifier="test-knowledge-base",
528+
cloudformation_primary_identifier="test-knowledge-base",
507529
request_response_specific_attributes={
508530
_AWS_BEDROCK_KNOWLEDGE_BASE_ID: "test-knowledge-base",
509531
},
@@ -522,6 +544,7 @@ def test_bedrock_agent_get_agent(self):
522544
remote_operation="GetAgent",
523545
remote_resource_type="AWS::Bedrock::Agent",
524546
remote_resource_identifier="test-agent",
547+
cloudformation_primary_identifier="test-agent",
525548
request_response_specific_attributes={
526549
_AWS_BEDROCK_AGENT_ID: "test-agent",
527550
},
@@ -540,6 +563,7 @@ def test_bedrock_agent_get_knowledge_base(self):
540563
remote_operation="GetKnowledgeBase",
541564
remote_resource_type="AWS::Bedrock::KnowledgeBase",
542565
remote_resource_identifier="test-knowledge-base",
566+
cloudformation_primary_identifier="test-knowledge-base",
543567
request_response_specific_attributes={
544568
_AWS_BEDROCK_KNOWLEDGE_BASE_ID: "test-knowledge-base",
545569
},
@@ -558,8 +582,10 @@ def test_bedrock_agent_get_data_source(self):
558582
remote_operation="GetDataSource",
559583
remote_resource_type="AWS::Bedrock::DataSource",
560584
remote_resource_identifier="test-data-source",
585+
cloudformation_primary_identifier="test-knowledge-base|test-data-source",
561586
request_response_specific_attributes={
562587
_AWS_BEDROCK_DATA_SOURCE_ID: "test-data-source",
588+
_AWS_BEDROCK_KNOWLEDGE_BASE_ID: "test-knowledge-base"
563589
},
564590
span_name="Bedrock Agent.GetDataSource",
565591
)
@@ -580,6 +606,7 @@ def _assert_aws_span_attributes(self, resource_scope_spans: List[ResourceScopeSp
580606
"CLIENT",
581607
kwargs.get("remote_resource_type", "None"),
582608
kwargs.get("remote_resource_identifier", "None"),
609+
kwargs.get("cloudformation_primary_identifier", "None")
583610
)
584611

585612
def _assert_aws_attributes(
@@ -590,6 +617,7 @@ def _assert_aws_attributes(
590617
span_kind: str,
591618
remote_resource_type: str,
592619
remote_resource_identifier: str,
620+
cloudformation_primary_identifier: str
593621
) -> None:
594622
attributes_dict: Dict[str, AnyValue] = self._get_attributes_dict(attributes_list)
595623
self._assert_str_attribute(attributes_dict, AWS_LOCAL_SERVICE, self.get_application_otel_service_name())
@@ -599,6 +627,8 @@ def _assert_aws_attributes(
599627
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_TYPE, remote_resource_type)
600628
if remote_resource_identifier != "None":
601629
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_IDENTIFIER, remote_resource_identifier)
630+
if cloudformation_primary_identifier != "None":
631+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_CLOUDFORMATION_PRIMARY_IDENTIFIER, cloudformation_primary_identifier)
602632
self._assert_str_attribute(attributes_dict, AWS_SPAN_KIND, span_kind)
603633

604634
@override

test/contract-tests/tests/test/amazon/utils/application_signals_constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
AWS_REMOTE_OPERATION: str = "aws.remote.operation"
1717
AWS_REMOTE_RESOURCE_TYPE: str = "aws.remote.resource.type"
1818
AWS_REMOTE_RESOURCE_IDENTIFIER: str = "aws.remote.resource.identifier"
19+
AWS_REMOTE_CLOUDFORMATION_PRIMARY_IDENTIFIER: str = "aws.remote.resource.cfn.primary.identifier"
1920
AWS_SPAN_KIND: str = "aws.span.kind"
2021
HTTP_RESPONSE_STATUS: str = "http.response.status_code"
2122
HTTP_REQUEST_METHOD: str = "http.request.method"

0 commit comments

Comments
 (0)