debian-python-raven/raven/contrib/django/client.py

194 lines
6.7 KiB
Python
Raw Normal View History

2012-02-05 04:27:13 +01:00
"""
raven.contrib.django.client
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2012-10-12 19:45:54 +02:00
:copyright: (c) 2010-2012 by the Sentry Team, see AUTHORS for more details.
2012-02-05 04:27:13 +01:00
:license: BSD, see LICENSE for more details.
"""
from __future__ import absolute_import
import logging
from django.conf import settings
from django.core.exceptions import SuspiciousOperation
2012-02-05 04:27:13 +01:00
from django.http import HttpRequest
from django.template import TemplateSyntaxError
from django.template.loader import LoaderOrigin
from raven.base import Client
2013-05-06 22:40:42 +02:00
from raven.contrib.django.utils import get_data_from_template, get_host
from raven.contrib.django.middleware import SentryLogMiddleware
2012-02-05 04:27:13 +01:00
from raven.utils.wsgi import get_headers, get_environ
__all__ = ('DjangoClient',)
class DjangoClient(Client):
logger = logging.getLogger('sentry.errors.client.django')
def is_enabled(self):
2012-10-31 05:06:15 +01:00
return bool(self.servers or 'sentry' in settings.INSTALLED_APPS)
def get_user_info(self, user):
if not user.is_authenticated():
return {'is_authenticated': False}
user_info = {
'id': user.pk,
'is_authenticated': True,
}
if hasattr(user, 'email'):
user_info['email'] = user.email
if hasattr(user, 'get_username'):
user_info['username'] = user.get_username()
elif hasattr(user, 'username'):
user_info['username'] = user.username
2012-02-05 04:27:13 +01:00
return user_info
def get_data_from_request(self, request):
try:
from django.contrib.auth.models import AbstractBaseUser as BaseUser
except ImportError:
from django.contrib.auth.models import User as BaseUser # NOQA
2012-02-05 04:27:13 +01:00
result = {}
if hasattr(request, 'user') and isinstance(request.user, BaseUser):
result['user'] = self.get_user_info(request.user)
try:
uri = request.build_absolute_uri()
except SuspiciousOperation:
# attempt to build a URL for reporting as Django won't allow us to
# use get_host()
if request.is_secure():
scheme = 'https'
else:
scheme = 'http'
2013-05-06 22:40:42 +02:00
host = get_host(request)
uri = '%s://%s%s' % (scheme, host, request.path)
if request.method != 'GET':
try:
2013-02-08 10:05:54 +01:00
data = request.body
2014-04-13 23:55:35 +02:00
except Exception:
2013-02-08 10:05:54 +01:00
try:
data = request.raw_post_data
2013-02-08 10:05:54 +01:00
except Exception:
2013-09-10 14:43:52 +02:00
# assume we had a partial read.
try:
data = request.POST or '<unavailable>'
2013-09-10 14:43:52 +02:00
except Exception:
data = '<unavailable>'
2012-02-05 04:27:13 +01:00
else:
data = None
2012-02-05 04:27:13 +01:00
environ = request.META
result.update({
'request': {
2012-02-05 04:27:13 +01:00
'method': request.method,
'url': uri,
2012-02-05 04:27:13 +01:00
'query_string': request.META.get('QUERY_STRING'),
'data': data,
'cookies': dict(request.COOKIES),
'headers': dict(get_headers(environ)),
'env': dict(get_environ(environ)),
}
})
2012-02-05 04:27:13 +01:00
return result
def build_msg(self, *args, **kwargs):
data = super(DjangoClient, self).build_msg(*args, **kwargs)
stacks = [
data.get('stacktrace'),
]
if 'exception' in data:
stacks.append(data['exception']['values'][0]['stacktrace'])
for stacktrace in filter(bool, stacks):
for frame in stacktrace['frames']:
module = frame.get('module')
if not module:
continue
if module.startswith('django.'):
frame['in_app'] = False
2013-02-08 01:15:36 +01:00
if not self.site and 'django.contrib.sites' in settings.INSTALLED_APPS:
try:
2013-06-15 23:02:30 +02:00
from django.contrib.sites.models import Site
site = Site.objects.get_current()
site_name = site.name or site.domain
data['tags'].setdefault('site', site_name)
2013-02-08 01:15:36 +01:00
except Exception:
# Database error? Fallback to the id
data['tags'].setdefault('site', settings.SITE_ID)
return data
2012-02-05 04:27:13 +01:00
def capture(self, event_type, request=None, **kwargs):
if 'data' not in kwargs:
kwargs['data'] = data = {}
else:
data = kwargs['data']
if request is None:
request = getattr(SentryLogMiddleware.thread, 'request', None)
2012-02-05 04:27:13 +01:00
is_http_request = isinstance(request, HttpRequest)
if is_http_request:
data.update(self.get_data_from_request(request))
if kwargs.get('exc_info'):
exc_value = kwargs['exc_info'][1]
# As of r16833 (Django) all exceptions may contain a ``django_template_source`` attribute (rather than the
# legacy ``TemplateSyntaxError.source`` check) which describes template information.
2012-06-03 21:41:25 +02:00
if hasattr(exc_value, 'django_template_source') or ((isinstance(exc_value, TemplateSyntaxError) and
2012-02-05 04:27:13 +01:00
isinstance(getattr(exc_value, 'source', None), (tuple, list)) and isinstance(exc_value.source[0], LoaderOrigin))):
source = getattr(exc_value, 'django_template_source', getattr(exc_value, 'source', None))
if source is None:
self.logger.info('Unable to get template source from exception')
data.update(get_data_from_template(source))
result = super(DjangoClient, self).capture(event_type, **kwargs)
if is_http_request and result:
2012-02-05 04:27:13 +01:00
# attach the sentry object to the request
request.sentry = {
'project_id': data.get('project', self.project),
'id': self.get_ident(result),
}
return result
def send(self, **kwargs):
"""
Serializes and signs ``data`` and passes the payload off to ``send_remote``
If ``servers`` was passed into the constructor, this will serialize the data and pipe it to
each server using ``send_remote()``. Otherwise, this will communicate with ``sentry.models.GroupedMessage``
directly.
"""
if self.servers:
return super(DjangoClient, self).send(**kwargs)
elif 'sentry' in settings.INSTALLED_APPS:
try:
return self.send_integrated(kwargs)
2013-03-17 09:11:26 +01:00
except Exception as e:
if self.raise_send_errors:
raise
2013-04-23 06:27:59 +02:00
self.error_logger.error(
'Unable to record event: %s\nEvent was: %r', e,
kwargs['message'], exc_info=True)
2012-02-05 04:27:13 +01:00
def send_integrated(self, kwargs):
from sentry.models import Group
return Group.objects.from_kwargs(**kwargs)