Skip to content

Commit f4f3042

Browse files
authored
fix(async-io): check for __name__ atribute when tracing coroutine (#2521)
1 parent f8758c6 commit f4f3042

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5353
([#2474](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2474))
5454
- `opentelemetry-instrumentation-elasticsearch` Improved support for version 8
5555
([#2420](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2420))
56+
- `opentelemetry-instrumentation-asyncio` Check for __name__ attribute in the coroutine
57+
([#2521](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2521))
5658

5759
## Version 1.24.0/0.45b0 (2024-03-28)
5860

Diff for: instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ def trace_item(self, coro_or_future):
261261
return coro_or_future
262262

263263
async def trace_coroutine(self, coro):
264+
if not hasattr(coro, "__name__"):
265+
return
264266
start = default_timer()
265267
attr = {
266268
"type": "coroutine",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import asyncio
15+
from unittest.mock import patch
16+
17+
# pylint: disable=no-name-in-module
18+
from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor
19+
from opentelemetry.instrumentation.asyncio.environment_variables import (
20+
OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE,
21+
)
22+
from opentelemetry.test.test_base import TestBase
23+
from opentelemetry.trace import get_tracer
24+
25+
26+
class TestAsyncioAnext(TestBase):
27+
@patch.dict(
28+
"os.environ",
29+
{OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "async_func"},
30+
)
31+
def setUp(self):
32+
super().setUp()
33+
AsyncioInstrumentor().instrument()
34+
self._tracer = get_tracer(
35+
__name__,
36+
)
37+
38+
def tearDown(self):
39+
super().tearDown()
40+
AsyncioInstrumentor().uninstrument()
41+
42+
# Asyncio anext() does not have __name__ attribute, which is used to determine if the coroutine should be traced.
43+
# This test is to ensure that the instrumentation does not break when the coroutine does not have __name__ attribute.
44+
def test_asyncio_anext(self):
45+
async def main():
46+
async def async_gen():
47+
for it in range(2):
48+
yield it
49+
50+
async_gen_instance = async_gen()
51+
agen = anext(async_gen_instance)
52+
await asyncio.create_task(agen)
53+
54+
asyncio.run(main())
55+
spans = self.memory_exporter.get_finished_spans()
56+
self.assertEqual(len(spans), 0)

0 commit comments

Comments
 (0)