From ae3f3460a18ac7fb1c15c864b26f436934e78951 Mon Sep 17 00:00:00 2001 From: Luke Zhang Date: Fri, 5 Sep 2025 08:49:13 -0700 Subject: [PATCH 1/2] botocore: Add support for SNS semantic convention attribute aws.sns.topic.arn The AWS SNS semantic convention defines the attribute aws.sns.topic.arn: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/aws.md#amazon-sns-attributes Currently, this attribute is not set in the botocore instrumentation library. This PR adds support for it by setting the attribute from both the request and response objects. Tests New unit tests added and passing. Verified with: tox -e py312-test-instrumentation-botocore tox -e spellcheck tox -e lint-instrumentation-botocore tox -e ruff Backward Compatibility There is no risk of breaking existing functionality. This change only adds instrumentation for an additional AWS resource without modifying the existing behavior of the auto-instrumentation library. --- .../botocore/extensions/sns.py | 20 ++++++++++++++++ .../tests/test_botocore_sns.py | 24 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py index 3ff42a3fed..fdc0227286 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py @@ -24,6 +24,10 @@ _AwsSdkCallContext, _AwsSdkExtension, _BotocoreInstrumentorContext, + _BotoResultT, +) +from opentelemetry.semconv._incubating.attributes.aws_attributes import ( + AWS_SNS_TOPIC_ARN, ) from opentelemetry.semconv.trace import ( MessagingDestinationKindValues, @@ -161,6 +165,9 @@ def __init__(self, call_context: _AwsSdkCallContext): def extract_attributes(self, attributes: _AttributeMapT): attributes[SpanAttributes.MESSAGING_SYSTEM] = "aws.sns" + topic_arn = self._call_context.params.get("TopicArn") + if topic_arn: + attributes[AWS_SNS_TOPIC_ARN] = topic_arn if self._op: self._op.extract_attributes(self._call_context, attributes) @@ -170,3 +177,16 @@ def before_service_call( ): if self._op: self._op.before_service_call(self._call_context, span) + + def on_success( + self, + span: Span, + result: _BotoResultT, + instrumentor_context: _BotocoreInstrumentorContext, + ): + if not span.is_recording(): + return + + topic_arn = result.get("TopicArn") + if topic_arn: + span.set_attribute(AWS_SNS_TOPIC_ARN, topic_arn) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_sns.py b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_sns.py index 38bdfc28a3..4cf504bfce 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_sns.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_sns.py @@ -21,6 +21,9 @@ from moto import mock_aws from opentelemetry.instrumentation.botocore import BotocoreInstrumentor +from opentelemetry.semconv._incubating.attributes.aws_attributes import ( + AWS_SNS_TOPIC_ARN, +) from opentelemetry.semconv.trace import ( MessagingDestinationKindValues, SpanAttributes, @@ -151,6 +154,10 @@ def test_publish_injects_span(self): ) span = self.assert_span(f"{self.topic_name} send") + self.assertEqual( + topic_arn, + span.attributes[AWS_SNS_TOPIC_ARN], + ) self.assert_injected_span(message_attrs, span) def test_publish_batch_to_topic(self): @@ -188,6 +195,10 @@ def test_publish_batch_to_topic(self): MessagingDestinationKindValues.TOPIC.value, span.attributes[SpanAttributes.MESSAGING_DESTINATION_KIND], ) + self.assertEqual( + topic_arn, + span.attributes[AWS_SNS_TOPIC_ARN], + ) self.assertEqual( topic_arn, span.attributes[SpanAttributes.MESSAGING_DESTINATION], @@ -199,3 +210,16 @@ def test_publish_batch_to_topic(self): self.assert_injected_span(message1_attrs, span) self.assert_injected_span(message2_attrs, span) + + @mock_aws + def test_create_topic_span(self): + _ = self.client.create_topic(Name=self.topic_name) + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(1, len(spans)) + span = spans[0] + self.assertEqual(SpanKind.CLIENT, span.kind) + self.assertEqual("SNS.CreateTopic", span.name) + self.assertEqual( + self.topic_arn, + span.attributes[AWS_SNS_TOPIC_ARN], + ) From 65bcdb9857573fee05e2fe7f21f816d1389ec195 Mon Sep 17 00:00:00 2001 From: Luke Zhang Date: Fri, 5 Sep 2025 09:10:49 -0700 Subject: [PATCH 2/2] add changelog. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a95525734..f0a3110b4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3366](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3366)) - `opentelemetry-instrumentation`: add support for `OTEL_PYTHON_AUTO_INSTRUMENTATION_EXPERIMENTAL_GEVENT_PATCH` to inform opentelemetry-instrument about gevent monkeypatching ([#3699](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3699)) +- `opentelemetry-instrumentation-botocore`: Add support for SNS semantic convention attribute aws.sns.topic.arn + ([#3734](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3734)) ## Version 1.36.0/0.57b0 (2025-07-29)