Skip to content

Commit f965f20

Browse files
authored
Merge branch 'main' into audit-and-test-opentelemetry-instrumentation-flask-no-op-tracer
2 parents 757a10d + 66ceef5 commit f965f20

File tree

17 files changed

+325
-39
lines changed

17 files changed

+325
-39
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- `opentelemetry-instrumentation-redis` Add `sanitize_query` config option to allow query sanitization. ([#1572](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1572))
1213
- `opentelemetry-instrumentation-celery` Record exceptions as events on the span.
1314
([#1573](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1573))
1415
- Add metric instrumentation for urllib
1516
([#1553](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1553))
1617
- `opentelemetry/sdk/extension/aws` Implement [`aws.ecs.*`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/cloud_provider/aws/ecs.md) and [`aws.logs.*`](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/cloud_provider/aws/logs/) resource attributes in the `AwsEcsResourceDetector` detector when the ECS Metadata v4 is available
1718
([#1212](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1212))
19+
- `opentelemetry-instrumentation-aio-pika` Support `aio_pika` 8.x
20+
([#1481](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1481))
1821
- `opentelemetry-instrumentation-aws-lambda` Flush `MeterProvider` at end of function invocation.
1922
([#1613](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1613))
20-
- Fix aiohttp bug with unset `trace_configs` ([#1592](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1592))
23+
- Fix aiohttp bug with unset `trace_configs`
24+
([#1592](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1592))
2125
- `opentelemetry-instrumentation-django` Allow explicit `excluded_urls` configuration through `instrument()`
2226
([#1618](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1618))
2327

instrumentation/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
| Instrumentation | Supported Packages | Metrics support |
33
| --------------- | ------------------ | --------------- |
4-
| [opentelemetry-instrumentation-aio-pika](./opentelemetry-instrumentation-aio-pika) | aio_pika ~= 7.2.0 | No
4+
| [opentelemetry-instrumentation-aio-pika](./opentelemetry-instrumentation-aio-pika) | aio_pika >= 7.2.0, < 9.0.0 | No
55
| [opentelemetry-instrumentation-aiohttp-client](./opentelemetry-instrumentation-aiohttp-client) | aiohttp ~= 3.0 | No
66
| [opentelemetry-instrumentation-aiopg](./opentelemetry-instrumentation-aiopg) | aiopg >= 0.13.0, < 2.0.0 | No
77
| [opentelemetry-instrumentation-asgi](./opentelemetry-instrumentation-asgi) | asgiref ~= 3.0 | No

instrumentation/opentelemetry-instrumentation-aio-pika/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ dependencies = [
3131

3232
[project.optional-dependencies]
3333
instruments = [
34-
"aio_pika ~= 7.2.0",
34+
"aio_pika >= 7.2.0, < 9.0.0",
3535
]
3636
test = [
3737
"opentelemetry-instrumentation-aio-pika[instruments]",

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# limitations under the License.
1414
from typing import Collection
1515

16-
_instruments: Collection[str] = ("aio_pika ~= 7.2.0",)
16+
_instruments: Collection[str] = ("aio_pika >= 7.2.0, < 9.0.0",)

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
)
2525
from opentelemetry.trace import Span, SpanKind, Tracer
2626

27-
_DEFAULT_ATTRIBUTES = {SpanAttributes.MESSAGING_SYSTEM: 'rabbitmq'}
27+
_DEFAULT_ATTRIBUTES = {SpanAttributes.MESSAGING_SYSTEM: "rabbitmq"}
2828

2929

3030
class SpanBuilder:
@@ -49,18 +49,30 @@ def set_destination(self, destination: str):
4949
self._attributes[SpanAttributes.MESSAGING_DESTINATION] = destination
5050

5151
def set_channel(self, channel: AbstractChannel):
52-
url = channel.connection.connection.url
53-
self._attributes.update({
54-
SpanAttributes.NET_PEER_NAME: url.host,
55-
SpanAttributes.NET_PEER_PORT: url.port
56-
})
52+
connection = channel.connection
53+
if getattr(connection, "connection", None):
54+
# aio_rmq 7
55+
url = connection.connection.url
56+
else:
57+
# aio_rmq 8
58+
url = connection.url
59+
self._attributes.update(
60+
{
61+
SpanAttributes.NET_PEER_NAME: url.host,
62+
SpanAttributes.NET_PEER_PORT: url.port,
63+
}
64+
)
5765

5866
def set_message(self, message: AbstractMessage):
5967
properties = message.properties
6068
if properties.message_id:
61-
self._attributes[SpanAttributes.MESSAGING_MESSAGE_ID] = properties.message_id
69+
self._attributes[
70+
SpanAttributes.MESSAGING_MESSAGE_ID
71+
] = properties.message_id
6272
if properties.correlation_id:
63-
self._attributes[SpanAttributes.MESSAGING_CONVERSATION_ID] = properties.correlation_id
73+
self._attributes[
74+
SpanAttributes.MESSAGING_CONVERSATION_ID
75+
] = properties.correlation_id
6476

6577
def build(self) -> Optional[Span]:
6678
if not is_instrumentation_enabled():
@@ -69,9 +81,11 @@ def build(self) -> Optional[Span]:
6981
self._attributes[SpanAttributes.MESSAGING_OPERATION] = self._operation.value
7082
else:
7183
self._attributes[SpanAttributes.MESSAGING_TEMP_DESTINATION] = True
72-
span = self._tracer.start_span(self._generate_span_name(), kind=self._kind, attributes=self._attributes)
84+
span = self._tracer.start_span(
85+
self._generate_span_name(), kind=self._kind, attributes=self._attributes
86+
)
7387
return span
7488

7589
def _generate_span_name(self) -> str:
76-
operation_value = self._operation.value if self._operation else 'send'
77-
return f'{self._destination} {operation_value}'
90+
operation_value = self._operation.value if self._operation else "send"
91+
return f"{self._destination} {operation_value}"

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
SERVER_URL = URL(
1616
f"amqp://{SERVER_USER}:{SERVER_PASS}@{SERVER_HOST}:{SERVER_PORT}/"
1717
)
18-
CONNECTION = Namespace(connection=Namespace(url=SERVER_URL))
19-
CHANNEL = Namespace(connection=CONNECTION, loop=None)
18+
CONNECTION_7 = Namespace(connection=Namespace(url=SERVER_URL))
19+
CONNECTION_8 = Namespace(url=SERVER_URL)
20+
CHANNEL_7 = Namespace(connection=CONNECTION_7, loop=None)
21+
CHANNEL_8 = Namespace(connection=CONNECTION_8, loop=None)
2022
MESSAGE = Namespace(
2123
properties=Namespace(
2224
message_id=MESSAGE_ID, correlation_id=CORRELATION_ID, headers={}

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

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
import asyncio
15-
from unittest import TestCase, mock
15+
from unittest import TestCase, mock, skipIf
1616

17-
from aio_pika import Queue
17+
from aio_pika import Queue, version_info
1818

1919
from opentelemetry.instrumentation.aio_pika.callback_decorator import (
2020
CallbackDecorator,
@@ -23,7 +23,8 @@
2323
from opentelemetry.trace import SpanKind, get_tracer
2424

2525
from .consts import (
26-
CHANNEL,
26+
CHANNEL_7,
27+
CHANNEL_8,
2728
CORRELATION_ID,
2829
EXCHANGE_NAME,
2930
MESSAGE,
@@ -35,7 +36,8 @@
3536
)
3637

3738

38-
class TestInstrumentedQueue(TestCase):
39+
@skipIf(version_info >= (8, 0), "Only for aio_pika 7")
40+
class TestInstrumentedQueueAioRmq7(TestCase):
3941
EXPECTED_ATTRIBUTES = {
4042
SpanAttributes.MESSAGING_SYSTEM: MESSAGING_SYSTEM,
4143
SpanAttributes.MESSAGING_DESTINATION: EXCHANGE_NAME,
@@ -52,7 +54,7 @@ def setUp(self):
5254
asyncio.set_event_loop(self.loop)
5355

5456
def test_get_callback_span(self):
55-
queue = Queue(CHANNEL, QUEUE_NAME, False, False, False, None)
57+
queue = Queue(CHANNEL_7, QUEUE_NAME, False, False, False, None)
5658
tracer = mock.MagicMock()
5759
CallbackDecorator(tracer, queue)._get_span(MESSAGE)
5860
tracer.start_span.assert_called_once_with(
@@ -62,7 +64,47 @@ def test_get_callback_span(self):
6264
)
6365

6466
def test_decorate_callback(self):
65-
queue = Queue(CHANNEL, QUEUE_NAME, False, False, False, None)
67+
queue = Queue(CHANNEL_7, QUEUE_NAME, False, False, False, None)
68+
callback = mock.MagicMock(return_value=asyncio.sleep(0))
69+
with mock.patch.object(
70+
CallbackDecorator, "_get_span"
71+
) as mocked_get_callback_span:
72+
callback_decorator = CallbackDecorator(self.tracer, queue)
73+
decorated_callback = callback_decorator.decorate(callback)
74+
self.loop.run_until_complete(decorated_callback(MESSAGE))
75+
mocked_get_callback_span.assert_called_once()
76+
callback.assert_called_once_with(MESSAGE)
77+
78+
79+
@skipIf(version_info <= (8, 0), "Only for aio_pika 8")
80+
class TestInstrumentedQueueAioRmq8(TestCase):
81+
EXPECTED_ATTRIBUTES = {
82+
SpanAttributes.MESSAGING_SYSTEM: MESSAGING_SYSTEM,
83+
SpanAttributes.MESSAGING_DESTINATION: EXCHANGE_NAME,
84+
SpanAttributes.NET_PEER_NAME: SERVER_HOST,
85+
SpanAttributes.NET_PEER_PORT: SERVER_PORT,
86+
SpanAttributes.MESSAGING_MESSAGE_ID: MESSAGE_ID,
87+
SpanAttributes.MESSAGING_CONVERSATION_ID: CORRELATION_ID,
88+
SpanAttributes.MESSAGING_OPERATION: "receive",
89+
}
90+
91+
def setUp(self):
92+
self.tracer = get_tracer(__name__)
93+
self.loop = asyncio.new_event_loop()
94+
asyncio.set_event_loop(self.loop)
95+
96+
def test_get_callback_span(self):
97+
queue = Queue(CHANNEL_8, QUEUE_NAME, False, False, False, None)
98+
tracer = mock.MagicMock()
99+
CallbackDecorator(tracer, queue)._get_span(MESSAGE)
100+
tracer.start_span.assert_called_once_with(
101+
f"{EXCHANGE_NAME} receive",
102+
kind=SpanKind.CONSUMER,
103+
attributes=self.EXPECTED_ATTRIBUTES,
104+
)
105+
106+
def test_decorate_callback(self):
107+
queue = Queue(CHANNEL_8, QUEUE_NAME, False, False, False, None)
66108
callback = mock.MagicMock(return_value=asyncio.sleep(0))
67109
with mock.patch.object(
68110
CallbackDecorator, "_get_span"

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

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
# limitations under the License.
1414
import asyncio
1515
from typing import Type
16-
from unittest import TestCase, mock
16+
from unittest import TestCase, mock, skipIf
1717

18-
from aio_pika import Exchange, RobustExchange
18+
from aio_pika import Exchange, RobustExchange, version_info
1919

2020
from opentelemetry.instrumentation.aio_pika.publish_decorator import (
2121
PublishDecorator,
@@ -24,8 +24,10 @@
2424
from opentelemetry.trace import SpanKind, get_tracer
2525

2626
from .consts import (
27-
CHANNEL,
28-
CONNECTION,
27+
CHANNEL_7,
28+
CHANNEL_8,
29+
CONNECTION_7,
30+
CONNECTION_8,
2931
CORRELATION_ID,
3032
EXCHANGE_NAME,
3133
MESSAGE,
@@ -37,7 +39,8 @@
3739
)
3840

3941

40-
class TestInstrumentedExchange(TestCase):
42+
@skipIf(version_info >= (8, 0), "Only for aio_pika 7")
43+
class TestInstrumentedExchangeAioRmq7(TestCase):
4144
EXPECTED_ATTRIBUTES = {
4245
SpanAttributes.MESSAGING_SYSTEM: MESSAGING_SYSTEM,
4346
SpanAttributes.MESSAGING_DESTINATION: f"{EXCHANGE_NAME},{ROUTING_KEY}",
@@ -54,7 +57,7 @@ def setUp(self):
5457
asyncio.set_event_loop(self.loop)
5558

5659
def test_get_publish_span(self):
57-
exchange = Exchange(CONNECTION, CHANNEL, EXCHANGE_NAME)
60+
exchange = Exchange(CONNECTION_7, CHANNEL_7, EXCHANGE_NAME)
5861
tracer = mock.MagicMock()
5962
PublishDecorator(tracer, exchange)._get_publish_span(
6063
MESSAGE, ROUTING_KEY
@@ -66,7 +69,60 @@ def test_get_publish_span(self):
6669
)
6770

6871
def _test_publish(self, exchange_type: Type[Exchange]):
69-
exchange = exchange_type(CONNECTION, CHANNEL, EXCHANGE_NAME)
72+
exchange = exchange_type(CONNECTION_7, CHANNEL_7, EXCHANGE_NAME)
73+
with mock.patch.object(
74+
PublishDecorator, "_get_publish_span"
75+
) as mock_get_publish_span:
76+
with mock.patch.object(
77+
Exchange, "publish", return_value=asyncio.sleep(0)
78+
) as mock_publish:
79+
decorated_publish = PublishDecorator(
80+
self.tracer, exchange
81+
).decorate(mock_publish)
82+
self.loop.run_until_complete(
83+
decorated_publish(MESSAGE, ROUTING_KEY)
84+
)
85+
mock_publish.assert_called_once()
86+
mock_get_publish_span.assert_called_once()
87+
88+
def test_publish(self):
89+
self._test_publish(Exchange)
90+
91+
def test_robust_publish(self):
92+
self._test_publish(RobustExchange)
93+
94+
95+
@skipIf(version_info <= (8, 0), "Only for aio_pika 8")
96+
class TestInstrumentedExchangeAioRmq8(TestCase):
97+
EXPECTED_ATTRIBUTES = {
98+
SpanAttributes.MESSAGING_SYSTEM: MESSAGING_SYSTEM,
99+
SpanAttributes.MESSAGING_DESTINATION: f"{EXCHANGE_NAME},{ROUTING_KEY}",
100+
SpanAttributes.NET_PEER_NAME: SERVER_HOST,
101+
SpanAttributes.NET_PEER_PORT: SERVER_PORT,
102+
SpanAttributes.MESSAGING_MESSAGE_ID: MESSAGE_ID,
103+
SpanAttributes.MESSAGING_CONVERSATION_ID: CORRELATION_ID,
104+
SpanAttributes.MESSAGING_TEMP_DESTINATION: True,
105+
}
106+
107+
def setUp(self):
108+
self.tracer = get_tracer(__name__)
109+
self.loop = asyncio.new_event_loop()
110+
asyncio.set_event_loop(self.loop)
111+
112+
def test_get_publish_span(self):
113+
exchange = Exchange(CHANNEL_8, EXCHANGE_NAME)
114+
tracer = mock.MagicMock()
115+
PublishDecorator(tracer, exchange)._get_publish_span(
116+
MESSAGE, ROUTING_KEY
117+
)
118+
tracer.start_span.assert_called_once_with(
119+
f"{EXCHANGE_NAME},{ROUTING_KEY} send",
120+
kind=SpanKind.PRODUCER,
121+
attributes=self.EXPECTED_ATTRIBUTES,
122+
)
123+
124+
def _test_publish(self, exchange_type: Type[Exchange]):
125+
exchange = exchange_type(CONNECTION_8, CHANNEL_8, EXCHANGE_NAME)
70126
with mock.patch.object(
71127
PublishDecorator, "_get_publish_span"
72128
) as mock_get_publish_span:

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ class TestBuilder(TestCase):
2121
def test_build(self):
2222
builder = SpanBuilder(get_tracer(__name__))
2323
builder.set_as_consumer()
24-
builder.set_destination('destination')
24+
builder.set_destination("destination")
2525
span = builder.build()
2626
self.assertTrue(isinstance(span, Span))

instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,19 @@ def test_instrument_connection_after_instrument(self):
222222
spans_list = self.memory_exporter.get_finished_spans()
223223
self.assertEqual(len(spans_list), 1)
224224

225+
def test_no_op_tracer_provider(self):
226+
cnx = async_call(aiopg.connect(database="test"))
227+
AiopgInstrumentor().instrument_connection(
228+
cnx, tracer_provider=trace_api.NoOpTracerProvider()
229+
)
230+
231+
cursor = async_call(cnx.cursor())
232+
query = "SELECT * FROM test"
233+
async_call(cursor.execute(query))
234+
235+
spans_list = self.memory_exporter.get_finished_spans()
236+
self.assertEqual(len(spans_list), 0)
237+
225238
def test_custom_tracer_provider_instrument_connection(self):
226239
resource = resources.Resource.create(
227240
{"service.name": "db-test-service"}

0 commit comments

Comments
 (0)