Skip to content

Commit 5bdec78

Browse files
committed
Merge branch 'main' of https://github.com/open-telemetry/opentelemetry-python-contrib into django-issue-fix
2 parents afb0923 + edb34e6 commit 5bdec78

File tree

19 files changed

+592
-132
lines changed

19 files changed

+592
-132
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3131
([#3731](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3731))
3232
- Fix documentation order of sections and headers for Django, Flask, MySQL, mysqlclient, psycopg, psycopg2, pymysql, sqlalchemy instrumentations.
3333
([#3719](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3719))
34+
- `opentelemetry-instrumentation-httpx`: fix missing metric response attributes when tracing is disabled
35+
([#3615](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3615))
3436

3537
### Added
3638

39+
- `opentelemetry-util-genai` Add a utility to parse the `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` environment variable.
40+
Add `gen_ai_latest_experimental` as a new value to the Sem Conv stability flag ([#3716](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3716)).
3741
- `opentelemetry-instrumentation-confluent-kafka` Add support for confluent-kafka <=2.11.0
3842
([#3685](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3685))
3943
- `opentelemetry-instrumentation-system-metrics`: Add `cpython.gc.collected_objects` and `cpython.gc.uncollectable_objects` metrics
@@ -42,6 +46,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4246
([#3366](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3366))
4347
- `opentelemetry-instrumentation`: add support for `OTEL_PYTHON_AUTO_INSTRUMENTATION_EXPERIMENTAL_GEVENT_PATCH` to inform opentelemetry-instrument about gevent monkeypatching
4448
([#3699](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3699))
49+
- `opentelemetry-instrumentation-botocore`: Add support for SNS semantic convention attribute aws.sns.topic.arn
50+
([#3734](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3734))
51+
- `opentelemetry-instrumentation`: botocore: upgrade moto package from 5.0.9 to 5.1.11
52+
([#3736](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3736))
4553

4654
## Version 1.36.0/0.57b0 (2025-07-29)
4755

instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,22 @@
1616
from aio_pika.abc import AbstractChannel, AbstractMessage
1717

1818
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
19+
from opentelemetry.semconv._incubating.attributes.messaging_attributes import (
20+
MESSAGING_MESSAGE_ID,
21+
MESSAGING_OPERATION,
22+
MESSAGING_SYSTEM,
23+
)
24+
from opentelemetry.semconv._incubating.attributes.net_attributes import (
25+
NET_PEER_NAME,
26+
NET_PEER_PORT,
27+
)
1928
from opentelemetry.semconv.trace import (
2029
MessagingOperationValues,
2130
SpanAttributes,
2231
)
2332
from opentelemetry.trace import Span, SpanKind, Tracer
2433

25-
_DEFAULT_ATTRIBUTES = {SpanAttributes.MESSAGING_SYSTEM: "rabbitmq"}
34+
_DEFAULT_ATTRIBUTES = {MESSAGING_SYSTEM: "rabbitmq"}
2635

2736

2837
class SpanBuilder:
@@ -44,6 +53,8 @@ def set_operation(self, operation: MessagingOperationValues):
4453

4554
def set_destination(self, destination: str):
4655
self._destination = destination
56+
# TODO: Update this implementation once the semantic conventions for messaging stabilize
57+
# See: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/messaging.md
4758
self._attributes[SpanAttributes.MESSAGING_DESTINATION] = destination
4859

4960
def set_channel(self, channel: AbstractChannel):
@@ -61,17 +72,15 @@ def set_channel(self, channel: AbstractChannel):
6172
url = connection.url
6273
self._attributes.update(
6374
{
64-
SpanAttributes.NET_PEER_NAME: url.host,
65-
SpanAttributes.NET_PEER_PORT: url.port or 5672,
75+
NET_PEER_NAME: url.host,
76+
NET_PEER_PORT: url.port or 5672,
6677
}
6778
)
6879

6980
def set_message(self, message: AbstractMessage):
7081
properties = message.properties
7182
if properties.message_id:
72-
self._attributes[SpanAttributes.MESSAGING_MESSAGE_ID] = (
73-
properties.message_id
74-
)
83+
self._attributes[MESSAGING_MESSAGE_ID] = properties.message_id
7584
if properties.correlation_id:
7685
self._attributes[SpanAttributes.MESSAGING_CONVERSATION_ID] = (
7786
properties.correlation_id
@@ -81,10 +90,10 @@ def build(self) -> Optional[Span]:
8190
if not is_instrumentation_enabled():
8291
return None
8392
if self._operation:
84-
self._attributes[SpanAttributes.MESSAGING_OPERATION] = (
85-
self._operation.value
86-
)
93+
self._attributes[MESSAGING_OPERATION] = self._operation.value
8794
else:
95+
# TODO: Update this implementation once the semantic conventions for messaging stabilize
96+
# See: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/messaging.md
8897
self._attributes[SpanAttributes.MESSAGING_TEMP_DESTINATION] = True
8998
span = self._tracer.start_span(
9099
self._generate_span_name(),

instrumentation/opentelemetry-instrumentation-aio-pika/tests/consts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
AIOPIKA_VERSION_INFO = tuple(int(v) for v in aiopika_version.split("."))
77
MESSAGE_ID = "meesage_id"
88
CORRELATION_ID = "correlation_id"
9-
MESSAGING_SYSTEM = "rabbitmq"
9+
MESSAGING_SYSTEM_VALUE = "rabbitmq"
1010
EXCHANGE_NAME = "exchange_name"
1111
QUEUE_NAME = "queue_name"
1212
ROUTING_KEY = "routing_key"

instrumentation/opentelemetry-instrumentation-aio-pika/tests/test_callback_decorator.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@
1919
from opentelemetry.instrumentation.aio_pika.callback_decorator import (
2020
CallbackDecorator,
2121
)
22+
from opentelemetry.semconv._incubating.attributes.messaging_attributes import (
23+
MESSAGING_MESSAGE_ID,
24+
MESSAGING_OPERATION,
25+
MESSAGING_SYSTEM,
26+
)
27+
from opentelemetry.semconv._incubating.attributes.net_attributes import (
28+
NET_PEER_NAME,
29+
NET_PEER_PORT,
30+
)
2231
from opentelemetry.semconv.trace import SpanAttributes
2332
from opentelemetry.trace import SpanKind, get_tracer
2433

@@ -30,7 +39,7 @@
3039
EXCHANGE_NAME,
3140
MESSAGE,
3241
MESSAGE_ID,
33-
MESSAGING_SYSTEM,
42+
MESSAGING_SYSTEM_VALUE,
3443
QUEUE_NAME,
3544
SERVER_HOST,
3645
SERVER_PORT,
@@ -40,13 +49,13 @@
4049
@skipIf(AIOPIKA_VERSION_INFO >= (8, 0), "Only for aio_pika 7")
4150
class TestInstrumentedQueueAioRmq7(TestCase):
4251
EXPECTED_ATTRIBUTES = {
43-
SpanAttributes.MESSAGING_SYSTEM: MESSAGING_SYSTEM,
52+
MESSAGING_SYSTEM: MESSAGING_SYSTEM_VALUE,
4453
SpanAttributes.MESSAGING_DESTINATION: EXCHANGE_NAME,
45-
SpanAttributes.NET_PEER_NAME: SERVER_HOST,
46-
SpanAttributes.NET_PEER_PORT: SERVER_PORT,
47-
SpanAttributes.MESSAGING_MESSAGE_ID: MESSAGE_ID,
54+
NET_PEER_NAME: SERVER_HOST,
55+
NET_PEER_PORT: SERVER_PORT,
56+
MESSAGING_MESSAGE_ID: MESSAGE_ID,
4857
SpanAttributes.MESSAGING_CONVERSATION_ID: CORRELATION_ID,
49-
SpanAttributes.MESSAGING_OPERATION: "receive",
58+
MESSAGING_OPERATION: "receive",
5059
}
5160

5261
def setUp(self):
@@ -80,13 +89,13 @@ def test_decorate_callback(self):
8089
@skipIf(AIOPIKA_VERSION_INFO <= (8, 0), "Only for aio_pika 8")
8190
class TestInstrumentedQueueAioRmq8(TestCase):
8291
EXPECTED_ATTRIBUTES = {
83-
SpanAttributes.MESSAGING_SYSTEM: MESSAGING_SYSTEM,
92+
MESSAGING_SYSTEM: MESSAGING_SYSTEM_VALUE,
8493
SpanAttributes.MESSAGING_DESTINATION: EXCHANGE_NAME,
85-
SpanAttributes.NET_PEER_NAME: SERVER_HOST,
86-
SpanAttributes.NET_PEER_PORT: SERVER_PORT,
87-
SpanAttributes.MESSAGING_MESSAGE_ID: MESSAGE_ID,
94+
NET_PEER_NAME: SERVER_HOST,
95+
NET_PEER_PORT: SERVER_PORT,
96+
MESSAGING_MESSAGE_ID: MESSAGE_ID,
8897
SpanAttributes.MESSAGING_CONVERSATION_ID: CORRELATION_ID,
89-
SpanAttributes.MESSAGING_OPERATION: "receive",
98+
MESSAGING_OPERATION: "receive",
9099
}
91100

92101
def setUp(self):

instrumentation/opentelemetry-instrumentation-aio-pika/tests/test_publish_decorator.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121
from opentelemetry.instrumentation.aio_pika.publish_decorator import (
2222
PublishDecorator,
2323
)
24+
from opentelemetry.semconv._incubating.attributes.messaging_attributes import (
25+
MESSAGING_MESSAGE_ID,
26+
MESSAGING_SYSTEM,
27+
)
28+
from opentelemetry.semconv._incubating.attributes.net_attributes import (
29+
NET_PEER_NAME,
30+
NET_PEER_PORT,
31+
)
2432
from opentelemetry.semconv.trace import SpanAttributes
2533
from opentelemetry.trace import SpanKind, get_tracer
2634

@@ -34,7 +42,7 @@
3442
EXCHANGE_NAME,
3543
MESSAGE,
3644
MESSAGE_ID,
37-
MESSAGING_SYSTEM,
45+
MESSAGING_SYSTEM_VALUE,
3846
ROUTING_KEY,
3947
SERVER_HOST,
4048
SERVER_PORT,
@@ -44,11 +52,11 @@
4452
@skipIf(AIOPIKA_VERSION_INFO >= (8, 0), "Only for aio_pika 7")
4553
class TestInstrumentedExchangeAioRmq7(TestCase):
4654
EXPECTED_ATTRIBUTES = {
47-
SpanAttributes.MESSAGING_SYSTEM: MESSAGING_SYSTEM,
55+
MESSAGING_SYSTEM: MESSAGING_SYSTEM_VALUE,
4856
SpanAttributes.MESSAGING_DESTINATION: f"{EXCHANGE_NAME},{ROUTING_KEY}",
49-
SpanAttributes.NET_PEER_NAME: SERVER_HOST,
50-
SpanAttributes.NET_PEER_PORT: SERVER_PORT,
51-
SpanAttributes.MESSAGING_MESSAGE_ID: MESSAGE_ID,
57+
NET_PEER_NAME: SERVER_HOST,
58+
NET_PEER_PORT: SERVER_PORT,
59+
MESSAGING_MESSAGE_ID: MESSAGE_ID,
5260
SpanAttributes.MESSAGING_CONVERSATION_ID: CORRELATION_ID,
5361
SpanAttributes.MESSAGING_TEMP_DESTINATION: True,
5462
}
@@ -123,11 +131,11 @@ def test_publish_works_with_not_recording_span_robust(self):
123131
@skipIf(AIOPIKA_VERSION_INFO <= (8, 0), "Only for aio_pika 8")
124132
class TestInstrumentedExchangeAioRmq8(TestCase):
125133
EXPECTED_ATTRIBUTES = {
126-
SpanAttributes.MESSAGING_SYSTEM: MESSAGING_SYSTEM,
134+
MESSAGING_SYSTEM: MESSAGING_SYSTEM_VALUE,
127135
SpanAttributes.MESSAGING_DESTINATION: f"{EXCHANGE_NAME},{ROUTING_KEY}",
128-
SpanAttributes.NET_PEER_NAME: SERVER_HOST,
129-
SpanAttributes.NET_PEER_PORT: SERVER_PORT,
130-
SpanAttributes.MESSAGING_MESSAGE_ID: MESSAGE_ID,
136+
NET_PEER_NAME: SERVER_HOST,
137+
NET_PEER_PORT: SERVER_PORT,
138+
MESSAGING_MESSAGE_ID: MESSAGE_ID,
131139
SpanAttributes.MESSAGING_CONVERSATION_ID: CORRELATION_ID,
132140
SpanAttributes.MESSAGING_TEMP_DESTINATION: True,
133141
}

instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
_AwsSdkCallContext,
2525
_AwsSdkExtension,
2626
_BotocoreInstrumentorContext,
27+
_BotoResultT,
28+
)
29+
from opentelemetry.semconv._incubating.attributes.aws_attributes import (
30+
AWS_SNS_TOPIC_ARN,
2731
)
2832
from opentelemetry.semconv.trace import (
2933
MessagingDestinationKindValues,
@@ -161,6 +165,9 @@ def __init__(self, call_context: _AwsSdkCallContext):
161165

162166
def extract_attributes(self, attributes: _AttributeMapT):
163167
attributes[SpanAttributes.MESSAGING_SYSTEM] = "aws.sns"
168+
topic_arn = self._call_context.params.get("TopicArn")
169+
if topic_arn:
170+
attributes[AWS_SNS_TOPIC_ARN] = topic_arn
164171

165172
if self._op:
166173
self._op.extract_attributes(self._call_context, attributes)
@@ -170,3 +177,16 @@ def before_service_call(
170177
):
171178
if self._op:
172179
self._op.before_service_call(self._call_context, span)
180+
181+
def on_success(
182+
self,
183+
span: Span,
184+
result: _BotoResultT,
185+
instrumentor_context: _BotocoreInstrumentorContext,
186+
):
187+
if not span.is_recording():
188+
return
189+
190+
topic_arn = result.get("TopicArn")
191+
if topic_arn:
192+
span.set_attribute(AWS_SNS_TOPIC_ARN, topic_arn)

instrumentation/opentelemetry-instrumentation-botocore/test-requirements-0.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ iniconfig==2.0.0
1313
Jinja2==3.1.6
1414
jmespath==1.0.1
1515
MarkupSafe==2.1.5
16-
moto==5.0.9
16+
moto==5.1.11
1717
packaging==24.0
1818
pluggy==1.5.0
1919
py-cpuinfo==9.0.0

instrumentation/opentelemetry-instrumentation-botocore/test-requirements-1.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ iniconfig==2.0.0
1313
Jinja2==3.1.6
1414
jmespath==1.0.1
1515
MarkupSafe==2.1.5
16-
moto==5.0.9
16+
moto==5.1.11
1717
packaging==24.0
1818
pluggy==1.5.0
1919
py-cpuinfo==9.0.0

instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_dynamodb.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ def test_scan(self):
439439
Limit=42,
440440
Select="ALL_ATTRIBUTES",
441441
TotalSegments=17,
442-
Segment=21,
442+
Segment=16,
443443
ProjectionExpression="PE",
444444
ConsistentRead=True,
445445
ReturnConsumedCapacity="TOTAL",
@@ -448,14 +448,14 @@ def test_scan(self):
448448
span = self.assert_span("Scan")
449449
self.assert_table_names(span, self.default_table_name)
450450
self.assertEqual(
451-
21, span.attributes[SpanAttributes.AWS_DYNAMODB_SEGMENT]
451+
16, span.attributes[SpanAttributes.AWS_DYNAMODB_SEGMENT]
452452
)
453453
self.assertEqual(
454454
17, span.attributes[SpanAttributes.AWS_DYNAMODB_TOTAL_SEGMENTS]
455455
)
456-
self.assertEqual(1, span.attributes[SpanAttributes.AWS_DYNAMODB_COUNT])
456+
self.assertEqual(0, span.attributes[SpanAttributes.AWS_DYNAMODB_COUNT])
457457
self.assertEqual(
458-
1, span.attributes[SpanAttributes.AWS_DYNAMODB_SCANNED_COUNT]
458+
0, span.attributes[SpanAttributes.AWS_DYNAMODB_SCANNED_COUNT]
459459
)
460460
self.assert_attributes_to_get(span, "id", "idl")
461461
self.assert_consistent_read(span, True)

instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_sns.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
from moto import mock_aws
2222

2323
from opentelemetry.instrumentation.botocore import BotocoreInstrumentor
24+
from opentelemetry.semconv._incubating.attributes.aws_attributes import (
25+
AWS_SNS_TOPIC_ARN,
26+
)
2427
from opentelemetry.semconv.trace import (
2528
MessagingDestinationKindValues,
2629
SpanAttributes,
@@ -151,6 +154,10 @@ def test_publish_injects_span(self):
151154
)
152155

153156
span = self.assert_span(f"{self.topic_name} send")
157+
self.assertEqual(
158+
topic_arn,
159+
span.attributes[AWS_SNS_TOPIC_ARN],
160+
)
154161
self.assert_injected_span(message_attrs, span)
155162

156163
def test_publish_batch_to_topic(self):
@@ -188,6 +195,10 @@ def test_publish_batch_to_topic(self):
188195
MessagingDestinationKindValues.TOPIC.value,
189196
span.attributes[SpanAttributes.MESSAGING_DESTINATION_KIND],
190197
)
198+
self.assertEqual(
199+
topic_arn,
200+
span.attributes[AWS_SNS_TOPIC_ARN],
201+
)
191202
self.assertEqual(
192203
topic_arn,
193204
span.attributes[SpanAttributes.MESSAGING_DESTINATION],
@@ -199,3 +210,16 @@ def test_publish_batch_to_topic(self):
199210

200211
self.assert_injected_span(message1_attrs, span)
201212
self.assert_injected_span(message2_attrs, span)
213+
214+
@mock_aws
215+
def test_create_topic_span(self):
216+
_ = self.client.create_topic(Name=self.topic_name)
217+
spans = self.memory_exporter.get_finished_spans()
218+
self.assertEqual(1, len(spans))
219+
span = spans[0]
220+
self.assertEqual(SpanKind.CLIENT, span.kind)
221+
self.assertEqual("SNS.CreateTopic", span.name)
222+
self.assertEqual(
223+
self.topic_arn,
224+
span.attributes[AWS_SNS_TOPIC_ARN],
225+
)

0 commit comments

Comments
 (0)