Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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],
Expand All @@ -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],
)