1616if MYPY :
1717 from typing import Any
1818 from typing import Callable
19+ from typing import Optional
1920 from typing import TypeVar
2021
22+ from sentry_sdk .tracing import Span
23+
2124 F = TypeVar ("F" , bound = Callable [..., Any ])
2225
2326_import_string_should_wrap_middleware = ContextVar (
3033 import_string_name = "import_string"
3134
3235
36+ if DJANGO_VERSION < (3 , 1 ):
37+ _asgi_middleware_mixin_factory = lambda _ : object
38+ else :
39+ from .asgi import _asgi_middleware_mixin_factory
40+
41+
3342def patch_django_middlewares ():
3443 # type: () -> None
3544 from django .core .handlers import base
@@ -64,29 +73,40 @@ def _wrap_middleware(middleware, middleware_name):
6473 # type: (Any, str) -> Any
6574 from sentry_sdk .integrations .django import DjangoIntegration
6675
76+ def _check_middleware_span (old_method ):
77+ # type: (Callable[..., Any]) -> Optional[Span]
78+ hub = Hub .current
79+ integration = hub .get_integration (DjangoIntegration )
80+ if integration is None or not integration .middleware_spans :
81+ return None
82+
83+ function_name = transaction_from_function (old_method )
84+
85+ description = middleware_name
86+ function_basename = getattr (old_method , "__name__" , None )
87+ if function_basename :
88+ description = "{}.{}" .format (description , function_basename )
89+
90+ middleware_span = hub .start_span (
91+ op = "django.middleware" , description = description
92+ )
93+ middleware_span .set_tag ("django.function_name" , function_name )
94+ middleware_span .set_tag ("django.middleware_name" , middleware_name )
95+
96+ return middleware_span
97+
6798 def _get_wrapped_method (old_method ):
6899 # type: (F) -> F
69100 with capture_internal_exceptions ():
70101
71102 def sentry_wrapped_method (* args , ** kwargs ):
72103 # type: (*Any, **Any) -> Any
73- hub = Hub .current
74- integration = hub .get_integration (DjangoIntegration )
75- if integration is None or not integration .middleware_spans :
76- return old_method (* args , ** kwargs )
77-
78- function_name = transaction_from_function (old_method )
104+ middleware_span = _check_middleware_span (old_method )
79105
80- description = middleware_name
81- function_basename = getattr (old_method , "__name__" , None )
82- if function_basename :
83- description = "{}.{}" .format (description , function_basename )
106+ if middleware_span is None :
107+ return old_method (* args , ** kwargs )
84108
85- with hub .start_span (
86- op = "django.middleware" , description = description
87- ) as span :
88- span .set_tag ("django.function_name" , function_name )
89- span .set_tag ("django.middleware_name" , middleware_name )
109+ with middleware_span :
90110 return old_method (* args , ** kwargs )
91111
92112 try :
@@ -102,11 +122,22 @@ def sentry_wrapped_method(*args, **kwargs):
102122
103123 return old_method
104124
105- class SentryWrappingMiddleware (object ):
106- def __init__ (self , * args , ** kwargs ):
107- # type: (*Any, **Any) -> None
108- self ._inner = middleware (* args , ** kwargs )
125+ class SentryWrappingMiddleware (
126+ _asgi_middleware_mixin_factory (_check_middleware_span ) # type: ignore
127+ ):
128+
129+ async_capable = getattr (middleware , "async_capable" , False )
130+
131+ def __init__ (self , get_response = None , * args , ** kwargs ):
132+ # type: (Optional[Callable[..., Any]], *Any, **Any) -> None
133+ if get_response :
134+ self ._inner = middleware (get_response , * args , ** kwargs )
135+ else :
136+ self ._inner = middleware (* args , ** kwargs )
137+ self .get_response = get_response
109138 self ._call_method = None
139+ if self .async_capable :
140+ super (SentryWrappingMiddleware , self ).__init__ (get_response )
110141
111142 # We need correct behavior for `hasattr()`, which we can only determine
112143 # when we have an instance of the middleware we're wrapping.
@@ -128,10 +159,20 @@ def __getattr__(self, method_name):
128159
129160 def __call__ (self , * args , ** kwargs ):
130161 # type: (*Any, **Any) -> Any
162+ if hasattr (self , "async_route_check" ) and self .async_route_check ():
163+ return self .__acall__ (* args , ** kwargs )
164+
131165 f = self ._call_method
132166 if f is None :
133- self ._call_method = f = _get_wrapped_method (self ._inner .__call__ )
134- return f (* args , ** kwargs )
167+ self ._call_method = f = self ._inner .__call__
168+
169+ middleware_span = _check_middleware_span (old_method = f )
170+
171+ if middleware_span is None :
172+ return f (* args , ** kwargs )
173+
174+ with middleware_span :
175+ return f (* args , ** kwargs )
135176
136177 if hasattr (middleware , "__name__" ):
137178 SentryWrappingMiddleware .__name__ = middleware .__name__
0 commit comments