Skip to content

Commit a7b6623

Browse files
authored
ref(pyramid): Errorhandlers now swallow events (#382)
Exceptions caught by errorhandlers ("exception handling tweens" or whatever) are now not reported unless the errorhandler returned a 500 response. Exceptions *raising* from errorhandlers are still reported.
1 parent ddab2d4 commit a7b6623

File tree

2 files changed

+79
-30
lines changed

2 files changed

+79
-30
lines changed

sentry_sdk/integrations/pyramid.py

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,30 +59,42 @@ def __init__(self, transaction_style="route_name"):
5959
def setup_once():
6060
# type: () -> None
6161
from pyramid.router import Router # type: ignore
62+
from pyramid.request import Request # type: ignore
6263

6364
old_handle_request = Router.handle_request
6465

6566
def sentry_patched_handle_request(self, request, *args, **kwargs):
6667
# type: (Any, Request, *Any, **Any) -> Response
6768
hub = Hub.current
6869
integration = hub.get_integration(PyramidIntegration)
69-
if integration is None:
70-
return old_handle_request(self, request, *args, **kwargs)
71-
72-
with hub.configure_scope() as scope:
73-
scope.add_event_processor(
74-
_make_event_processor(weakref.ref(request), integration)
75-
)
70+
if integration is not None:
71+
with hub.configure_scope() as scope:
72+
scope.add_event_processor(
73+
_make_event_processor(weakref.ref(request), integration)
74+
)
7675

77-
try:
78-
return old_handle_request(self, request, *args, **kwargs)
79-
except Exception:
80-
exc_info = sys.exc_info()
81-
_capture_exception(exc_info)
82-
reraise(*exc_info)
76+
return old_handle_request(self, request, *args, **kwargs)
8377

8478
Router.handle_request = sentry_patched_handle_request
8579

80+
if hasattr(Request, "invoke_exception_view"):
81+
old_invoke_exception_view = Request.invoke_exception_view
82+
83+
def sentry_patched_invoke_exception_view(self, *args, **kwargs):
84+
rv = old_invoke_exception_view(self, *args, **kwargs)
85+
86+
if (
87+
self.exc_info
88+
and all(self.exc_info)
89+
and rv.status_int == 500
90+
and Hub.current.get_integration(PyramidIntegration) is not None
91+
):
92+
_capture_exception(self.exc_info)
93+
94+
return rv
95+
96+
Request.invoke_exception_view = sentry_patched_invoke_exception_view
97+
8698
old_wsgi_call = Router.__call__
8799

88100
def sentry_patched_wsgi_call(self, environ, start_response):
@@ -92,15 +104,23 @@ def sentry_patched_wsgi_call(self, environ, start_response):
92104
if integration is None:
93105
return old_wsgi_call(self, environ, start_response)
94106

95-
return SentryWsgiMiddleware(lambda *a, **kw: old_wsgi_call(self, *a, **kw))(
107+
def sentry_patched_inner_wsgi_call(environ, start_response):
108+
try:
109+
return old_wsgi_call(self, environ, start_response)
110+
except Exception:
111+
einfo = sys.exc_info()
112+
_capture_exception(einfo)
113+
reraise(*einfo)
114+
115+
return SentryWsgiMiddleware(sentry_patched_inner_wsgi_call)(
96116
environ, start_response
97117
)
98118

99119
Router.__call__ = sentry_patched_wsgi_call
100120

101121

102-
def _capture_exception(exc_info, **kwargs):
103-
# type: (ExcInfo, **Any) -> None
122+
def _capture_exception(exc_info):
123+
# type: (ExcInfo) -> None
104124
if exc_info[0] is None or issubclass(exc_info[0], HTTPException):
105125
return
106126
hub = Hub.current

tests/integrations/pyramid/test_pyramid.py

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
import json
2-
3-
from io import BytesIO
4-
52
import logging
6-
3+
import pkg_resources
74
import pytest
85

9-
from pyramid.authorization import ACLAuthorizationPolicy
6+
from io import BytesIO
7+
108
import pyramid.testing
119

10+
from pyramid.authorization import ACLAuthorizationPolicy
1211
from pyramid.response import Response
1312

14-
from werkzeug.test import Client
15-
1613
from sentry_sdk import capture_message, add_breadcrumb
1714
from sentry_sdk.integrations.pyramid import PyramidIntegration
1815

16+
from werkzeug.test import Client
17+
18+
19+
PYRAMID_VERSION = tuple(
20+
map(int, pkg_resources.get_distribution("pyramid").version.split("."))
21+
)
22+
1923

2024
def hi(request):
2125
capture_message("hi")
@@ -219,7 +223,7 @@ def errorhandler(exc, request):
219223
assert not events
220224

221225

222-
def test_errorhandler(
226+
def test_errorhandler_ok(
223227
sentry_init, pyramid_config, capture_exceptions, route, get_client
224228
):
225229
sentry_init(integrations=[PyramidIntegration()])
@@ -237,8 +241,36 @@ def errorhandler(exc, request):
237241
client = get_client()
238242
client.get("/")
239243

244+
assert not errors
245+
246+
247+
@pytest.mark.skipif(
248+
PYRAMID_VERSION < (1, 9),
249+
reason="We don't have the right hooks in older Pyramid versions",
250+
)
251+
def test_errorhandler_500(
252+
sentry_init, pyramid_config, capture_exceptions, route, get_client
253+
):
254+
sentry_init(integrations=[PyramidIntegration()])
255+
errors = capture_exceptions()
256+
257+
@route("/")
258+
def index(request):
259+
1 / 0
260+
261+
def errorhandler(exc, request):
262+
return Response("bad request", status=500)
263+
264+
pyramid_config.add_view(errorhandler, context=Exception)
265+
266+
client = get_client()
267+
app_iter, status, headers = client.get("/")
268+
assert b"".join(app_iter) == b"bad request"
269+
assert status.lower() == "500 internal server error"
270+
240271
error, = errors
241-
assert type(error) is Exception
272+
273+
assert isinstance(error, ZeroDivisionError)
242274

243275

244276
def test_error_in_errorhandler(
@@ -262,12 +294,9 @@ def error_handler(err, request):
262294
with pytest.raises(ZeroDivisionError):
263295
client.get("/")
264296

265-
event1, event2 = events
266-
267-
exception, = event1["exception"]["values"]
268-
assert exception["type"] == "ValueError"
297+
event, = events
269298

270-
exception = event2["exception"]["values"][-1]
299+
exception = event["exception"]["values"][-1]
271300
assert exception["type"] == "ZeroDivisionError"
272301

273302

0 commit comments

Comments
 (0)