37
37
38
38
_DEFAULT_TRANSACTION_NAME = "generic ASGI request"
39
39
40
+ TRANSACTION_STYLE_VALUES = ("endpoint" , "url" )
41
+
40
42
41
43
def _capture_exception (hub , exc ):
42
44
# type: (Hub, Any) -> None
@@ -68,10 +70,10 @@ def _looks_like_asgi3(app):
68
70
69
71
70
72
class SentryAsgiMiddleware :
71
- __slots__ = ("app" , "__call__" )
73
+ __slots__ = ("app" , "__call__" , "transaction_style" )
72
74
73
- def __init__ (self , app , unsafe_context_data = False ):
74
- # type: (Any, bool) -> None
75
+ def __init__ (self , app , unsafe_context_data = False , transaction_style = "endpoint" ):
76
+ # type: (Any, bool, str ) -> None
75
77
"""
76
78
Instrument an ASGI application with Sentry. Provides HTTP/websocket
77
79
data to sent events and basic handling for exceptions bubbling up
@@ -87,6 +89,12 @@ def __init__(self, app, unsafe_context_data=False):
87
89
"The ASGI middleware for Sentry requires Python 3.7+ "
88
90
"or the aiocontextvars package." + CONTEXTVARS_ERROR_MESSAGE
89
91
)
92
+ if transaction_style not in TRANSACTION_STYLE_VALUES :
93
+ raise ValueError (
94
+ "Invalid value for transaction_style: %s (must be in %s)"
95
+ % (transaction_style , TRANSACTION_STYLE_VALUES )
96
+ )
97
+ self .transaction_style = transaction_style
90
98
self .app = app
91
99
92
100
if _looks_like_asgi3 (app ):
@@ -179,12 +187,21 @@ def event_processor(self, event, hint, asgi_scope):
179
187
event .get ("transaction" , _DEFAULT_TRANSACTION_NAME )
180
188
== _DEFAULT_TRANSACTION_NAME
181
189
):
182
- endpoint = asgi_scope .get ("endpoint" )
183
- # Webframeworks like Starlette mutate the ASGI env once routing is
184
- # done, which is sometime after the request has started. If we have
185
- # an endpoint, overwrite our generic transaction name.
186
- if endpoint :
187
- event ["transaction" ] = transaction_from_function (endpoint )
190
+ if self .transaction_style == "endpoint" :
191
+ endpoint = asgi_scope .get ("endpoint" )
192
+ # Webframeworks like Starlette mutate the ASGI env once routing is
193
+ # done, which is sometime after the request has started. If we have
194
+ # an endpoint, overwrite our generic transaction name.
195
+ if endpoint :
196
+ event ["transaction" ] = transaction_from_function (endpoint )
197
+ elif self .transaction_style == "url" :
198
+ # FastAPI includes the route object in the scope to let Sentry extract the
199
+ # path from it for the transaction name
200
+ route = asgi_scope .get ("route" )
201
+ if route :
202
+ path = getattr (route , "path" , None )
203
+ if path is not None :
204
+ event ["transaction" ] = path
188
205
189
206
event ["request" ] = request_info
190
207
0 commit comments