Skip to content

Commit 9acc119

Browse files
authored
feat: Add tracing and transaction names to aiohttp (getsentry#467)
1 parent 34d8a03 commit 9acc119

File tree

3 files changed

+69
-9
lines changed

3 files changed

+69
-9
lines changed

mypy.ini

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ disallow_untyped_defs = False
3535
disallow_any_generics = False
3636
disallow_untyped_defs = False
3737

38+
[mypy-sentry_sdk.integrations.aiohttp]
39+
disallow_any_generics = True
40+
disallow_untyped_defs = True
41+
3842
[mypy-sentry_sdk.utils]
3943
disallow_any_generics = False
4044
disallow_untyped_defs = False

sentry_sdk/integrations/aiohttp.py

+36-9
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,25 @@
99
from sentry_sdk.utils import (
1010
capture_internal_exceptions,
1111
event_from_exception,
12+
transaction_from_function,
1213
HAS_REAL_CONTEXTVARS,
1314
)
1415

1516
import asyncio
16-
from aiohttp.web import Application, HTTPException # type: ignore
17+
from aiohttp.web import Application, HTTPException, UrlDispatcher # type: ignore
1718

1819
from sentry_sdk._types import MYPY
1920

2021
if MYPY:
2122
from aiohttp.web_request import Request # type: ignore
23+
from aiohttp.abc import AbstractMatchInfo # type: ignore
2224
from typing import Any
2325
from typing import Dict
2426
from typing import Tuple
2527
from typing import Callable
2628

2729
from sentry_sdk.utils import ExcInfo
30+
from sentry_sdk._types import EventProcessor
2831

2932

3033
class AioHttpIntegration(Integration):
@@ -60,14 +63,17 @@ async def inner():
6063
scope.clear_breadcrumbs()
6164
scope.add_event_processor(_make_request_processor(weak_request))
6265

63-
try:
64-
response = await old_handle(self, request)
65-
except HTTPException:
66-
raise
67-
except Exception:
68-
reraise(*_capture_exception(hub))
66+
# If this transaction name makes it to the UI, AIOHTTP's
67+
# URL resolver did not find a route or died trying.
68+
with hub.span(transaction="generic AIOHTTP request"):
69+
try:
70+
response = await old_handle(self, request)
71+
except HTTPException:
72+
raise
73+
except Exception:
74+
reraise(*_capture_exception(hub))
6975

70-
return response
76+
return response
7177

7278
# Explicitly wrap in task such that current contextvar context is
7379
# copied. Just doing `return await inner()` will leak scope data
@@ -76,9 +82,30 @@ async def inner():
7682

7783
Application._handle = sentry_app_handle
7884

85+
old_urldispatcher_resolve = UrlDispatcher.resolve
86+
87+
async def sentry_urldispatcher_resolve(self, request):
88+
# type: (UrlDispatcher, Request) -> AbstractMatchInfo
89+
rv = await old_urldispatcher_resolve(self, request)
90+
91+
name = None
92+
93+
try:
94+
name = transaction_from_function(rv.handler)
95+
except Exception:
96+
pass
97+
98+
if name is not None:
99+
with Hub.current.configure_scope() as scope:
100+
scope.transaction = name
101+
102+
return rv
103+
104+
UrlDispatcher.resolve = sentry_urldispatcher_resolve
105+
79106

80107
def _make_request_processor(weak_request):
81-
# type: (Callable[[], Request]) -> Callable
108+
# type: (Callable[[], Request]) -> EventProcessor
82109
def aiohttp_processor(
83110
event, # type: Dict[str, Any]
84111
hint, # type: Dict[str, Tuple[type, BaseException, Any]]

tests/integrations/aiohttp/test_aiohttp.py

+29
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ async def hello(request):
2020

2121
event, = events
2222

23+
assert (
24+
event["transaction"]
25+
== "tests.integrations.aiohttp.test_aiohttp.test_basic.<locals>.hello"
26+
)
27+
2328
exception, = event["exception"]["values"]
2429
assert exception["type"] == "ZeroDivisionError"
2530
request = event["request"]
@@ -72,3 +77,27 @@ async def hello(request):
7277
assert resp.status == 200
7378

7479
assert events == []
80+
81+
82+
async def test_tracing(sentry_init, aiohttp_client, loop, capture_events):
83+
sentry_init(integrations=[AioHttpIntegration()], traces_sample_rate=1.0)
84+
85+
async def hello(request):
86+
return web.Response(text="hello")
87+
88+
app = web.Application()
89+
app.router.add_get("/", hello)
90+
91+
events = capture_events()
92+
93+
client = await aiohttp_client(app)
94+
resp = await client.get("/")
95+
assert resp.status == 200
96+
97+
event, = events
98+
99+
assert event["type"] == "transaction"
100+
assert (
101+
event["transaction"]
102+
== "tests.integrations.aiohttp.test_aiohttp.test_tracing.<locals>.hello"
103+
)

0 commit comments

Comments
 (0)