2011-10-07 19:12:06 +02:00
|
|
|
"""
|
2011-10-07 19:57:45 +02:00
|
|
|
raven.middleware
|
2011-10-07 19:12:06 +02:00
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2012-10-12 19:45:54 +02:00
|
|
|
:copyright: (c) 2010-2012 by the Sentry Team, see AUTHORS for more details.
|
2011-10-07 19:12:06 +02:00
|
|
|
:license: BSD, see LICENSE for more details.
|
|
|
|
"""
|
2013-06-15 22:57:40 +02:00
|
|
|
from __future__ import absolute_import
|
2011-10-07 19:12:06 +02:00
|
|
|
|
2013-06-15 22:57:40 +02:00
|
|
|
from raven.utils.wsgi import (
|
|
|
|
get_current_url, get_headers, get_environ)
|
2011-10-07 19:12:06 +02:00
|
|
|
|
2012-01-28 20:50:45 +01:00
|
|
|
|
2011-10-07 19:12:06 +02:00
|
|
|
class Sentry(object):
|
|
|
|
"""
|
2012-01-28 20:50:45 +01:00
|
|
|
A WSGI middleware which will attempt to capture any
|
|
|
|
uncaught exceptions and send them to Sentry.
|
|
|
|
|
2011-10-07 19:57:45 +02:00
|
|
|
>>> from raven.base import Client
|
2011-10-07 19:12:06 +02:00
|
|
|
>>> application = Sentry(application, Client())
|
|
|
|
"""
|
2013-04-03 07:11:18 +02:00
|
|
|
def __init__(self, application, client=None):
|
2011-10-07 19:12:06 +02:00
|
|
|
self.application = application
|
2013-04-03 07:11:18 +02:00
|
|
|
if client is None:
|
|
|
|
from raven.base import Client
|
|
|
|
client = Client()
|
2011-10-07 19:12:06 +02:00
|
|
|
self.client = client
|
|
|
|
|
|
|
|
def __call__(self, environ, start_response):
|
2013-12-05 21:00:46 +01:00
|
|
|
# TODO(dcramer): ideally this is lazy, but the context helpers must
|
|
|
|
# support callbacks first
|
|
|
|
self.client.http_context(self.get_http_context(environ))
|
|
|
|
|
2011-10-07 19:12:06 +02:00
|
|
|
try:
|
2012-10-12 19:45:07 +02:00
|
|
|
iterable = self.application(environ, start_response)
|
|
|
|
except Exception:
|
|
|
|
self.handle_exception(environ)
|
|
|
|
raise
|
2015-11-13 08:32:20 +01:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
self.handle_exception(environ)
|
|
|
|
raise
|
2015-11-13 02:20:16 +01:00
|
|
|
except SystemExit as e:
|
|
|
|
if e.code != 0:
|
|
|
|
self.handle_exception(environ)
|
|
|
|
raise
|
2012-10-12 19:45:07 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
for event in iterable:
|
2011-10-07 21:24:23 +02:00
|
|
|
yield event
|
2011-10-07 19:12:06 +02:00
|
|
|
except Exception:
|
2012-10-12 19:45:07 +02:00
|
|
|
self.handle_exception(environ)
|
2011-10-07 19:12:06 +02:00
|
|
|
raise
|
2015-11-13 08:32:20 +01:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
self.handle_exception(environ)
|
|
|
|
raise
|
2015-11-13 02:20:16 +01:00
|
|
|
except SystemExit as e:
|
|
|
|
if e.code != 0:
|
|
|
|
self.handle_exception(environ)
|
|
|
|
raise
|
2012-10-12 19:45:07 +02:00
|
|
|
finally:
|
|
|
|
# wsgi spec requires iterable to call close if it exists
|
|
|
|
# see http://blog.dscpl.com.au/2012/10/obligations-for-calling-close-on.html
|
|
|
|
if iterable and hasattr(iterable, 'close') and callable(iterable.close):
|
|
|
|
try:
|
|
|
|
iterable.close()
|
|
|
|
except Exception:
|
|
|
|
self.handle_exception(environ)
|
2015-11-13 08:32:20 +01:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
self.handle_exception(environ)
|
|
|
|
raise
|
2015-11-13 02:20:16 +01:00
|
|
|
except SystemExit as e:
|
|
|
|
if e.code != 0:
|
|
|
|
self.handle_exception(environ)
|
|
|
|
raise
|
2014-01-04 23:45:46 +01:00
|
|
|
self.client.context.clear()
|
2011-10-07 19:12:06 +02:00
|
|
|
|
2013-12-05 21:00:46 +01:00
|
|
|
def get_http_context(self, environ):
|
|
|
|
return {
|
|
|
|
'method': environ.get('REQUEST_METHOD'),
|
|
|
|
'url': get_current_url(environ, strip_querystring=True),
|
|
|
|
'query_string': environ.get('QUERY_STRING'),
|
|
|
|
# TODO
|
|
|
|
# 'data': environ.get('wsgi.input'),
|
|
|
|
'headers': dict(get_headers(environ)),
|
|
|
|
'env': dict(get_environ(environ)),
|
|
|
|
}
|
|
|
|
|
2013-12-03 04:53:20 +01:00
|
|
|
def process_response(self, request, response):
|
|
|
|
self.client.context.clear()
|
|
|
|
|
2013-12-05 21:00:46 +01:00
|
|
|
def handle_exception(self, environ=None):
|
|
|
|
return self.client.captureException()
|