8000 fix(wsgi): Log SystemExit (with non-zero exit code) and KeyboardInterrupt by saifelse · Pull Request #380 · getsentry/sentry-python · GitHub
[go: up one dir, main page]

Skip to content

fix(wsgi): Log SystemExit (with non-zero exit code) and KeyboardInterrupt #380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 1, 2019
27 changes: 17 additions & 10 deletions sentry_sdk/integrations/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def __call__(self, environ, start_response):

try:
rv = self.app(environ, start_response)
except Exception:
except BaseException:
reraise(*_capture_exception(hub))

return _ScopedResponse(hub, rv)
Expand Down Expand Up @@ -151,15 +151,22 @@ def get_client_ip(environ):

def _capture_exception(hub):
# type: (Hub) -> ExcInfo
exc_info = sys.exc_info()

# Check client here as it might have been unset while streaming response
if hub.client is not None:
exc_info = sys.exc_info()
event, hint = event_from_exception(
exc_info,
client_options=hub.client.options,
mechanism={"type": "wsgi", "handled": False},
)
hub.capture_event(event, hint=hint)
e = exc_info[1]

# SystemExit(0) is the only uncaught exception that is expected behavior
should_skip_capture = isinstance(e, SystemExit) and e.code in (0, None)
if not should_skip_capture:
event, hint = event_from_exception(
exc_info,
client_options=hub.client.options,
mechanism={"type": "wsgi", "handled": False},
)
hub.capture_event(event, hint=hint)

return exc_info


Expand All @@ -181,7 +188,7 @@ def __iter__(self):
chunk = next(iterator)
except StopIteration:
break
except Exception:
except BaseException:
reraise(*_capture_exception(self._hub))

yield chunk
Expand All @@ -192,7 +199,7 @@ def close(self):
self._response.close()
except AttributeError:
pass
except Exception:
except BaseException:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing an as e here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oof, thanks

reraise(*_capture_exception(self._hub))


Expand Down
77 changes: 77 additions & 0 deletions tests/integrations/wsgi/test_wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,28 @@ def app(environ, start_response):
return app


class IterableApp(object):
def __init__(self, iterable):
self.iterable = iterable

def __call__(self, environ, start_response):
return self.iterable


class ExitingIterable(object):
def __init__(self, exc_func):
self._exc_func = exc_func

def __iter__(self):
return self

def __next__(self):
raise self._exc_func()

def next(self):
return type(self).__next__(self)


def test_basic(sentry_init, crashing_app, capture_events):
sentry_init(send_default_pii=True)
app = SentryWsgiMiddleware(crashing_app)
Expand All @@ -30,3 +52,58 @@ def test_basic(sentry_init, crashing_app, capture_events):
"query_string": "",
"url": "http://localhost/",
}


@pytest.fixture(params=[0, None])
def test_systemexit_zero_is_ignored(sentry_init, capture_events, request):
zero_code = request.param
sentry_init(send_default_pii=True)
iterable = ExitingIterable(lambda: SystemExit(zero_code))
app = SentryWsgiMiddleware(IterableApp(iterable))
client = Client(app)
events = capture_events()

with pytest.raises(SystemExit):
client.get("/")

assert len(events) == 0


@pytest.fixture(params=["", "foo", 1, 2])
def test_systemexit_nonzero_is_captured(sentry_init, capture_events, request):
nonzero_code = request.param
sentry_init(send_default_pii=True)
iterable = ExitingIterable(lambda: SystemExit(nonzero_code))
app = SentryWsgiMiddleware(IterableApp(iterable))
client = Client(app)
events = capture_events()

with pytest.raises(SystemExit):
client.get("/")

event, = events

assert "exception" in event
exc = event["exception"]["values"][-1]
assert exc["type"] == "SystemExit"
assert exc["value"] == nonzero_code
assert event["level"] == "error"


def test_keyboard_interrupt_is_captured(sentry_init, capture_events):
sentry_init(send_default_pii=True)
iterable = ExitingIterable(lambda: KeyboardInterrupt())
app = SentryWsgiMiddleware(IterableApp(iterable))
client = Client(app)
events = capture_events()

with pytest.raises(KeyboardInterrupt):
client.get("/")

event, = events

assert "exception" in event
exc = event["exception"]["values"][-1]
assert exc["type"] == "KeyboardInterrupt"
assert exc["value"] == ""
assert event["level"] == "error"
0