1111from sentry_sdk import Hub , _functools
1212from sentry_sdk ._types import TYPE_CHECKING
1313from sentry_sdk .consts import OP
14+ from sentry_sdk .hub import _should_send_default_pii
1415
1516from sentry_sdk .integrations .asgi import SentryAsgiMiddleware
17+ from sentry_sdk .utils import capture_internal_exceptions
18+
19+ from django .core .handlers .wsgi import WSGIRequest
20+
1621
1722if TYPE_CHECKING :
1823 from typing import Any
24+ from typing import Dict
1925 from typing import Union
2026 from typing import Callable
2127
28+ from django .core .handlers .asgi import ASGIRequest
2229 from django .http .response import HttpResponse
2330
31+ from sentry_sdk .integrations .django import DjangoIntegration
32+ from sentry_sdk ._types import EventProcessor
33+
34+
35+ def _make_asgi_request_event_processor (request , integration ):
36+ # type: (ASGIRequest, DjangoIntegration) -> EventProcessor
37+ def asgi_request_event_processor (event , hint ):
38+ # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
39+ # if the request is gone we are fine not logging the data from
40+ # it. This might happen if the processor is pushed away to
41+ # another thread.
42+ from sentry_sdk .integrations .django import (
43+ DjangoRequestExtractor ,
44+ _set_user_info ,
45+ )
46+
47+ if request is None :
48+ return event
49+
50+ if type (request ) == WSGIRequest :
51+ return event
52+
53+ with capture_internal_exceptions ():
54+ DjangoRequestExtractor (request ).extract_into_event (event )
55+
56+ if _should_send_default_pii ():
57+ with capture_internal_exceptions ():
58+ _set_user_info (request , event )
59+
60+ return event
61+
62+ return asgi_request_event_processor
63+
2464
2565def patch_django_asgi_handler_impl (cls ):
2666 # type: (Any) -> None
@@ -31,16 +71,46 @@ def patch_django_asgi_handler_impl(cls):
3171
3272 async def sentry_patched_asgi_handler (self , scope , receive , send ):
3373 # type: (Any, Any, Any, Any) -> Any
34- if Hub .current .get_integration (DjangoIntegration ) is None :
74+ hub = Hub .current
75+ integration = hub .get_integration (DjangoIntegration )
76+ if integration is None :
3577 return await old_app (self , scope , receive , send )
3678
3779 middleware = SentryAsgiMiddleware (
3880 old_app .__get__ (self , cls ), unsafe_context_data = True
3981 )._run_asgi3
82+
4083 return await middleware (scope , receive , send )
4184
4285 cls .__call__ = sentry_patched_asgi_handler
4386
87+ modern_django_asgi_support = hasattr (cls , "create_request" )
88+ if modern_django_asgi_support :
89+ old_create_request = cls .create_request
90+
91+ def sentry_patched_create_request (self , * args , ** kwargs ):
92+ # type: (Any, *Any, **Any) -> Any
93+ hub = Hub .current
94+ integration = hub .get_integration (DjangoIntegration )
95+ if integration is None :
96+ return old_create_request (self , * args , ** kwargs )
97+
98+ with hub .configure_scope () as scope :
99+ request , error_response = old_create_request (self , * args , ** kwargs )
100+
101+ # read the body once, to signal Django to cache the body stream
102+ # so we can read the body in our event processor
103+ # (otherwise Django closes the body stream and makes it impossible to read it again)
104+ _ = request .body
105+
106+ scope .add_event_processor (
107+ _make_asgi_request_event_processor (request , integration )
108+ )
109+
110+ return request , error_response
111+
112+ cls .create_request = sentry_patched_create_request
113+
44114
45115def patch_get_response_async (cls , _before_get_response ):
46116 # type: (Any, Any) -> None
0 commit comments