Commit 24acca41 authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

Fixed #12012 -- Added support for logging. Thanks to Vinay Sajip for his draft...

Fixed #12012 -- Added support for logging. Thanks to Vinay Sajip for his draft patch, and to the many people who gave feedback during development of the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13981 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 667d832e
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ from django.utils import importlib

ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"


class LazySettings(LazyObject):
    """
    A lazy proxy for either global Django settings or a custom settings object.
@@ -114,6 +115,16 @@ class Settings(object):
            os.environ['TZ'] = self.TIME_ZONE
            time.tzset()

        # Settings are configured, so we can set up the logger if required
        if self.LOGGING_CONFIG:
            # First find the logging configuration function ...
            logging_config_path, logging_config_func_name = self.LOGGING_CONFIG.rsplit('.', 1)
            logging_config_module = importlib.import_module(logging_config_path)
            logging_config_func = getattr(logging_config_module, logging_config_func_name)

            # ... then invoke it with the logging settings
            logging_config_func(self.LOGGING)

class UserSettingsHolder(object):
    """
    Holder for user configured settings.
+28 −0
Original line number Diff line number Diff line
@@ -498,6 +498,34 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.user_messages.LegacyFallbackS
# Default values of MESSAGE_LEVEL and MESSAGE_TAGS are defined within
# django.contrib.messages to avoid imports in this settings file.

###########
# LOGGING #
###########

# The callable to use to configure logging
LOGGING_CONFIG = 'django.utils.log.dictConfig'

# The default logging configuration. This sends an email to
# the site admins on every HTTP 500 error. All other log
# records are sent to the bit bucket.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request':{
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

###########
# TESTING #
###########
+23 −0
Original line number Diff line number Diff line
@@ -94,3 +94,26 @@ INSTALLED_APPS = (
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
)

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request':{
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}
+22 −14
Original line number Diff line number Diff line
import logging
import sys

from django import http
@@ -5,6 +6,9 @@ from django.core import signals
from django.utils.encoding import force_unicode
from django.utils.importlib import import_module

logger = logging.getLogger('django.request')


class BaseHandler(object):
    # Changes that are always applied to a response (in this order).
    response_fixes = [
@@ -118,6 +122,11 @@ class BaseHandler(object):

                return response
            except http.Http404, e:
                logger.warning('Not Found: %s' % request.path,
                            extra={
                                'status_code': 404,
                                'request': request
                            })
                if settings.DEBUG:
                    from django.views import debug
                    return debug.technical_404_response(request, e)
@@ -131,6 +140,11 @@ class BaseHandler(object):
                        finally:
                            receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
            except exceptions.PermissionDenied:
                logger.warning('Forbidden (Permission denied): %s' % request.path,
                            extra={
                                'status_code': 403,
                                'request': request
                            })
                return http.HttpResponseForbidden('<h1>Permission denied</h1>')
            except SystemExit:
                # Allow sys.exit() to actually exit. See tickets #1023 and #4701
@@ -155,7 +169,6 @@ class BaseHandler(object):
        available would be an error.
        """
        from django.conf import settings
        from django.core.mail import mail_admins

        if settings.DEBUG_PROPAGATE_EXCEPTIONS:
            raise
@@ -164,14 +177,14 @@ class BaseHandler(object):
            from django.views import debug
            return debug.technical_500_response(request, *exc_info)

        # When DEBUG is False, send an error message to the admins.
        subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
        try:
            request_repr = repr(request)
        except:
            request_repr = "Request repr() unavailable"
        message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
        mail_admins(subject, message, fail_silently=True)
        logger.error('Internal Server Error: %s' % request.path,
            exc_info=exc_info,
            extra={
                'status_code': 500,
                'request':request
            }
        )

        # If Http500 handler is not installed, re-raise last exception
        if resolver.urlconf_module is None:
            raise exc_info[1], None, exc_info[2]
@@ -179,11 +192,6 @@ class BaseHandler(object):
        callback, param_dict = resolver.resolve500()
        return callback(request, **param_dict)

    def _get_traceback(self, exc_info=None):
        "Helper function to return the traceback as a string"
        import traceback
        return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))

    def apply_response_fixes(self, request, response):
        """
        Applies each of the functions in self.response_fixes to the request and
+12 −0
Original line number Diff line number Diff line
import logging
import os
from pprint import pformat
import sys
from warnings import warn

from django import http
@@ -9,6 +11,9 @@ from django.core.urlresolvers import set_script_prefix
from django.utils import datastructures
from django.utils.encoding import force_unicode, smart_str, iri_to_uri

logger = logging.getLogger('django.request')


# NOTE: do *not* import settings (or any module which eventually imports
# settings) until after ModPythonHandler has been called; otherwise os.environ
# won't be set up correctly (with respect to settings).
@@ -200,6 +205,13 @@ class ModPythonHandler(BaseHandler):
            try:
                request = self.request_class(req)
            except UnicodeDecodeError:
                logger.warning('Bad Request (UnicodeDecodeError): %s' % request.path,
                    exc_info=sys.exc_info(),
                    extra={
                        'status_code': 400,
                        'request': request
                    }
                )
                response = http.HttpResponseBadRequest()
            else:
                response = self.get_response(request)
Loading