Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

agriconnect / opbeat   python

Repository URL to install this package:

Version: 3.5.3 

/ contrib / django / client.py

"""
opbeat.contrib.django.client
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:copyright: (c) 2011-2012 Opbeat

Large portions are
:copyright: (c) 2010 by the Sentry Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""

from __future__ import absolute_import

import logging

import django
from django.core.exceptions import SuspiciousOperation
from django.db import DatabaseError
from django.http import HttpRequest
from django.template import TemplateSyntaxError

from opbeat.base import Client
from opbeat.conf import defaults
from opbeat.contrib.django.utils import (get_data_from_template_debug,
                                         get_data_from_template_source,
                                         iterate_with_template_sources)
from opbeat.utils.wsgi import get_environ, get_headers

try:
    from django.template.loader import LoaderOrigin  # Django < 1.9
except ImportError:
    from django.template.base import Origin as LoaderOrigin  # Django >= 1.9


try:
    # Attempt to use the Django 1.7+ apps sub-framework.
    from django.apps import apps

    is_app_installed = apps.is_installed
except ImportError:
    from django.conf import settings

    # Use the legacy method of simple checking the configuration.
    def is_app_installed(app_name):
        return app_name in settings.INSTALLED_APPS


__all__ = ('DjangoClient',)


class DjangoClient(Client):
    logger = logging.getLogger('opbeat.errors.client.django')

    def __init__(self, **kwargs):
        instrument_django_middleware = kwargs.pop(
            'instrument_django_middleware',
            None
        )
        if instrument_django_middleware is not None:
            self.instrument_django_middleware = instrument_django_middleware
        else:
            self.instrument_django_middleware = defaults.INSTRUMENT_DJANGO_MIDDLEWARE
        kwargs['framework_version'] = 'django/' + django.get_version()
        super(DjangoClient, self).__init__(**kwargs)

    def get_user_info(self, request):
        try:
            if request.user.is_authenticated():
                user_info = {
                    'is_authenticated': True,
                    'id': request.user.pk,
                }
                if hasattr(request.user, 'get_username'):
                    user_info['username'] = request.user.get_username()
                elif hasattr(request.user, 'username'):
                    user_info['username'] = request.user.username
                else:
                    # this only happens if the project uses custom user models, but
                    # doesn't correctly inherit from AbstractBaseUser
                    user_info['username'] = ''

                if hasattr(request.user, 'email'):
                    user_info['email'] = request.user.email
            else:
                user_info = {
                    'is_authenticated': False,
                }
        except DatabaseError:
            # If the connection is closed or similar, we'll just skip this
            return {}

        return user_info

    def get_data_from_request(self, request):
        django_auth_installed = is_app_installed('django.contrib.auth')

        if django_auth_installed:
            from django.contrib.auth.models import AnonymousUser
            try:
                # try to import User via get_user_model (Django 1.5+)
                from django.contrib.auth import get_user_model
                User = get_user_model()
            except ImportError:
                # import the User model from the standard location (Django <1.5)
                from django.contrib.auth.models import User

        if request.method != 'GET':
            try:
                if hasattr(request, 'body'):
                    # Django 1.4+
                    raw_data = request.body
                else:
                    raw_data = request.raw_post_data
                data = raw_data if raw_data else request.POST
            except Exception:
                # assume we had a partial read:
                data = '<unavailable>'
        else:
            data = None

        environ = request.META

        if hasattr(request, 'get_raw_uri'):
            # added in Django 1.9
            url = request.get_raw_uri()
        else:
            try:
                # Requires host to be in ALLOWED_HOSTS, might throw a
                # DisallowedHost exception
                url = request.build_absolute_uri()
            except SuspiciousOperation:
                # catching SuspiciousOperation, as the more specific
                # DisallowedHost has only been introduced in Django 1.6.
                # We can't figure out the real URL, so we have to set it to
                # None
                url = None

        result = {
            'http': {
                'method': request.method,
                'url': url,
                'query_string': request.META.get('QUERY_STRING'),
                'data': data,
                'cookies': dict(request.COOKIES),
                'headers': dict(get_headers(environ)),
                'env': dict(get_environ(environ)),
            }
        }

        if django_auth_installed and \
           hasattr(request, 'user') and \
           isinstance(request.user, (User, AnonymousUser)):
            result['user'] = self.get_user_info(request)

        return result

    def capture(self, event_type, request=None, **kwargs):
        if 'data' not in kwargs:
            kwargs['data'] = data = {}
        else:
            data = kwargs['data']

        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.
            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], 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(source))
            elif hasattr(exc_value, 'template_debug'):  # Django 1.9+
                data.update(get_data_from_template_debug(exc_value.template_debug))

        result = super(DjangoClient, self).capture(event_type, **kwargs)

        if is_http_request:
            # attach the opbeat object to the request
            request.opbeat = {
                'app_id': data.get('app_id', self.app_id),
                'id': self.get_ident(result),
            }

        return result

    def get_stack_info_for_trace(self, frames, extended=True):
        """If the stacktrace originates within the Opbeat module, it will skip
        frames until some other module comes up."""
        frames = list(iterate_with_template_sources(frames, extended))
        i = 0
        while len(frames) > i:
            if 'module' in frames[i] and not (
                    frames[i]['module'].startswith('opbeat.') or
                    frames[i]['module'] == 'contextlib'
            ):
                return frames[i:]
            i += 1
        return frames

    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()``.
        """
        if self.servers:
            return super(DjangoClient, self).send(**kwargs)
        else:
            self.error_logger.error('No servers configured, and opbeat not installed. Cannot send message')
            return None