4
4
Based on Tom Christie's `sentry-asgi <https://github.com/encode/sentry-asgi>`_.
5
5
"""
6
6
7
+ import asyncio
7
8
import functools
9
+ import inspect
8
10
import urllib
9
11
10
12
from sentry_sdk ._types import MYPY
17
19
from typing import Dict
18
20
from typing import Any
19
21
from typing import Optional
22
+ from typing import Callable
20
23
21
24
from sentry_sdk ._types import Event , Hint
22
25
@@ -37,26 +40,45 @@ def _capture_exception(hub, exc):
37
40
hub .capture_event (event , hint = hint )
38
41
39
42
43
+ def _looks_like_asgi3 (app ):
44
+ # type: (Any) -> bool
45
+ """
46
+ Try to figure out if an application object supports ASGI3.
47
+
48
+ This is how uvicorn figures out the application version as well.
49
+ """
50
+ if inspect .isclass (app ):
51
+ return hasattr (app , "__await__" )
52
+ elif inspect .isfunction (app ):
53
+ return asyncio .iscoroutinefunction (app )
54
+ else :
55
+ call = getattr (app , "__call__" , None ) # noqa
56
+ return asyncio .iscoroutinefunction (call )
57
+
58
+
40
59
class SentryAsgiMiddleware :
41
- __slots__ = ("app" ,)
60
+ __slots__ = ("app" , "__call__" )
42
61
43
62
def __init__ (self , app ):
44
63
# type: (Any) -> None
45
64
self .app = app
46
65
47
- def __call__ (self , scope , receive = None , send = None ):
48
- # type: (Any, Any, Any) -> Any
49
- if receive is None or send is None :
66
+ if _looks_like_asgi3 (app ):
67
+ self .__call__ = self ._run_asgi3 # type: Callable[..., Any]
68
+ else :
69
+ self .__call__ = self ._run_asgi2
50
70
51
- async def run_asgi2 ( receive , send ):
52
- # type: (Any, Any) -> Any
53
- return await self . _run_app (
54
- scope , lambda : self . app ( scope )( receive , send )
55
- )
71
+ def _run_asgi2 ( self , scope ):
72
+ # type: (Any) -> Any
73
+ async def inner ( receive , send ):
74
+ # type: (Any, Any) -> Any
75
+ return await self . _run_app ( scope , lambda : self . app ( scope )( receive , send ) )
56
76
57
- return run_asgi2
58
- else :
59
- return self ._run_app (scope , lambda : self .app (scope , receive , send ))
77
+ return inner
78
+
79
+ async def _run_asgi3 (self , scope , receive , send ):
80
+ # type: (Any, Any, Any) -> Any
81
+ return await self ._run_app (scope , lambda : self .app (scope , receive , send ))
60
82
61
83
async def _run_app (self , scope , callback ):
62
84
# type: (Any, Any) -> Any
0 commit comments