11import json
2+ import sys
23
3- from sentry_sdk .hub import _should_send_default_pii
4+ import sentry_sdk
5+ from sentry_sdk .hub import _internal_exceptions , _should_send_default_pii
46from sentry_sdk .event import AnnotatedValue
7+ from sentry_sdk ._compat import reraise , implements_iterator
58
69
710def get_environ (environ ):
@@ -38,28 +41,11 @@ def __init__(self, request):
3841 self .request = request
3942
4043 def extract_into_event (self , event , client_options ):
41- if "request" in event :
42- return
43-
44- # if the code below fails halfway through we at least have some data
45- event ["request" ] = request_info = {}
46-
44+ request_info = event .setdefault ("request" , {})
4745 request_info ["url" ] = self .url
48- request_info ["query_string" ] = self .query_string
49- request_info ["method" ] = self .method
50-
51- request_info ["env" ] = dict (get_environ (self .env ))
5246
5347 if _should_send_default_pii ():
54- request_info ["headers" ] = dict (self .headers )
5548 request_info ["cookies" ] = dict (self .cookies )
56- else :
57- request_info ["headers" ] = {
58- k : v
59- for k , v in dict (self .headers ).items ()
60- if k .lower ().replace ("_" , "-" )
61- not in ("set-cookie" , "cookie" , "authentication" )
62- }
6349
6450 bodies = client_options .get ("request_bodies" )
6551 if (
@@ -108,22 +94,6 @@ def content_length(self):
10894 def url (self ):
10995 raise NotImplementedError ()
11096
111- @property
112- def query_string (self ):
113- return self .env .get ("QUERY_STRING" )
114-
115- @property
116- def method (self ):
117- return self .env .get ("REQUEST_METHOD" )
118-
119- @property
120- def headers (self ):
121- return get_headers (self .env )
122-
123- @property
124- def env (self ):
125- raise NotImplementedError ()
126-
12797 @property
12898 def cookies (self ):
12999 raise NotImplementedError ()
@@ -136,10 +106,6 @@ def raw_data(self):
136106 def form (self ):
137107 raise NotImplementedError ()
138108
139- @property
140- def form_is_multipart (self ):
141- return self .env .get ("CONTENT_TYPE" ).startswith ("multipart/form-data" )
142-
143109 @property
144110 def is_json (self ):
145111 mt = (self .env .get ("CONTENT_TYPE" ) or "" ).split (";" , 1 )[0 ]
@@ -177,3 +143,89 @@ def get_client_ip(environ):
177143 return environ ["HTTP_X_FORWARDED_FOR" ].split ("," )[0 ].strip ()
178144 except (KeyError , IndexError ):
179145 return environ .get ("REMOTE_ADDR" )
146+
147+
148+ def run_wsgi_app (app , environ , start_response ):
149+ hub = sentry_sdk .get_current_hub ()
150+ hub .push_scope ()
151+ with _internal_exceptions ():
152+ client_options = sentry_sdk .get_current_hub ().client .options
153+ sentry_sdk .get_current_hub ().add_event_processor (
154+ lambda : _make_wsgi_event_processor (environ , client_options )
155+ )
156+
157+ try :
158+ rv = app (environ , start_response )
159+ except Exception :
160+ einfo = sys .exc_info ()
161+ sentry_sdk .capture_exception (einfo )
162+ hub .pop_scope_unsafe ()
163+ reraise (* einfo )
164+
165+ return _ScopePoppingResponse (hub , rv )
166+
167+
168+ @implements_iterator
169+ class _ScopePoppingResponse (object ):
170+ __slots__ = ("_response" , "_hub" )
171+
172+ def __init__ (self , hub , response ):
173+ self ._hub = hub
174+ self ._response = response
175+
176+ def __iter__ (self ):
177+ try :
178+ self ._response = iter (self ._response )
179+ except Exception :
180+ einfo = sys .exc_info ()
181+ sentry_sdk .capture_exception (einfo )
182+ reraise (* einfo )
183+ return self
184+
185+ def __next__ (self ):
186+ try :
187+ return next (self ._response )
188+ except StopIteration :
189+ raise
190+ except Exception :
191+ einfo = sys .exc_info ()
192+ sentry_sdk .capture_exception (einfo )
193+ reraise (* einfo )
194+
195+ def close (self ):
196+ self ._hub .pop_scope_unsafe ()
197+ if hasattr (self ._response , "close" ):
198+ try :
199+ self ._response .close ()
200+ except Exception :
201+ einfo = sys .exc_info ()
202+ sentry_sdk .capture_exception (einfo )
203+ reraise (* einfo )
204+
205+
206+ def _make_wsgi_event_processor (environ , client_options ):
207+ def event_processor (event ):
208+ with _internal_exceptions ():
209+ # if the code below fails halfway through we at least have some data
210+ request_info = event .setdefault ("request" , {})
211+
212+ if "query_string" not in request_info :
213+ request_info ["query_string" ] = environ .get ("QUERY_STRING" )
214+
215+ if "method" not in request_info :
216+ request_info ["method" ] = environ .get ("REQUEST_METHOD" )
217+
218+ if "env" not in request_info :
219+ request_info ["env" ] = dict (get_environ (environ ))
220+
221+ if "headers" not in request_info :
222+ request_info ["headers" ] = dict (get_headers (environ ))
223+ if not _should_send_default_pii ():
224+ request_info ["headers" ] = {
225+ k : v
226+ for k , v in request_info ["headers" ].items ()
227+ if k .lower ().replace ("_" , "-" )
228+ not in ("set-cookie" , "cookie" , "authorization" )
229+ }
230+
231+ return event_processor
0 commit comments