Commit f0f327bb authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #18993 -- 'django' logger logs to console when DEBUG=True

Thanks Preston Holmes for the review.
parent a014ddfe
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -24,18 +24,25 @@ except ImportError:

getLogger = logging.getLogger

# Default logging for Django. This sends an email to
# the site admins on every HTTP 500 error. All other log
# records are sent to the bit bucket.
# Default logging for Django. This sends an email to the site admins on every
# HTTP 500 error. Depending on DEBUG, all other log records are either sent to
# the console (DEBUG=True) or discarded by mean of the NullHandler (DEBUG=False).
DEFAULT_LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        }
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console':{
            'level': 'INFO',
            'class': 'logging.StreamHandler',
        },
        'null': {
            'class': 'django.utils.log.NullHandler',
        },
@@ -47,12 +54,13 @@ DEFAULT_LOGGING = {
    },
    'loggers': {
        'django': {
            'handlers': ['null'],
            'handlers': ['console'],
            'filters': ['require_debug_true'],
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
            'propagate': False,
        },
    }
}
@@ -130,3 +138,8 @@ class CallbackFilter(logging.Filter):
class RequireDebugFalse(logging.Filter):
    def filter(self, record):
        return not settings.DEBUG


class RequireDebugTrue(logging.Filter):
    def filter(self, record):
       return settings.DEBUG
+4 −0
Original line number Diff line number Diff line
@@ -172,6 +172,10 @@ Django 1.5 also includes several smaller improvements worth noting:
* An instance of :class:`~django.core.urlresolvers.ResolverMatch` is stored on
  the request as ``resolver_match``.

* By default, all logging messages reaching the `django` logger when
  :setting:`DEBUG` is `True` are sent to the console (unless you redefine the
  logger in your :setting:`LOGGING` setting).

Backwards incompatible changes in 1.5
=====================================

+18 −2
Original line number Diff line number Diff line
@@ -546,6 +546,13 @@ logging module.
            }
        },

.. class:: RequireDebugTrue()

   .. versionadded:: 1.5

   This filter is similar to :class:`RequireDebugFalse`, except that records are
   passed only when :setting:`DEBUG` is `True`.

.. _default-logging-configuration:

Django's default logging configuration
@@ -555,5 +562,14 @@ By default, Django configures the ``django.request`` logger so that all messages
with ``ERROR`` or ``CRITICAL`` level are sent to :class:`AdminEmailHandler`, as
long as the :setting:`DEBUG` setting is set to ``False``.

All messages reaching the ``django`` catch-all logger are discarded
(sent to ``NullHandler``).
All messages reaching the ``django`` catch-all logger when :setting:`DEBUG` is
`True` are sent ot the console. They are simply discarded (sent to
``NullHandler``) when :setting:`DEBUG` is `False`.

.. versionchanged:: 1.5

    Before Django 1.5, all messages reaching the ``django`` logger were
    discarded, regardless of :setting:`DEBUG`.

See also :ref:`Configuring logging <configuring-logging>` to learn how you can
complement or replace this default logging configuration.
+30 −10
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ from django.core import mail
from django.test import TestCase, RequestFactory
from django.test.utils import override_settings
from django.utils.log import CallbackFilter, RequireDebugFalse
from django.utils.six import StringIO

from ..admin_scripts.tests import AdminScriptTestCase

@@ -109,6 +110,28 @@ class PatchLoggingConfigTest(TestCase):
        self.assertEqual(config, new_config)


class DefaultLoggingTest(TestCase):
    def setUp(self):
        self.logger = logging.getLogger('django')
        self.old_stream = self.logger.handlers[0].stream

    def tearDown(self):
        self.logger.handlers[0].stream = self.old_stream

    def test_django_logger(self):
        """
        The 'django' base logger only output anything when DEBUG=True.
        """
        output = StringIO()
        self.logger.handlers[0].stream = output
        self.logger.error("Hey, this is an error.")
        self.assertEqual(output.getvalue(), '')

        with self.settings(DEBUG=True):
            self.logger.error("Hey, this is an error.")
            self.assertEqual(output.getvalue(), 'Hey, this is an error.\n')


class CallbackFilterTest(TestCase):
    def test_sense(self):
        f_false = CallbackFilter(lambda r: False)
@@ -131,6 +154,7 @@ class CallbackFilterTest(TestCase):


class AdminEmailHandlerTest(TestCase):
    logger = logging.getLogger('django.request')

    def get_admin_email_handler(self, logger):
        # Inspired from regressiontests/views/views.py: send_log()
@@ -156,14 +180,13 @@ class AdminEmailHandlerTest(TestCase):
        token1 = 'ping'
        token2 = 'pong'

        logger = logging.getLogger('django.request')
        admin_email_handler = self.get_admin_email_handler(logger)
        admin_email_handler = self.get_admin_email_handler(self.logger)
        # Backup then override original filters
        orig_filters = admin_email_handler.filters
        try:
            admin_email_handler.filters = []

            logger.error(message, token1, token2)
            self.logger.error(message, token1, token2)

            self.assertEqual(len(mail.outbox), 1)
            self.assertEqual(mail.outbox[0].to, ['admin@example.com'])
@@ -187,15 +210,14 @@ class AdminEmailHandlerTest(TestCase):
        token1 = 'ping'
        token2 = 'pong'

        logger = logging.getLogger('django.request')
        admin_email_handler = self.get_admin_email_handler(logger)
        admin_email_handler = self.get_admin_email_handler(self.logger)
        # Backup then override original filters
        orig_filters = admin_email_handler.filters
        try:
            admin_email_handler.filters = []
            rf = RequestFactory()
            request = rf.get('/')
            logger.error(message, token1, token2,
            self.logger.error(message, token1, token2,
                extra={
                    'status_code': 403,
                    'request': request,
@@ -225,8 +247,7 @@ class AdminEmailHandlerTest(TestCase):

        self.assertEqual(len(mail.outbox), 0)

        logger = logging.getLogger('django.request')
        logger.error(message)
        self.logger.error(message)

        self.assertEqual(len(mail.outbox), 1)
        self.assertFalse('\n' in mail.outbox[0].subject)
@@ -250,8 +271,7 @@ class AdminEmailHandlerTest(TestCase):

        self.assertEqual(len(mail.outbox), 0)

        logger = logging.getLogger('django.request')
        logger.error(message)
        self.logger.error(message)

        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, expected_subject)