Created
September 25, 2018 13:09
-
-
Save wichert/1fb5ee81d1ff0ba9e96624a55d41350f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
import os | |
from pyramid.httpexceptions import WSGIHTTPException | |
from pyramid.tweens import EXCVIEW | |
from raven import Client | |
from raven import fetch_package_version | |
from raven.utils.wsgi import get_environ | |
try: | |
from raven.contrib.celery import register_signal, register_logger_signal | |
import celery # NOQA | |
HAVE_CELERY = True | |
except ImportError: | |
HAVE_CELERY = False | |
log = logging.getLogger(__name__) | |
class NewSentryContext: | |
"""Event used to setup a Sentry context for the current request. | |
This is typically used to add data to the context, for example: | |
.. code-block:: python | |
@subscriber(PrepareSentryContext) | |
def add_client_os(event): | |
event.context.merge({ | |
'os': get_client_os(event.request), | |
}) | |
Keep in mind that this event is fired very early during request processing, | |
before Pyramid has done context lookup, authentication or authorisation. | |
""" | |
def __init__(self, request, context): | |
self.request = request | |
self.context = context | |
class MockClient(object): | |
def captureException(self, *a, **kw): | |
pass | |
def captureMessage(self, *a, **kw): | |
pass | |
def create_client(config): | |
registry = config.registry | |
settings = config.get_settings() | |
params = { | |
'release': fetch_package_version(registry.package_name), | |
'environment': os.environ.get('SENTRY_ENVIRONMENT', 'development'), | |
} | |
params.update({k[7:]: v | |
for (k, v) in settings.items() | |
if k.startswith('sentry.')}) | |
params['tags'] = { | |
'application': registry.package_name, | |
} | |
if os.environ.get('SENTRY_DSN'): | |
params.pop('dsn', None) # Environment wins from config file | |
elif not params.get('dsn'): | |
return None | |
return Client(**params) | |
def sentry_tween_factory(handler, registry): | |
def sentry_tween(request): | |
client = request.raven | |
client.context.activate() | |
data = None | |
try: | |
if request.content_type == 'application/data': | |
data = request.json_body | |
elif request.content_type == 'application/x-www-form-urlencoded': | |
data = dict(request.POST) | |
else: | |
data = request.body | |
except ValueError: | |
pass | |
client.http_context({ | |
'method': request.method, | |
'url': request.path_url, | |
'query_string': request.query_string, | |
'headers': dict(request.headers), | |
'env': dict(get_environ(request.environ)), | |
'data': data, | |
}) | |
request.registry.notify(NewSentryContext(request, client.context)) | |
try: | |
response = handler(request) | |
except (WSGIHTTPException, StopIteration, GeneratorExit): | |
raise | |
except SystemExit as e: | |
if e.code != 0: | |
client.captureException() | |
raise | |
except Exception: | |
client.captureException() | |
raise | |
finally: | |
client.context.clear() | |
client.transaction.clear() | |
return response | |
return sentry_tween | |
def includeme(config): | |
client = create_client(config) | |
if client is None: | |
log.warn('No sentry DSN found in environment or config.') | |
client = MockClient() | |
else: | |
config.add_tween('curvetips.logging.sentry.sentry_tween_factory', under=EXCVIEW) | |
if HAVE_CELERY: | |
register_logger_signal(client) | |
register_signal(client, ignore_expected=True) | |
config.registry['raven'] = client | |
config.add_request_method(lambda r: client, 'raven', reify=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment