9
9
parse_version ,
10
10
transaction_from_function ,
11
11
)
12
- from sentry_sdk .integrations import Integration , DidNotEnable
12
+ from sentry_sdk .integrations import (
13
+ Integration ,
14
+ DidNotEnable ,
15
+ _DEFAULT_FAILED_REQUEST_STATUS_CODES ,
16
+ )
13
17
from sentry_sdk .integrations .wsgi import SentryWsgiMiddleware
14
18
from sentry_sdk .integrations ._wsgi_common import RequestExtractor
15
19
16
20
from typing import TYPE_CHECKING
17
21
18
22
if TYPE_CHECKING :
23
+ from collections .abc import Set
24
+
19
25
from sentry_sdk .integrations .wsgi import _ScopedResponse
20
26
from typing import Any
21
27
from typing import Dict
28
34
try :
29
35
from bottle import (
30
36
Bottle ,
37
+ HTTPResponse ,
31
38
Route ,
32
39
request as bottle_request ,
33
40
__version__ as BOTTLE_VERSION ,
@@ -45,15 +52,21 @@ class BottleIntegration(Integration):
45
52
46
53
transaction_style = ""
47
54
48
- def __init__ (self , transaction_style = "endpoint" ):
49
- # type: (str) -> None
55
+ def __init__ (
56
+ self ,
57
+ transaction_style = "endpoint" , # type: str
58
+ * ,
59
+ failed_request_status_codes = _DEFAULT_FAILED_REQUEST_STATUS_CODES , # type: Set[int]
60
+ ):
61
+ # type: (...) -> None
50
62
51
63
if transaction_style not in TRANSACTION_STYLE_VALUES :
52
64
raise ValueError (
53
65
"Invalid value for transaction_style: %s (must be in %s)"
54
66
% (transaction_style , TRANSACTION_STYLE_VALUES )
55
67
)
56
68
self .transaction_style = transaction_style
69
+ self .failed_request_status_codes = failed_request_status_codes
57
70
58
71
@staticmethod
59
72
def setup_once ():
@@ -102,26 +115,29 @@ def _patched_handle(self, environ):
102
115
103
116
old_make_callback = Route ._make_callback
104
117
105
- @ensure_integration_enabled ( BottleIntegration , old_make_callback )
118
+ @functools . wraps ( old_make_callback )
106
119
def patched_make_callback (self , * args , ** kwargs ):
107
120
# type: (Route, *object, **object) -> Any
108
- client = sentry_sdk .get_client ()
109
121
prepared_callback = old_make_callback (self , * args , ** kwargs )
110
122
123
+ integration = sentry_sdk .get_client ().get_integration (BottleIntegration )
124
+ if integration is None :
125
+ return prepared_callback
126
+
111
127
def wrapped_callback (* args , ** kwargs ):
112
128
# type: (*object, **object) -> Any
113
-
114
129
try :
115
130
res = prepared_callback (* args , ** kwargs )
116
131
except Exception as exception :
117
- event , hint = event_from_exception (
118
- exception ,
119
- client_options = client .options ,
120
- mechanism = {"type" : "bottle" , "handled" : False },
121
- )
122
- sentry_sdk .capture_event (event , hint = hint )
132
+ _capture_exception (exception , handled = False )
123
133
raise exception
124
134
135
+ if (
136
+ isinstance (res , HTTPResponse )
137
+ and res .status_code in integration .failed_request_status_codes
138
+ ):
139
+ _capture_exception (res , handled = True )
140
+
125
141
return res
126
142
127
143
return wrapped_callback
@@ -191,3 +207,13 @@ def event_processor(event, hint):
191
207
return event
192
208
193
209
return event_processor
210
+
211
+
212
+ def _capture_exception (exception , handled ):
213
+ # type: (BaseException, bool) -> None
214
+ event , hint = event_from_exception (
215
+ exception ,
216
+ client_options = sentry_sdk .get_client ().options ,
217
+ mechanism = {"type" : "bottle" , "handled" : handled },
218
+ )
219
+ sentry_sdk .capture_event (event , hint = hint )
0 commit comments