Fixed #18993 -- 'django' logger logs to console when DEBUG=True
Thanks Preston Holmes for the review.
This commit is contained in:
parent
a014ddfef2
commit
f0f327bbfe
|
@ -24,18 +24,25 @@ except ImportError:
|
||||||
|
|
||||||
getLogger = logging.getLogger
|
getLogger = logging.getLogger
|
||||||
|
|
||||||
# Default logging for Django. This sends an email to
|
# Default logging for Django. This sends an email to the site admins on every
|
||||||
# the site admins on every HTTP 500 error. All other log
|
# HTTP 500 error. Depending on DEBUG, all other log records are either sent to
|
||||||
# records are sent to the bit bucket.
|
# the console (DEBUG=True) or discarded by mean of the NullHandler (DEBUG=False).
|
||||||
DEFAULT_LOGGING = {
|
DEFAULT_LOGGING = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'disable_existing_loggers': False,
|
'disable_existing_loggers': False,
|
||||||
'filters': {
|
'filters': {
|
||||||
'require_debug_false': {
|
'require_debug_false': {
|
||||||
'()': 'django.utils.log.RequireDebugFalse',
|
'()': 'django.utils.log.RequireDebugFalse',
|
||||||
}
|
},
|
||||||
|
'require_debug_true': {
|
||||||
|
'()': 'django.utils.log.RequireDebugTrue',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'handlers': {
|
'handlers': {
|
||||||
|
'console':{
|
||||||
|
'level': 'INFO',
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
},
|
||||||
'null': {
|
'null': {
|
||||||
'class': 'django.utils.log.NullHandler',
|
'class': 'django.utils.log.NullHandler',
|
||||||
},
|
},
|
||||||
|
@ -47,12 +54,13 @@ DEFAULT_LOGGING = {
|
||||||
},
|
},
|
||||||
'loggers': {
|
'loggers': {
|
||||||
'django': {
|
'django': {
|
||||||
'handlers': ['null'],
|
'handlers': ['console'],
|
||||||
|
'filters': ['require_debug_true'],
|
||||||
},
|
},
|
||||||
'django.request': {
|
'django.request': {
|
||||||
'handlers': ['mail_admins'],
|
'handlers': ['mail_admins'],
|
||||||
'level': 'ERROR',
|
'level': 'ERROR',
|
||||||
'propagate': True,
|
'propagate': False,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,3 +138,8 @@ class CallbackFilter(logging.Filter):
|
||||||
class RequireDebugFalse(logging.Filter):
|
class RequireDebugFalse(logging.Filter):
|
||||||
def filter(self, record):
|
def filter(self, record):
|
||||||
return not settings.DEBUG
|
return not settings.DEBUG
|
||||||
|
|
||||||
|
|
||||||
|
class RequireDebugTrue(logging.Filter):
|
||||||
|
def filter(self, record):
|
||||||
|
return settings.DEBUG
|
||||||
|
|
|
@ -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
|
* An instance of :class:`~django.core.urlresolvers.ResolverMatch` is stored on
|
||||||
the request as ``resolver_match``.
|
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
|
Backwards incompatible changes in 1.5
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
|
|
@ -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:
|
.. _default-logging-configuration:
|
||||||
|
|
||||||
Django's 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
|
with ``ERROR`` or ``CRITICAL`` level are sent to :class:`AdminEmailHandler`, as
|
||||||
long as the :setting:`DEBUG` setting is set to ``False``.
|
long as the :setting:`DEBUG` setting is set to ``False``.
|
||||||
|
|
||||||
All messages reaching the ``django`` catch-all logger are discarded
|
All messages reaching the ``django`` catch-all logger when :setting:`DEBUG` is
|
||||||
(sent to ``NullHandler``).
|
`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.
|
||||||
|
|
|
@ -9,6 +9,7 @@ from django.core import mail
|
||||||
from django.test import TestCase, RequestFactory
|
from django.test import TestCase, RequestFactory
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.log import CallbackFilter, RequireDebugFalse
|
from django.utils.log import CallbackFilter, RequireDebugFalse
|
||||||
|
from django.utils.six import StringIO
|
||||||
|
|
||||||
from ..admin_scripts.tests import AdminScriptTestCase
|
from ..admin_scripts.tests import AdminScriptTestCase
|
||||||
|
|
||||||
|
@ -109,6 +110,28 @@ class PatchLoggingConfigTest(TestCase):
|
||||||
self.assertEqual(config, new_config)
|
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):
|
class CallbackFilterTest(TestCase):
|
||||||
def test_sense(self):
|
def test_sense(self):
|
||||||
f_false = CallbackFilter(lambda r: False)
|
f_false = CallbackFilter(lambda r: False)
|
||||||
|
@ -131,6 +154,7 @@ class CallbackFilterTest(TestCase):
|
||||||
|
|
||||||
|
|
||||||
class AdminEmailHandlerTest(TestCase):
|
class AdminEmailHandlerTest(TestCase):
|
||||||
|
logger = logging.getLogger('django.request')
|
||||||
|
|
||||||
def get_admin_email_handler(self, logger):
|
def get_admin_email_handler(self, logger):
|
||||||
# Inspired from regressiontests/views/views.py: send_log()
|
# Inspired from regressiontests/views/views.py: send_log()
|
||||||
|
@ -156,14 +180,13 @@ class AdminEmailHandlerTest(TestCase):
|
||||||
token1 = 'ping'
|
token1 = 'ping'
|
||||||
token2 = 'pong'
|
token2 = 'pong'
|
||||||
|
|
||||||
logger = logging.getLogger('django.request')
|
admin_email_handler = self.get_admin_email_handler(self.logger)
|
||||||
admin_email_handler = self.get_admin_email_handler(logger)
|
|
||||||
# Backup then override original filters
|
# Backup then override original filters
|
||||||
orig_filters = admin_email_handler.filters
|
orig_filters = admin_email_handler.filters
|
||||||
try:
|
try:
|
||||||
admin_email_handler.filters = []
|
admin_email_handler.filters = []
|
||||||
|
|
||||||
logger.error(message, token1, token2)
|
self.logger.error(message, token1, token2)
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
self.assertEqual(mail.outbox[0].to, ['admin@example.com'])
|
self.assertEqual(mail.outbox[0].to, ['admin@example.com'])
|
||||||
|
@ -187,15 +210,14 @@ class AdminEmailHandlerTest(TestCase):
|
||||||
token1 = 'ping'
|
token1 = 'ping'
|
||||||
token2 = 'pong'
|
token2 = 'pong'
|
||||||
|
|
||||||
logger = logging.getLogger('django.request')
|
admin_email_handler = self.get_admin_email_handler(self.logger)
|
||||||
admin_email_handler = self.get_admin_email_handler(logger)
|
|
||||||
# Backup then override original filters
|
# Backup then override original filters
|
||||||
orig_filters = admin_email_handler.filters
|
orig_filters = admin_email_handler.filters
|
||||||
try:
|
try:
|
||||||
admin_email_handler.filters = []
|
admin_email_handler.filters = []
|
||||||
rf = RequestFactory()
|
rf = RequestFactory()
|
||||||
request = rf.get('/')
|
request = rf.get('/')
|
||||||
logger.error(message, token1, token2,
|
self.logger.error(message, token1, token2,
|
||||||
extra={
|
extra={
|
||||||
'status_code': 403,
|
'status_code': 403,
|
||||||
'request': request,
|
'request': request,
|
||||||
|
@ -225,8 +247,7 @@ class AdminEmailHandlerTest(TestCase):
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 0)
|
self.assertEqual(len(mail.outbox), 0)
|
||||||
|
|
||||||
logger = logging.getLogger('django.request')
|
self.logger.error(message)
|
||||||
logger.error(message)
|
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
self.assertFalse('\n' in mail.outbox[0].subject)
|
self.assertFalse('\n' in mail.outbox[0].subject)
|
||||||
|
@ -250,8 +271,7 @@ class AdminEmailHandlerTest(TestCase):
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 0)
|
self.assertEqual(len(mail.outbox), 0)
|
||||||
|
|
||||||
logger = logging.getLogger('django.request')
|
self.logger.error(message)
|
||||||
logger.error(message)
|
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
self.assertEqual(mail.outbox[0].subject, expected_subject)
|
self.assertEqual(mail.outbox[0].subject, expected_subject)
|
||||||
|
|
Loading…
Reference in New Issue