Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 36 additions & 16 deletions sentry_sdk/integrations/pyramid.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,30 +59,42 @@ def __init__(self, transaction_style="route_name"):
def setup_once():
# type: () -> None
from pyramid.router import Router # type: ignore
from pyramid.request import Request # type: ignore

old_handle_request = Router.handle_request

def sentry_patched_handle_request(self, request, *args, **kwargs):
# type: (Any, Request, *Any, **Any) -> Response
hub = Hub.current
integration = hub.get_integration(PyramidIntegration)
if integration is None:
return old_handle_request(self, request, *args, **kwargs)

with hub.configure_scope() as scope:
scope.add_event_processor(
_make_event_processor(weakref.ref(request), integration)
)
if integration is not None:
with hub.configure_scope() as scope:
scope.add_event_processor(
_make_event_processor(weakref.ref(request), integration)
)

try:
return old_handle_request(self, request, *args, **kwargs)
except Exception:
exc_info = sys.exc_info()
_capture_exception(exc_info)
reraise(*exc_info)
return old_handle_request(self, request, *args, **kwargs)

Router.handle_request = sentry_patched_handle_request

if hasattr(Request, "invoke_exception_view"):
old_invoke_exception_view = Request.invoke_exception_view

def sentry_patched_invoke_exception_view(self, *args, **kwargs):
rv = old_invoke_exception_view(self, *args, **kwargs)

if (
self.exc_info
and all(self.exc_info)
and rv.status_int == 500
and Hub.current.get_integration(PyramidIntegration) is not None
):
_capture_exception(self.exc_info)

return rv

Request.invoke_exception_view = sentry_patched_invoke_exception_view

old_wsgi_call = Router.__call__

def sentry_patched_wsgi_call(self, environ, start_response):
Expand All @@ -92,15 +104,23 @@ def sentry_patched_wsgi_call(self, environ, start_response):
if integration is None:
return old_wsgi_call(self, environ, start_response)

return SentryWsgiMiddleware(lambda *a, **kw: old_wsgi_call(self, *a, **kw))(
def sentry_patched_inner_wsgi_call(environ, start_response):
try:
return old_wsgi_call(self, environ, start_response)
except Exception:
einfo = sys.exc_info()
_capture_exception(einfo)
reraise(*einfo)

return SentryWsgiMiddleware(sentry_patched_inner_wsgi_call)(
environ, start_response
)

Router.__call__ = sentry_patched_wsgi_call


def _capture_exception(exc_info, **kwargs):
# type: (ExcInfo, **Any) -> None
def _capture_exception(exc_info):
# type: (ExcInfo) -> None
if exc_info[0] is None or issubclass(exc_info[0], HTTPException):
return
hub = Hub.current
Expand Down
57 changes: 43 additions & 14 deletions tests/integrations/pyramid/test_pyramid.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import json

from io import BytesIO

import logging

import pkg_resources
import pytest

from pyramid.authorization import ACLAuthorizationPolicy
from io import BytesIO

import pyramid.testing

from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.response import Response

from werkzeug.test import Client

from sentry_sdk import capture_message, add_breadcrumb
from sentry_sdk.integrations.pyramid import PyramidIntegration

from werkzeug.test import Client


PYRAMID_VERSION = tuple(
map(int, pkg_resources.get_distribution("pyramid").version.split("."))
)


def hi(request):
capture_message("hi")
Expand Down Expand Up @@ -219,7 +223,7 @@ def errorhandler(exc, request):
assert not events


def test_errorhandler(
def test_errorhandler_ok(
sentry_init, pyramid_config, capture_exceptions, route, get_client
):
sentry_init(integrations=[PyramidIntegration()])
Expand All @@ -237,8 +241,36 @@ def errorhandler(exc, request):
client = get_client()
client.get("/")

assert not errors


@pytest.mark.skipif(
PYRAMID_VERSION < (1, 9),
reason="We don't have the right hooks in older Pyramid versions",
)
def test_errorhandler_500(
sentry_init, pyramid_config, capture_exceptions, route, get_client
):
sentry_init(integrations=[PyramidIntegration()])
errors = capture_exceptions()

@route("/")
def index(request):
1 / 0

def errorhandler(exc, request):
return Response("bad request", status=500)

pyramid_config.add_view(errorhandler, context=Exception)

client = get_client()
app_iter, status, headers = client.get("/")
assert b"".join(app_iter) == b"bad request"
assert status.lower() == "500 internal server error"

error, = errors
assert type(error) is Exception

assert isinstance(error, ZeroDivisionError)


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

event1, event2 = events

exception, = event1["exception"]["values"]
assert exception["type"] == "ValueError"
event, = events

exception = event2["exception"]["values"][-1]
exception = event["exception"]["values"][-1]
assert exception["type"] == "ZeroDivisionError"


Expand Down