%PDF- %PDF-
Direktori : /opt/alt/python37/lib/python3.7/site-packages/raven/contrib/django/ |
Current File : //opt/alt/python37/lib/python3.7/site-packages/raven/contrib/django/client.py |
# -*- coding: utf-8 -*- """ raven.contrib.django.client ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :copyright: (c) 2010-2012 by the Sentry Team, see AUTHORS for more details. :license: BSD, see LICENSE for more details. """ from __future__ import absolute_import import time import logging from django import VERSION as DJANGO_VERSION from django.conf import settings from django.core.exceptions import SuspiciousOperation from django.http import HttpRequest from django.template import TemplateSyntaxError from django.utils.datastructures import MultiValueDict try: # support Django 1.9 from django.template.base import Origin except ImportError: # backward compatibility from django.template.loader import LoaderOrigin as Origin from raven.base import Client from raven.contrib.django.utils import get_data_from_template, get_host from raven.contrib.django.middleware import SentryMiddleware from raven.utils.compat import string_types, binary_type, iterlists from raven.contrib.django.resolver import RouteResolver from raven.utils.wsgi import get_headers, get_environ, get_client_ip from raven.utils import once from raven import breadcrumbs __all__ = ('DjangoClient',) if DJANGO_VERSION < (1, 10): def is_authenticated(request_user): return request_user.is_authenticated() else: def is_authenticated(request_user): return request_user.is_authenticated class _FormatConverter(object): def __init__(self, param_mapping): self.param_mapping = param_mapping self.params = [] def __getitem__(self, val): self.params.append(self.param_mapping.get(val)) return '%s' def format_sql(sql, params): rv = [] if isinstance(params, dict): conv = _FormatConverter(params) if params: sql = sql % conv params = conv.params else: params = () for param in params or (): if param is None: rv.append('NULL') elif isinstance(param, string_types): if isinstance(param, binary_type): param = param.decode('utf-8', 'replace') if len(param) > 256: param = param[:256] + u'…' rv.append("'%s'" % param.replace("'", "''")) else: rv.append(repr(param)) return sql, rv @once def install_sql_hook(): """If installed this causes Django's queries to be captured.""" try: from django.db.backends.utils import CursorWrapper except ImportError: from django.db.backends.util import CursorWrapper try: real_execute = CursorWrapper.execute real_executemany = CursorWrapper.executemany except AttributeError: # XXX(mitsuhiko): On some very old django versions (<1.6) this # trickery would have to look different but I can't be bothered. return def record_sql(vendor, alias, start, duration, sql, params): def processor(data): real_sql, real_params = format_sql(sql, params) if real_params: real_sql = real_sql % tuple(real_params) # maybe category to 'django.%s.%s' % (vendor, alias or # 'default') ? data.update({ 'message': real_sql, 'category': 'query', }) breadcrumbs.record(processor=processor) def record_many_sql(vendor, alias, start, sql, param_list): duration = time.time() - start for params in param_list: record_sql(vendor, alias, start, duration, sql, params) def execute(self, sql, params=None): start = time.time() try: return real_execute(self, sql, params) finally: record_sql(self.db.vendor, getattr(self.db, 'alias', None), start, time.time() - start, sql, params) def executemany(self, sql, param_list): start = time.time() try: return real_executemany(self, sql, param_list) finally: record_many_sql(self.db.vendor, getattr(self.db, 'alias', None), start, sql, param_list) CursorWrapper.execute = execute CursorWrapper.executemany = executemany breadcrumbs.ignore_logger('django.db.backends') class DjangoClient(Client): logger = logging.getLogger('sentry.errors.client.django') resolver = RouteResolver() def __init__(self, *args, **kwargs): install_sql_hook = kwargs.pop('install_sql_hook', True) Client.__init__(self, *args, **kwargs) if install_sql_hook: self.install_sql_hook() def install_sql_hook(self): install_sql_hook() def get_user_info(self, request): user_info = { 'ip_address': get_client_ip(request.META), } user = getattr(request, 'user', None) if user is None: return user_info try: authenticated = is_authenticated(user) if not authenticated: return user_info user_info['id'] = user.pk 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 except Exception: # We expect that user objects can be somewhat broken at times # and try to just handle as much as possible and ignore errors # as good as possible here. pass return user_info def get_data_from_request(self, request): result = {} result['user'] = self.get_user_info(request) 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' host = get_host(request) uri = '%s://%s%s' % (scheme, host, request.path) if request.method not in ('GET', 'HEAD'): try: data = request.body except Exception: try: data = request.raw_post_data except Exception: # assume we had a partial read. try: data = request.POST or '<unavailable>' except Exception: data = '<unavailable>' else: if isinstance(data, MultiValueDict): data = dict( (k, v[0] if len(v) == 1 else v) for k, v in iterlists(data)) else: data = None environ = request.META result.update({ 'request': { 'method': request.method, 'url': uri, 'query_string': request.META.get('QUERY_STRING'), 'data': data, 'cookies': dict(request.COOKIES), 'headers': dict(get_headers(environ)), 'env': dict(get_environ(environ)), } }) return result def build_msg(self, *args, **kwargs): data = super(DjangoClient, self).build_msg(*args, **kwargs) for frame in self._iter_frames(data): module = frame.get('module') if not module: continue if module.startswith('django.'): frame['in_app'] = False if not self.site and 'django.contrib.sites' in settings.INSTALLED_APPS: try: 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) except Exception: # Database error? Fallback to the id try: data['tags'].setdefault('site', settings.SITE_ID) except AttributeError: # SITE_ID wasn't set, so just ignore pass return data 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(SentryMiddleware.thread, 'request', None) 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. As of Django 1.9 or so the new # template debug thing showed up. if hasattr(exc_value, 'django_template_source') or \ ((isinstance(exc_value, TemplateSyntaxError) and isinstance(getattr(exc_value, 'source', None), (tuple, list)) and isinstance(exc_value.source[0], Origin))) or \ hasattr(exc_value, 'template_debug'): source = getattr(exc_value, 'django_template_source', getattr(exc_value, 'source', None)) debug = getattr(exc_value, 'template_debug', None) if source is None: self.logger.info('Unable to get template source from exception') data.update(get_data_from_template(source, debug)) result = super(DjangoClient, self).capture(event_type, **kwargs) if is_http_request and result: # attach the sentry object to the request request.sentry = { 'project_id': data.get('project', self.remote.project), 'id': result, } return result def get_transaction_from_request(self, request): return self.resolver.resolve(request.path)