From a93565b26732eba814d9d1f423dd0654b8259718 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Mon, 10 Oct 2022 11:34:28 +0200 Subject: [PATCH 01/15] First version of asyncio integration --- sentry_sdk/integrations/asyncio.py | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 sentry_sdk/integrations/asyncio.py diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py new file mode 100644 index 0000000000..c86ea59b4b --- /dev/null +++ b/sentry_sdk/integrations/asyncio.py @@ -0,0 +1,55 @@ +from __future__ import absolute_import + +import asyncio +from asyncio.tasks import Task + + +from sentry_sdk.hub import Hub +from sentry_sdk.integrations import Integration +from sentry_sdk._types import MYPY +from sentry_sdk.utils import logger + +if MYPY: + from typing import Any + + +def _sentry_task_factory(loop, coro): + # type: (Any, Any) -> Task + logger.debug(f"~~~~~~~~ Task Factory: {loop} / {coro}") + logger.debug(f"before hub: {Hub.current}") + logger.debug(f"before scope: {Hub.current.scope}") + logger.debug(f"before span: {Hub.current.scope.span}") + hub = Hub(Hub.current) + logger.debug(f"cloned hub: {hub}") + logger.debug(f"cloned scope: {hub.scope}") + logger.debug(f"cloned span: {hub.scope.span}") + + with hub.start_span(op="asyncprocess", description=coro.__qualname__) as span: + logger.debug(f"Created span: {span}") + # The default task factory in asyncio does not have its own function + # but is just a couple of lines in `asyncio.base_events.create_task()` + # Those lines are copied here. + + # WARNING: + # If the default behavior of the task creation in asyncio changes, + # this will break! + task = Task(coro, loop=loop) + if task._source_traceback: + del task._source_traceback[-1] + + return task + + +def patch_asyncio(): + # type: () -> None + loop = asyncio.get_running_loop() + loop.set_task_factory(_sentry_task_factory) + + +class AsyncioIntegration(Integration): + identifier = "asyncio" + + @staticmethod + def setup_once(): + # type: () -> None + patch_asyncio() From 18a02c5dcb2d2a198455b979225e5be9a7ca5c97 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Mon, 10 Oct 2022 15:51:41 +0200 Subject: [PATCH 02/15] Create a hub and span for each corotine run. --- sentry_sdk/integrations/asyncio.py | 43 +++++++++++++----------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index c86ea59b4b..c2cb1f5350 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -7,7 +7,6 @@ from sentry_sdk.hub import Hub from sentry_sdk.integrations import Integration from sentry_sdk._types import MYPY -from sentry_sdk.utils import logger if MYPY: from typing import Any @@ -15,29 +14,25 @@ def _sentry_task_factory(loop, coro): # type: (Any, Any) -> Task - logger.debug(f"~~~~~~~~ Task Factory: {loop} / {coro}") - logger.debug(f"before hub: {Hub.current}") - logger.debug(f"before scope: {Hub.current.scope}") - logger.debug(f"before span: {Hub.current.scope.span}") - hub = Hub(Hub.current) - logger.debug(f"cloned hub: {hub}") - logger.debug(f"cloned scope: {hub.scope}") - logger.debug(f"cloned span: {hub.scope.span}") - - with hub.start_span(op="asyncprocess", description=coro.__qualname__) as span: - logger.debug(f"Created span: {span}") - # The default task factory in asyncio does not have its own function - # but is just a couple of lines in `asyncio.base_events.create_task()` - # Those lines are copied here. - - # WARNING: - # If the default behavior of the task creation in asyncio changes, - # this will break! - task = Task(coro, loop=loop) - if task._source_traceback: - del task._source_traceback[-1] - - return task + + async def _coro_creating_hub_and_span(): + hub = Hub(Hub.current) + with hub: + with hub.start_span(op="asyncprocess", description=coro.__qualname__): + await coro + + # The default task factory in `asyncio`` does not have its own function + # but is just a couple of lines in `asyncio.base_events.create_task()` + # Those lines are copied here. + + # WARNING: + # If the default behavior of the task creation in asyncio changes, + # this will break! + task = Task(_coro_creating_hub_and_span(), loop=loop) + if task._source_traceback: + del task._source_traceback[-1] + + return task def patch_asyncio(): From 82f03290de0e1c70caac62b30eb7d0b78c8ee0de Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Mon, 10 Oct 2022 15:57:22 +0200 Subject: [PATCH 03/15] Fixed some typing --- sentry_sdk/integrations/asyncio.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index c2cb1f5350..fb1cb4506b 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -13,9 +13,10 @@ def _sentry_task_factory(loop, coro): - # type: (Any, Any) -> Task + # type: (Any, Any) -> Task[None] async def _coro_creating_hub_and_span(): + # type: () -> None hub = Hub(Hub.current) with hub: with hub.start_span(op="asyncprocess", description=coro.__qualname__): @@ -29,8 +30,8 @@ async def _coro_creating_hub_and_span(): # If the default behavior of the task creation in asyncio changes, # this will break! task = Task(_coro_creating_hub_and_span(), loop=loop) - if task._source_traceback: - del task._source_traceback[-1] + if task._source_traceback: # type: ignore + del task._source_traceback[-1] # type: ignore return task @@ -38,7 +39,7 @@ async def _coro_creating_hub_and_span(): def patch_asyncio(): # type: () -> None loop = asyncio.get_running_loop() - loop.set_task_factory(_sentry_task_factory) + loop.set_task_factory(_sentry_task_factory) # type: ignore class AsyncioIntegration(Integration): From 00678e0b2cc24b55c3f069e87529a78e7266d8cd Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Mon, 10 Oct 2022 15:57:22 +0200 Subject: [PATCH 04/15] Fixed some typing --- sentry_sdk/integrations/asyncio.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index c2cb1f5350..5b3bd8d05b 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -13,9 +13,10 @@ def _sentry_task_factory(loop, coro): - # type: (Any, Any) -> Task + # type: (Any, Any) -> Task[None] async def _coro_creating_hub_and_span(): + # type: () -> None hub = Hub(Hub.current) with hub: with hub.start_span(op="asyncprocess", description=coro.__qualname__): @@ -29,8 +30,8 @@ async def _coro_creating_hub_and_span(): # If the default behavior of the task creation in asyncio changes, # this will break! task = Task(_coro_creating_hub_and_span(), loop=loop) - if task._source_traceback: - del task._source_traceback[-1] + if task._source_traceback: # type: ignore + del task._source_traceback[-1] # type: ignore return task From 5ed18dad81d3bbd3e768762a21324a400f429738 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Mon, 10 Oct 2022 16:43:17 +0200 Subject: [PATCH 05/15] Fixed linting --- sentry_sdk/integrations/asyncio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index fb1cb4506b..5b3bd8d05b 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -39,7 +39,7 @@ async def _coro_creating_hub_and_span(): def patch_asyncio(): # type: () -> None loop = asyncio.get_running_loop() - loop.set_task_factory(_sentry_task_factory) # type: ignore + loop.set_task_factory(_sentry_task_factory) class AsyncioIntegration(Integration): From 64d8e1a47ff715bce16b62695cee8418f0df71cb Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 12 Oct 2022 11:10:17 +0200 Subject: [PATCH 06/15] Added tests --- sentry_sdk/integrations/asyncio.py | 2 +- tests/integrations/asyncio/__init__.py | 0 tests/integrations/asyncio/test_asyncio.py | 107 +++++++++++++++++++++ tests/integrations/conftest.py | 12 +++ 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 tests/integrations/asyncio/__init__.py create mode 100644 tests/integrations/asyncio/test_asyncio.py diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 5b3bd8d05b..1dfb76c055 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -19,7 +19,7 @@ async def _coro_creating_hub_and_span(): # type: () -> None hub = Hub(Hub.current) with hub: - with hub.start_span(op="asyncprocess", description=coro.__qualname__): + with hub.start_span(op="asynctask", description=coro.__qualname__): await coro # The default task factory in `asyncio`` does not have its own function diff --git a/tests/integrations/asyncio/__init__.py b/tests/integrations/asyncio/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/integrations/asyncio/test_asyncio.py b/tests/integrations/asyncio/test_asyncio.py new file mode 100644 index 0000000000..f29284db12 --- /dev/null +++ b/tests/integrations/asyncio/test_asyncio.py @@ -0,0 +1,107 @@ +import asyncio +import sys + +import pytest +import sentry_sdk +from sentry_sdk.integrations.asyncio import AsyncioIntegration + + +minimum_python_36 = pytest.mark.skipif( + sys.version_info < (3, 6), reason="ASGI is only supported in Python >= 3.6" +) + + +async def foo(): + await asyncio.sleep(0.01) + + +async def bar(): + await asyncio.sleep(0.01) + + +@minimum_python_36 +@pytest.mark.asyncio +async def test_create_task( + sentry_init, + capture_events, + event_loop, +): + sentry_init( + traces_sample_rate=1.0, + send_default_pii=True, + debug=True, + integrations=[ + AsyncioIntegration(), + ], + ) + + events = capture_events() + + with sentry_sdk.start_transaction(name="test_transaction_for_create_task"): + with sentry_sdk.start_span(op="root", description="not so important"): + tasks = [event_loop.create_task(foo()), event_loop.create_task(bar())] + await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) + + sentry_sdk.flush() + + (transaction_event,) = events + + assert transaction_event["spans"][0]["op"] == "root" + assert transaction_event["spans"][0]["description"] == "not so important" + + assert transaction_event["spans"][1]["op"] == "asynctask" + assert transaction_event["spans"][1]["description"] == "foo" + assert ( + transaction_event["spans"][1]["parent_span_id"] + == transaction_event["spans"][0]["span_id"] + ) + + assert transaction_event["spans"][2]["op"] == "asynctask" + assert transaction_event["spans"][2]["description"] == "bar" + assert ( + transaction_event["spans"][2]["parent_span_id"] + == transaction_event["spans"][0]["span_id"] + ) + + +@minimum_python_36 +@pytest.mark.asyncio +async def test_gather( + sentry_init, + capture_events, +): + sentry_init( + traces_sample_rate=1.0, + send_default_pii=True, + debug=True, + integrations=[ + AsyncioIntegration(), + ], + ) + + events = capture_events() + + with sentry_sdk.start_transaction(name="test_transaction_for_gather"): + with sentry_sdk.start_span(op="root", description="not so important"): + await asyncio.gather(foo(), bar(), return_exceptions=True) + + sentry_sdk.flush() + + (transaction_event,) = events + + assert transaction_event["spans"][0]["op"] == "root" + assert transaction_event["spans"][0]["description"] == "not so important" + + assert transaction_event["spans"][1]["op"] == "asynctask" + assert transaction_event["spans"][1]["description"] == "foo" + assert ( + transaction_event["spans"][1]["parent_span_id"] + == transaction_event["spans"][0]["span_id"] + ) + + assert transaction_event["spans"][2]["op"] == "asynctask" + assert transaction_event["spans"][2]["description"] == "bar" + assert ( + transaction_event["spans"][2]["parent_span_id"] + == transaction_event["spans"][0]["span_id"] + ) diff --git a/tests/integrations/conftest.py b/tests/integrations/conftest.py index cffb278d70..b5a89a82f6 100644 --- a/tests/integrations/conftest.py +++ b/tests/integrations/conftest.py @@ -1,4 +1,8 @@ +import asyncio + import pytest +import pytest_asyncio + import sentry_sdk @@ -19,3 +23,11 @@ def capture_event(self, event, hint=None): return errors return inner + + +@pytest_asyncio.fixture(scope="session") +def event_loop(request): + """Create an instance of the default event loop for each test case.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() From 8f74a501b9de06c8d5603a36541015130b2628f1 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 12 Oct 2022 11:21:04 +0200 Subject: [PATCH 07/15] Moved fixtured into test because it uses modules that are not always loaded --- tests/integrations/asyncio/test_asyncio.py | 10 ++++++++++ tests/integrations/conftest.py | 12 ------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/integrations/asyncio/test_asyncio.py b/tests/integrations/asyncio/test_asyncio.py index f29284db12..84b9889377 100644 --- a/tests/integrations/asyncio/test_asyncio.py +++ b/tests/integrations/asyncio/test_asyncio.py @@ -2,6 +2,8 @@ import sys import pytest +import pytest_asyncio + import sentry_sdk from sentry_sdk.integrations.asyncio import AsyncioIntegration @@ -19,6 +21,14 @@ async def bar(): await asyncio.sleep(0.01) +@pytest_asyncio.fixture(scope="session") +def event_loop(request): + """Create an instance of the default event loop for each test case.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + @minimum_python_36 @pytest.mark.asyncio async def test_create_task( diff --git a/tests/integrations/conftest.py b/tests/integrations/conftest.py index b5a89a82f6..cffb278d70 100644 --- a/tests/integrations/conftest.py +++ b/tests/integrations/conftest.py @@ -1,8 +1,4 @@ -import asyncio - import pytest -import pytest_asyncio - import sentry_sdk @@ -23,11 +19,3 @@ def capture_event(self, event, hint=None): return errors return inner - - -@pytest_asyncio.fixture(scope="session") -def event_loop(request): - """Create an instance of the default event loop for each test case.""" - loop = asyncio.get_event_loop_policy().new_event_loop() - yield loop - loop.close() From 3fb9d114e2645242f1cdad3aeca7d805fdb5360d Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 12 Oct 2022 13:29:00 +0200 Subject: [PATCH 08/15] Using constant --- sentry_sdk/consts.py | 1 + sentry_sdk/integrations/asyncio.py | 3 ++- tests/integrations/asyncio/test_asyncio.py | 9 +++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index b6e546e336..7c924dcad7 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -108,6 +108,7 @@ def _get_default_options(): class OP: + ASYNCTASK = "asynctask" DB = "db" DB_REDIS = "db.redis" EVENT_DJANGO = "event.django" diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 1dfb76c055..056fa4388e 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -2,6 +2,7 @@ import asyncio from asyncio.tasks import Task +from sentry_sdk.consts import OP from sentry_sdk.hub import Hub @@ -19,7 +20,7 @@ async def _coro_creating_hub_and_span(): # type: () -> None hub = Hub(Hub.current) with hub: - with hub.start_span(op="asynctask", description=coro.__qualname__): + with hub.start_span(op=OP.ASYNCTASK, description=coro.__qualname__): await coro # The default task factory in `asyncio`` does not have its own function diff --git a/tests/integrations/asyncio/test_asyncio.py b/tests/integrations/asyncio/test_asyncio.py index 84b9889377..aaca319399 100644 --- a/tests/integrations/asyncio/test_asyncio.py +++ b/tests/integrations/asyncio/test_asyncio.py @@ -5,6 +5,7 @@ import pytest_asyncio import sentry_sdk +from sentry_sdk.consts import OP from sentry_sdk.integrations.asyncio import AsyncioIntegration @@ -59,14 +60,14 @@ async def test_create_task( assert transaction_event["spans"][0]["op"] == "root" assert transaction_event["spans"][0]["description"] == "not so important" - assert transaction_event["spans"][1]["op"] == "asynctask" + assert transaction_event["spans"][1]["op"] == OP.ASYNCTASK assert transaction_event["spans"][1]["description"] == "foo" assert ( transaction_event["spans"][1]["parent_span_id"] == transaction_event["spans"][0]["span_id"] ) - assert transaction_event["spans"][2]["op"] == "asynctask" + assert transaction_event["spans"][2]["op"] == OP.ASYNCTASK assert transaction_event["spans"][2]["description"] == "bar" assert ( transaction_event["spans"][2]["parent_span_id"] @@ -102,14 +103,14 @@ async def test_gather( assert transaction_event["spans"][0]["op"] == "root" assert transaction_event["spans"][0]["description"] == "not so important" - assert transaction_event["spans"][1]["op"] == "asynctask" + assert transaction_event["spans"][1]["op"] == OP.ASYNCTASK assert transaction_event["spans"][1]["description"] == "foo" assert ( transaction_event["spans"][1]["parent_span_id"] == transaction_event["spans"][0]["span_id"] ) - assert transaction_event["spans"][2]["op"] == "asynctask" + assert transaction_event["spans"][2]["op"] == OP.ASYNCTASK assert transaction_event["spans"][2]["description"] == "bar" assert ( transaction_event["spans"][2]["parent_span_id"] From 35973755344b5256e5f6e6f53a5f8709afeea378 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 14 Oct 2022 10:09:09 +0200 Subject: [PATCH 09/15] Using the 'function' op. --- sentry_sdk/consts.py | 2 +- sentry_sdk/integrations/asyncio.py | 2 +- tests/integrations/asyncio/test_asyncio.py | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 7c924dcad7..cf81529408 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -108,10 +108,10 @@ def _get_default_options(): class OP: - ASYNCTASK = "asynctask" DB = "db" DB_REDIS = "db.redis" EVENT_DJANGO = "event.django" + FUNCTION = "function" FUNCTION_AWS = "function.aws" FUNCTION_GCP = "function.gcp" HTTP_CLIENT = "http.client" diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 056fa4388e..22a8745b89 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -20,7 +20,7 @@ async def _coro_creating_hub_and_span(): # type: () -> None hub = Hub(Hub.current) with hub: - with hub.start_span(op=OP.ASYNCTASK, description=coro.__qualname__): + with hub.start_span(op=OP.FUNCTION, description=coro.__qualname__): await coro # The default task factory in `asyncio`` does not have its own function diff --git a/tests/integrations/asyncio/test_asyncio.py b/tests/integrations/asyncio/test_asyncio.py index aaca319399..2e0643c4d2 100644 --- a/tests/integrations/asyncio/test_asyncio.py +++ b/tests/integrations/asyncio/test_asyncio.py @@ -60,14 +60,14 @@ async def test_create_task( assert transaction_event["spans"][0]["op"] == "root" assert transaction_event["spans"][0]["description"] == "not so important" - assert transaction_event["spans"][1]["op"] == OP.ASYNCTASK + assert transaction_event["spans"][1]["op"] == OP.FUNCTION assert transaction_event["spans"][1]["description"] == "foo" assert ( transaction_event["spans"][1]["parent_span_id"] == transaction_event["spans"][0]["span_id"] ) - assert transaction_event["spans"][2]["op"] == OP.ASYNCTASK + assert transaction_event["spans"][2]["op"] == OP.FUNCTION assert transaction_event["spans"][2]["description"] == "bar" assert ( transaction_event["spans"][2]["parent_span_id"] @@ -103,14 +103,14 @@ async def test_gather( assert transaction_event["spans"][0]["op"] == "root" assert transaction_event["spans"][0]["description"] == "not so important" - assert transaction_event["spans"][1]["op"] == OP.ASYNCTASK + assert transaction_event["spans"][1]["op"] == OP.FUNCTION assert transaction_event["spans"][1]["description"] == "foo" assert ( transaction_event["spans"][1]["parent_span_id"] == transaction_event["spans"][0]["span_id"] ) - assert transaction_event["spans"][2]["op"] == OP.ASYNCTASK + assert transaction_event["spans"][2]["op"] == OP.FUNCTION assert transaction_event["spans"][2]["description"] == "bar" assert ( transaction_event["spans"][2]["parent_span_id"] From 402b19261539ec392ffe245f350c7cbcff34e610 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 14 Oct 2022 10:13:18 +0200 Subject: [PATCH 10/15] Wrap import with try except --- sentry_sdk/integrations/asyncio.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 22a8745b89..4519491eac 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -1,14 +1,17 @@ from __future__ import absolute_import -import asyncio -from asyncio.tasks import Task from sentry_sdk.consts import OP - - from sentry_sdk.hub import Hub -from sentry_sdk.integrations import Integration +from sentry_sdk.integrations import Integration, DidNotEnable from sentry_sdk._types import MYPY +try: + import asyncio + from asyncio.tasks import Task +except ImportError: + raise DidNotEnable("asyncio not available") + + if MYPY: from typing import Any From d37cfb10e0e9c16d0d87dd682c3ad022231ffe88 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 14 Oct 2022 10:17:56 +0200 Subject: [PATCH 11/15] Make sure to use custom task factory if there is one --- sentry_sdk/integrations/asyncio.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 4519491eac..2164c64ac1 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -26,7 +26,12 @@ async def _coro_creating_hub_and_span(): with hub.start_span(op=OP.FUNCTION, description=coro.__qualname__): await coro - # The default task factory in `asyncio`` does not have its own function + # Trying to use user set task factory (if there is one) + orig_factory = loop.get_task_factory() + if orig_factory: + return orig_factory(loop, coro) + + # The default task factory in `asyncio` does not have its own function # but is just a couple of lines in `asyncio.base_events.create_task()` # Those lines are copied here. From 7c60637deded07f3c0d6f81e2b5d96fc1a151512 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 14 Oct 2022 14:38:58 +0200 Subject: [PATCH 12/15] Update sentry_sdk/integrations/asyncio.py Co-authored-by: Neel Shah --- sentry_sdk/integrations/asyncio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 2164c64ac1..da9279a234 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -29,7 +29,7 @@ async def _coro_creating_hub_and_span(): # Trying to use user set task factory (if there is one) orig_factory = loop.get_task_factory() if orig_factory: - return orig_factory(loop, coro) + return orig_factory(loop, _coro_creating_hub_and_span) # The default task factory in `asyncio` does not have its own function # but is just a couple of lines in `asyncio.base_events.create_task()` From 2de0b43989f0d3876ff75e69ab00d4fe369d4b9d Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 14 Oct 2022 14:41:31 +0200 Subject: [PATCH 13/15] Error handling --- sentry_sdk/integrations/asyncio.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index da9279a234..95629f98d5 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -47,8 +47,12 @@ async def _coro_creating_hub_and_span(): def patch_asyncio(): # type: () -> None - loop = asyncio.get_running_loop() - loop.set_task_factory(_sentry_task_factory) + try: + loop = asyncio.get_running_loop() + loop.set_task_factory(_sentry_task_factory) + except RuntimeError: + # When there is no running loop, we have nothing to patch. + pass class AsyncioIntegration(Integration): From e7e5ebbe2bb4946b2e3c7cffd997a15b8d2c2dd1 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Mon, 17 Oct 2022 16:33:01 +0200 Subject: [PATCH 14/15] Update sentry_sdk/integrations/asyncio.py Co-authored-by: Neel Shah --- sentry_sdk/integrations/asyncio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 95629f98d5..34289058ce 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -38,7 +38,7 @@ async def _coro_creating_hub_and_span(): # WARNING: # If the default behavior of the task creation in asyncio changes, # this will break! - task = Task(_coro_creating_hub_and_span(), loop=loop) + task = Task(_coro_creating_hub_and_span, loop=loop) if task._source_traceback: # type: ignore del task._source_traceback[-1] # type: ignore From 01a9fe61f041029a21705016fcf736ebd63a9928 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Mon, 17 Oct 2022 16:41:42 +0200 Subject: [PATCH 15/15] Ignoring typing --- sentry_sdk/integrations/asyncio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 34289058ce..ab07ffc3cb 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -38,7 +38,7 @@ async def _coro_creating_hub_and_span(): # WARNING: # If the default behavior of the task creation in asyncio changes, # this will break! - task = Task(_coro_creating_hub_and_span, loop=loop) + task = Task(_coro_creating_hub_and_span, loop=loop) # type: ignore if task._source_traceback: # type: ignore del task._source_traceback[-1] # type: ignore