11import json
2+ import contextvars
23
34import sentry_sdk
5+ from sentry_sdk .consts import OP
46from sentry_sdk .integrations import Integration
57from sentry_sdk .integrations ._wsgi_common import request_body_within_bounds
8+ from sentry_sdk .tracing import TransactionSource
69from sentry_sdk .utils import (
710 AnnotatedValue ,
811 capture_internal_exceptions ,
1821
1922if TYPE_CHECKING :
2023 from typing import Any , Callable , Dict , Optional , Union
24+ from sentry_sdk .tracing import Transaction
2125 from sentry_sdk ._types import Event , Hint
2226
2327
@@ -85,20 +89,27 @@ class SentryMiddleware(Middleware): # type: ignore[misc]
8589 DramatiqIntegration.
8690 """
8791
92+ # type: contextvars.ContextVar[Transaction]
93+ _transaction = contextvars .ContextVar ("_transaction" , default = None )
94+
8895 def before_process_message (self , broker , message ):
8996 # type: (Broker, Message) -> None
9097 integration = sentry_sdk .get_client ().get_integration (DramatiqIntegration )
9198 if integration is None :
9299 return
93100
94- message ._scope_manager = sentry_sdk .new_scope ()
95- message ._scope_manager .__enter__ ()
96-
97101 scope = sentry_sdk .get_current_scope ()
98- scope .set_transaction_name (message .actor_name )
99102 scope .set_extra ("dramatiq_message_id" , message .message_id )
100103 scope .add_event_processor (_make_message_event_processor (message , integration ))
101104
105+ transaction = sentry_sdk .start_transaction (
106+ name = message .actor_name ,
107+ op = OP .QUEUE_PROCESS ,
108+ source = TransactionSource .TASK ,
109+ )
110+ transaction .__enter__ ()
111+ self ._transaction .set (transaction )
112+
102113 def after_process_message (self , broker , message , * , result = None , exception = None ):
103114 # type: (Broker, Message, Any, Optional[Any], Optional[Exception]) -> None
104115 integration = sentry_sdk .get_client ().get_integration (DramatiqIntegration )
@@ -108,23 +119,29 @@ def after_process_message(self, broker, message, *, result=None, exception=None)
108119 actor = broker .get_actor (message .actor_name )
109120 throws = message .options .get ("throws" ) or actor .options .get ("throws" )
110121
111- try :
112- if (
113- exception is not None
114- and not (throws and isinstance (exception , throws ))
115- and not isinstance (exception , Retry )
116- ):
117- event , hint = event_from_exception (
118- exception ,
119- client_options = sentry_sdk .get_client ().options ,
120- mechanism = {
121- "type" : DramatiqIntegration .identifier ,
122- "handled" : False ,
123- },
124- )
125- sentry_sdk .capture_event (event , hint = hint )
126- finally :
127- message ._scope_manager .__exit__ (None , None , None )
122+ transaction = self ._transaction .get ()
123+
124+ is_event_capture_required = (
125+ exception is not None
126+ and not (throws and isinstance (exception , throws ))
127+ and not isinstance (exception , Retry )
128+ )
129+ if not is_event_capture_required :
130+ # normal transaction finish
131+ transaction .__exit__ (None , None , None )
132+ return
133+
134+ event , hint = event_from_exception (
135+ exception ,
136+ client_options = sentry_sdk .get_client ().options ,
137+ mechanism = {
138+ "type" : DramatiqIntegration .identifier ,
139+ "handled" : False ,
140+ },
141+ )
142+ sentry_sdk .capture_event (event , hint = hint )
143+ # transaction error
144+ transaction .__exit__ (type (exception ), exception , None )
128145
129146
130147def _make_message_event_processor (message , integration ):
0 commit comments