Support transport option in Flask/Django (fixes GH-623)

This commit is contained in:
David Cramer 2015-07-11 00:10:45 -06:00
parent d3623e897d
commit 468bc4e6c0
4 changed files with 53 additions and 21 deletions

View File

@ -16,10 +16,11 @@ import logging
import sys
import warnings
from django.conf import settings as django_settings
from django.conf import settings
from hashlib import md5
from raven.utils import six
from raven.utils.imports import import_string
from raven.contrib.django.management import patch_cli_runner
@ -30,7 +31,7 @@ def get_installed_apps():
"""
Modules in settings.INSTALLED_APPS as a set.
"""
return set(django_settings.INSTALLED_APPS)
return set(settings.INSTALLED_APPS)
_client = (None, None)
@ -107,23 +108,21 @@ client = ProxyClient()
def get_option(x, d=None):
options = getattr(django_settings, 'RAVEN_CONFIG', {})
options = getattr(settings, 'RAVEN_CONFIG', {})
return getattr(django_settings, 'SENTRY_%s' % x, options.get(x, d))
return getattr(settings, 'SENTRY_%s' % x, options.get(x, d))
def get_client(client=None):
def get_client(client=None, reset=False):
global _client
tmp_client = client is not None
if not tmp_client:
client = getattr(django_settings, 'SENTRY_CLIENT', 'raven.contrib.django.DjangoClient')
client = getattr(settings, 'SENTRY_CLIENT', 'raven.contrib.django.DjangoClient')
if _client[0] != client:
module, class_name = client.rsplit('.', 1)
ga = lambda x, d=None: getattr(django_settings, 'SENTRY_%s' % x, d)
options = copy.deepcopy(getattr(django_settings, 'RAVEN_CONFIG', {}))
if _client[0] != client or reset:
ga = lambda x, d=None: getattr(settings, 'SENTRY_%s' % x, d)
options = copy.deepcopy(getattr(settings, 'RAVEN_CONFIG', {}))
options.setdefault('servers', ga('SERVERS'))
options.setdefault('include_paths', ga('INCLUDE_PATHS', []))
options['include_paths'] = set(options['include_paths']) | get_installed_apps()
@ -131,7 +130,6 @@ def get_client(client=None):
options.setdefault('timeout', ga('TIMEOUT'))
options.setdefault('name', ga('NAME'))
options.setdefault('auto_log_stacks', ga('AUTO_LOG_STACKS'))
options.setdefault('key', ga('KEY', md5(django_settings.SECRET_KEY.encode('utf8')).hexdigest()))
options.setdefault('string_max_length', ga('MAX_LENGTH_STRING'))
options.setdefault('list_max_length', ga('MAX_LENGTH_LIST'))
options.setdefault('site', ga('SITE'))
@ -143,10 +141,13 @@ def get_client(client=None):
options.setdefault('context', ga('CONTEXT'))
options.setdefault('release', ga('RELEASE'))
class_name = str(class_name)
transport = ga('TRANSPORT') or options.get('transport')
if isinstance(transport, basestring):
transport = import_string(transport)
options['transport'] = transport
try:
Client = getattr(__import__(module, {}, {}, class_name), class_name)
Client = import_string(client)
except ImportError:
logger.exception('Failed to import client: %s', client)
if not _client[1]:
@ -186,7 +187,7 @@ def register_handlers():
from django.core.signals import got_request_exception
# HACK: support Sentry's internal communication
if 'sentry' in django_settings.INSTALLED_APPS:
if 'sentry' in settings.INSTALLED_APPS:
from django.db import transaction
# Django 1.6
if hasattr(transaction, 'atomic'):
@ -208,7 +209,7 @@ def register_handlers():
got_request_exception.connect(exception_handler, weak=False)
# If Celery is installed, register a signal handler
if 'djcelery' in django_settings.INSTALLED_APPS:
if 'djcelery' in settings.INSTALLED_APPS:
try:
# Celery < 2.5? is not supported
from raven.contrib.celery import (
@ -222,8 +223,8 @@ def register_handlers():
logger.exception('Failed to install Celery error handler')
try:
ga = lambda x, d=None: getattr(django_settings, 'SENTRY_%s' % x, d)
options = getattr(django_settings, 'RAVEN_CONFIG', {})
ga = lambda x, d=None: getattr(settings, 'SENTRY_%s' % x, d)
options = getattr(settings, 'RAVEN_CONFIG', {})
loglevel = options.get('celery_loglevel',
ga('CELERY_LOGLEVEL', logging.ERROR))
@ -237,8 +238,8 @@ def register_serializers():
import raven.contrib.django.serializers # NOQA
if ('raven.contrib.django' in django_settings.INSTALLED_APPS
or 'raven.contrib.django.raven_compat' in django_settings.INSTALLED_APPS):
if ('raven.contrib.django' in settings.INSTALLED_APPS
or 'raven.contrib.django.raven_compat' in settings.INSTALLED_APPS):
register_handlers()
register_serializers()

View File

@ -21,18 +21,27 @@ import logging
from flask import request, current_app, g
from flask.signals import got_request_exception, request_finished
from werkzeug.exceptions import ClientDisconnected
from raven.conf import setup_logging
from raven.base import Client
from raven.middleware import Sentry as SentryMiddleware
from raven.handlers.logging import SentryHandler
from raven.utils.compat import _urlparse
from raven.utils.imports import import_string
from raven.utils.wsgi import get_headers, get_environ
from werkzeug.exceptions import ClientDisconnected
def make_client(client_cls, app, dsn=None):
# TODO(dcramer): django and Flask share very similar concepts here, and
# should be refactored
transport = app.config.get('SENTRY_TRANSPORT')
if isinstance(transport, basestring):
transport = import_string(transport)
return client_cls(
dsn=dsn or app.config.get('SENTRY_DSN') or os.environ.get('SENTRY_DSN'),
transport=transport,
include_paths=set(app.config.get('SENTRY_INCLUDE_PATHS', [])) | set([app.import_name]),
exclude_paths=app.config.get('SENTRY_EXCLUDE_PATHS'),
servers=app.config.get('SENTRY_SERVERS'),

12
raven/utils/imports.py Normal file
View File

@ -0,0 +1,12 @@
from __future__ import absolute_import
def import_string(key):
key = str(key)
if '.' not in key:
return __import__(key)
module_name, class_name = key.rsplit('.', 1)
module = __import__(module_name, {}, {}, [class_name], -1)
return getattr(module, class_name)

View File

@ -32,6 +32,7 @@ from raven.contrib.django.models import client, get_client, sentry_exception_han
from raven.contrib.django.middleware.wsgi import Sentry
from raven.contrib.django.templatetags.raven import sentry_public_dsn
from raven.contrib.django.views import is_valid_origin
from raven.transport import HTTPTransport
from raven.utils.serializer import transform
from raven.utils import six
from raven.utils.six import StringIO
@ -402,6 +403,15 @@ class DjangoClientTest(TestCase):
with Settings(**extra_settings):
assert isinstance(get_client(), DjangoClient)
def test_transport_specification(self):
extra_settings = {
'SENTRY_TRANSPORT': 'raven.transport.HTTPTransport',
'SENTRY_DSN': 'http://public:secret@example.com/1',
}
with Settings(**extra_settings):
client = get_client(reset=True)
assert type(client.remote.get_transport()) is HTTPTransport
def test_response_error_id_middleware(self):
# TODO: test with 500s
with Settings(MIDDLEWARE_CLASSES=[