|
1 | 1 | from __future__ import absolute_import |
2 | 2 |
|
| 3 | +import inspect |
| 4 | +import threading |
| 5 | + |
3 | 6 | from sentry_sdk.hub import _should_send_default_pii, Hub |
4 | 7 | from sentry_sdk.integrations import DidNotEnable, Integration |
5 | 8 | from sentry_sdk.integrations._wsgi_common import _filter_headers |
|
11 | 14 | event_from_exception, |
12 | 15 | ) |
13 | 16 |
|
| 17 | +from sentry_sdk._functools import wraps |
14 | 18 | from sentry_sdk._types import TYPE_CHECKING |
15 | 19 |
|
16 | 20 | if TYPE_CHECKING: |
|
34 | 38 | request, |
35 | 39 | websocket, |
36 | 40 | ) |
| 41 | + from quart.scaffold import Scaffold # type: ignore |
37 | 42 | from quart.signals import ( # type: ignore |
38 | 43 | got_background_exception, |
39 | 44 | got_request_exception, |
40 | 45 | got_websocket_exception, |
41 | 46 | request_started, |
42 | 47 | websocket_started, |
43 | 48 | ) |
| 49 | + from quart.utils import is_coroutine_function # type: ignore |
44 | 50 | except ImportError: |
45 | 51 | raise DidNotEnable("Quart is not installed") |
46 | 52 |
|
@@ -71,18 +77,62 @@ def setup_once(): |
71 | 77 | got_request_exception.connect(_capture_exception) |
72 | 78 | got_websocket_exception.connect(_capture_exception) |
73 | 79 |
|
74 | | - old_app = Quart.__call__ |
| 80 | + patch_asgi_app() |
| 81 | + patch_scaffold_route() |
| 82 | + |
| 83 | + |
| 84 | +def patch_asgi_app(): |
| 85 | + # type: () -> None |
| 86 | + old_app = Quart.__call__ |
| 87 | + |
| 88 | + async def sentry_patched_asgi_app(self, scope, receive, send): |
| 89 | + # type: (Any, Any, Any, Any) -> Any |
| 90 | + if Hub.current.get_integration(QuartIntegration) is None: |
| 91 | + return await old_app(self, scope, receive, send) |
| 92 | + |
| 93 | + middleware = SentryAsgiMiddleware(lambda *a, **kw: old_app(self, *a, **kw)) |
| 94 | + middleware.__call__ = middleware._run_asgi3 |
| 95 | + return await middleware(scope, receive, send) |
| 96 | + |
| 97 | + Quart.__call__ = sentry_patched_asgi_app |
| 98 | + |
| 99 | + |
| 100 | +def patch_scaffold_route(): |
| 101 | + # type: () -> None |
| 102 | + old_route = Scaffold.route |
| 103 | + |
| 104 | + def _sentry_route(*args, **kwargs): |
| 105 | + # type: (*Any, **Any) -> Any |
| 106 | + old_decorator = old_route(*args, **kwargs) |
| 107 | + |
| 108 | + def decorator(old_func): |
| 109 | + # type: (Any) -> Any |
| 110 | + |
| 111 | + if inspect.isfunction(old_func) and not is_coroutine_function(old_func): |
| 112 | + |
| 113 | + @wraps(old_func) |
| 114 | + def _sentry_func(*args, **kwargs): |
| 115 | + # type: (*Any, **Any) -> Any |
| 116 | + hub = Hub.current |
| 117 | + integration = hub.get_integration(QuartIntegration) |
| 118 | + if integration is None: |
| 119 | + return old_func(*args, **kwargs) |
| 120 | + |
| 121 | + with hub.configure_scope() as sentry_scope: |
| 122 | + if sentry_scope.profile is not None: |
| 123 | + sentry_scope.profile.active_thread_id = ( |
| 124 | + threading.current_thread().ident |
| 125 | + ) |
| 126 | + |
| 127 | + return old_func(*args, **kwargs) |
| 128 | + |
| 129 | + return old_decorator(_sentry_func) |
75 | 130 |
|
76 | | - async def sentry_patched_asgi_app(self, scope, receive, send): |
77 | | - # type: (Any, Any, Any, Any) -> Any |
78 | | - if Hub.current.get_integration(QuartIntegration) is None: |
79 | | - return await old_app(self, scope, receive, send) |
| 131 | + return old_decorator(old_func) |
80 | 132 |
|
81 | | - middleware = SentryAsgiMiddleware(lambda *a, **kw: old_app(self, *a, **kw)) |
82 | | - middleware.__call__ = middleware._run_asgi3 |
83 | | - return await middleware(scope, receive, send) |
| 133 | + return decorator |
84 | 134 |
|
85 | | - Quart.__call__ = sentry_patched_asgi_app |
| 135 | + Scaffold.route = _sentry_route |
86 | 136 |
|
87 | 137 |
|
88 | 138 | def _set_transaction_name_and_source(scope, transaction_style, request): |
|
0 commit comments