Skip to content

Commit fc080db

Browse files
committed
feat(asyncio): Allow to turn task spans off
1 parent 33ba1d2 commit fc080db

File tree

2 files changed

+88
-4
lines changed

2 files changed

+88
-4
lines changed

sentry_sdk/integrations/asyncio.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sentry_sdk
55
from sentry_sdk.consts import OP
66
from sentry_sdk.integrations import Integration, DidNotEnable
7+
from sentry_sdk.integrations._wsgi_common import nullcontext
78
from sentry_sdk.utils import event_from_exception, logger, reraise
89

910
try:
@@ -60,11 +61,22 @@ def _sentry_task_factory(
6061
async def _task_with_sentry_span_creation() -> "Any":
6162
result = None
6263

64+
integration = sentry_sdk.get_client().get_integration(
65+
AsyncioIntegration
66+
)
67+
task_spans = (
68+
integration.task_spans if integration is not None else True
69+
)
70+
6371
with sentry_sdk.isolation_scope():
64-
with sentry_sdk.start_span(
65-
op=OP.FUNCTION,
66-
name=get_name(coro),
67-
origin=AsyncioIntegration.origin,
72+
with (
73+
sentry_sdk.start_span(
74+
op=OP.FUNCTION,
75+
name=get_name(coro),
76+
origin=AsyncioIntegration.origin,
77+
)
78+
if task_spans
79+
else nullcontext()
6880
):
6981
try:
7082
result = await coro
@@ -140,6 +152,9 @@ class AsyncioIntegration(Integration):
140152
identifier = "asyncio"
141153
origin = f"auto.function.{identifier}"
142154

155+
def __init__(self, task_spans: bool = True) -> None:
156+
self.task_spans = task_spans
157+
143158
@staticmethod
144159
def setup_once() -> None:
145160
patch_asyncio()

tests/integrations/asyncio/test_asyncio.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,75 @@ async def test_span_origin(
395395
assert event["spans"][0]["origin"] == "auto.function.asyncio"
396396

397397

398+
@minimum_python_38
399+
@pytest.mark.asyncio
400+
async def test_task_spans_false(
401+
sentry_init,
402+
capture_events,
403+
uninstall_integration,
404+
):
405+
"""
406+
Test that task_spans=False disables span creation but retains scope isolation.
407+
"""
408+
uninstall_integration("asyncio")
409+
410+
sentry_init(
411+
traces_sample_rate=1.0,
412+
integrations=[
413+
AsyncioIntegration(task_spans=False),
414+
],
415+
)
416+
417+
events = capture_events()
418+
419+
with sentry_sdk.start_transaction(name="test_no_spans"):
420+
with sentry_sdk.start_span(op="root", name="root span"):
421+
tasks = [asyncio.create_task(foo()), asyncio.create_task(bar())]
422+
await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
423+
424+
sentry_sdk.flush()
425+
426+
(transaction_event,) = events
427+
428+
# Only the root span should be present, no asyncio spans
429+
assert len(transaction_event["spans"]) == 1
430+
assert transaction_event["spans"][0]["op"] == "root"
431+
assert transaction_event["spans"][0]["description"] == "root span"
432+
433+
434+
@minimum_python_38
435+
@pytest.mark.asyncio
436+
async def test_enable_asyncio_integration_with_task_spans_false(
437+
sentry_init,
438+
capture_events,
439+
uninstall_integration,
440+
):
441+
"""
442+
Test that enable_asyncio_integration() helper works with task_spans=False.
443+
"""
444+
uninstall_integration("asyncio")
445+
446+
sentry_init(traces_sample_rate=1.0)
447+
448+
assert "asyncio" not in sentry_sdk.get_client().integrations
449+
450+
enable_asyncio_integration(task_spans=False)
451+
452+
assert "asyncio" in sentry_sdk.get_client().integrations
453+
assert sentry_sdk.get_client().integrations["asyncio"].task_spans is False
454+
455+
events = capture_events()
456+
457+
with sentry_sdk.start_transaction(name="test"):
458+
await asyncio.create_task(foo())
459+
460+
sentry_sdk.flush()
461+
462+
(transaction,) = events
463+
# No asyncio spans should be created
464+
assert not transaction["spans"]
465+
466+
398467
@minimum_python_38
399468
@pytest.mark.asyncio
400469
async def test_delayed_enable_integration(sentry_init, capture_events):

0 commit comments

Comments
 (0)