Fixed #16568 -- Added RequireDebugFalse filter to prevent sending 500 error emails when DEBUG is True in projects with no explicit LOGGING setting. Thanks to Andreas Pelme for report and patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16840 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f9dad46d36
commit
343004c4de
|
@ -199,13 +199,8 @@ def compat_patch_logging_config(logging_config):
|
||||||
while filter_name in filters:
|
while filter_name in filters:
|
||||||
filter_name = filter_name + "_"
|
filter_name = filter_name + "_"
|
||||||
|
|
||||||
def _callback(record):
|
|
||||||
from django.conf import settings
|
|
||||||
return not settings.DEBUG
|
|
||||||
|
|
||||||
filters[filter_name] = {
|
filters[filter_name] = {
|
||||||
"()": "django.utils.log.CallbackFilter",
|
"()": "django.utils.log.RequireDebugFalse",
|
||||||
"callback": _callback
|
}
|
||||||
}
|
|
||||||
|
|
||||||
logging_config["handlers"]["mail_admins"]["filters"] = [filter_name]
|
logging_config["handlers"]["mail_admins"]["filters"] = [filter_name]
|
||||||
|
|
|
@ -514,13 +514,13 @@ LOGGING_CONFIG = 'django.utils.log.dictConfig'
|
||||||
# The default logging configuration. This sends an email to
|
# The default logging configuration. This sends an email to
|
||||||
# the site admins on every HTTP 500 error. All other log
|
# the site admins on every HTTP 500 error. All other log
|
||||||
# records are sent to the bit bucket.
|
# records are sent to the bit bucket.
|
||||||
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'disable_existing_loggers': False,
|
'disable_existing_loggers': False,
|
||||||
'filters': {
|
'filters': {
|
||||||
'require_debug_false': {
|
'require_debug_false': {
|
||||||
'()': 'django.utils.log.CallbackFilter',
|
'()': 'django.utils.log.RequireDebugFalse',
|
||||||
'callback': lambda r: not DEBUG
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'handlers': {
|
'handlers': {
|
||||||
|
|
|
@ -128,8 +128,7 @@ LOGGING = {
|
||||||
'disable_existing_loggers': False,
|
'disable_existing_loggers': False,
|
||||||
'filters': {
|
'filters': {
|
||||||
'require_debug_false': {
|
'require_debug_false': {
|
||||||
'()': 'django.utils.log.CallbackFilter',
|
'()': 'django.utils.log.RequireDebugFalse'
|
||||||
'callback': lambda r: not DEBUG
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'handlers': {
|
'handlers': {
|
||||||
|
|
|
@ -30,6 +30,7 @@ logger = getLogger('django')
|
||||||
if not logger.handlers:
|
if not logger.handlers:
|
||||||
logger.addHandler(NullHandler())
|
logger.addHandler(NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class AdminEmailHandler(logging.Handler):
|
class AdminEmailHandler(logging.Handler):
|
||||||
"""An exception log handler that emails log entries to site admins.
|
"""An exception log handler that emails log entries to site admins.
|
||||||
|
|
||||||
|
@ -82,8 +83,12 @@ class CallbackFilter(logging.Filter):
|
||||||
def __init__(self, callback):
|
def __init__(self, callback):
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
|
|
||||||
|
|
||||||
def filter(self, record):
|
def filter(self, record):
|
||||||
if self.callback(record):
|
if self.callback(record):
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
class RequireDebugFalse(logging.Filter):
|
||||||
|
def filter(self, record):
|
||||||
|
return not settings.DEBUG
|
||||||
|
|
|
@ -593,8 +593,7 @@ to :class:`django.utils.log.AdminEmailHandler` to prevent admin error emails in
|
||||||
|
|
||||||
'filters': {
|
'filters': {
|
||||||
'require_debug_false': {
|
'require_debug_false': {
|
||||||
'()': 'django.utils.log.CallbackFilter',
|
'()': 'django.utils.log.RequireDebugFalse'
|
||||||
'callback': lambda r: not DEBUG
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'handlers': {
|
'handlers': {
|
||||||
|
|
|
@ -504,8 +504,8 @@ Python logging module.
|
||||||
Filters
|
Filters
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Django provides one log filter in addition to those provided by the
|
Django provides two log filters in addition to those provided by the Python
|
||||||
Python logging module.
|
logging module.
|
||||||
|
|
||||||
.. class:: CallbackFilter(callback)
|
.. class:: CallbackFilter(callback)
|
||||||
|
|
||||||
|
@ -516,14 +516,19 @@ Python logging module.
|
||||||
through the filter. Handling of that record will not proceed if the callback
|
through the filter. Handling of that record will not proceed if the callback
|
||||||
returns False.
|
returns False.
|
||||||
|
|
||||||
|
.. class:: RequireDebugFalse()
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
|
This filter will only pass on records when settings.DEBUG is False.
|
||||||
|
|
||||||
This filter is used as follows in the default :setting:`LOGGING`
|
This filter is used as follows in the default :setting:`LOGGING`
|
||||||
configuration to ensure that the :class:`AdminEmailHandler` only sends error
|
configuration to ensure that the :class:`AdminEmailHandler` only sends error
|
||||||
emails to admins when :setting:`DEBUG` is `False`::
|
emails to admins when :setting:`DEBUG` is `False`::
|
||||||
|
|
||||||
'filters': {
|
'filters': {
|
||||||
'require_debug_false': {
|
'require_debug_false': {
|
||||||
'()': 'django.utils.log.CallbackFilter',
|
'()': 'django.utils.log.RequireDebugFalse',
|
||||||
'callback': lambda r: not DEBUG
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'handlers': {
|
'handlers': {
|
||||||
|
|
|
@ -4,10 +4,10 @@ import copy
|
||||||
|
|
||||||
from django.conf import compat_patch_logging_config
|
from django.conf import compat_patch_logging_config
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
|
||||||
from django.utils.log import CallbackFilter, getLogger
|
|
||||||
from django.core import mail
|
|
||||||
|
|
||||||
|
from django.utils.log import CallbackFilter, RequireDebugFalse, getLogger
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
from django.core import mail
|
||||||
|
|
||||||
|
|
||||||
# logging config prior to using filter with mail_admins
|
# logging config prior to using filter with mail_admins
|
||||||
|
@ -30,7 +30,6 @@ OLD_LOGGING = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PatchLoggingConfigTest(TestCase):
|
class PatchLoggingConfigTest(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests for backward-compat shim for #16288. These tests should be removed in
|
Tests for backward-compat shim for #16288. These tests should be removed in
|
||||||
|
@ -50,28 +49,30 @@ class PatchLoggingConfigTest(TestCase):
|
||||||
config["handlers"]["mail_admins"]["filters"],
|
config["handlers"]["mail_admins"]["filters"],
|
||||||
['require_debug_false'])
|
['require_debug_false'])
|
||||||
|
|
||||||
|
|
||||||
def test_filter_configuration(self):
|
def test_filter_configuration(self):
|
||||||
"""
|
"""
|
||||||
Test that the debug-false filter is a CallbackFilter with a callback
|
Test that the auto-added require_debug_false filter is an instance of
|
||||||
that works as expected (returns ``not DEBUG``).
|
`RequireDebugFalse` filter class.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
config = copy.deepcopy(OLD_LOGGING)
|
config = copy.deepcopy(OLD_LOGGING)
|
||||||
compat_patch_logging_config(config)
|
compat_patch_logging_config(config)
|
||||||
|
|
||||||
flt = config["filters"]["require_debug_false"]
|
flt = config["filters"]["require_debug_false"]
|
||||||
|
self.assertEqual(flt["()"], "django.utils.log.RequireDebugFalse")
|
||||||
|
|
||||||
self.assertEqual(flt["()"], "django.utils.log.CallbackFilter")
|
def test_require_debug_false_filter(self):
|
||||||
|
"""
|
||||||
|
Test the RequireDebugFalse filter class.
|
||||||
|
|
||||||
callback = flt["callback"]
|
"""
|
||||||
|
filter_ = RequireDebugFalse()
|
||||||
|
|
||||||
with self.settings(DEBUG=True):
|
with self.settings(DEBUG=True):
|
||||||
self.assertEqual(callback("record is not used"), False)
|
self.assertEqual(filter_.filter("record is not used"), False)
|
||||||
|
|
||||||
with self.settings(DEBUG=False):
|
with self.settings(DEBUG=False):
|
||||||
self.assertEqual(callback("record is not used"), True)
|
self.assertEqual(filter_.filter("record is not used"), True)
|
||||||
|
|
||||||
|
|
||||||
def test_no_patch_if_filters_key_exists(self):
|
def test_no_patch_if_filters_key_exists(self):
|
||||||
"""
|
"""
|
||||||
|
@ -110,6 +111,7 @@ class CallbackFilterTest(TestCase):
|
||||||
|
|
||||||
def test_passes_on_record(self):
|
def test_passes_on_record(self):
|
||||||
collector = []
|
collector = []
|
||||||
|
|
||||||
def _callback(record):
|
def _callback(record):
|
||||||
collector.append(record)
|
collector.append(record)
|
||||||
return True
|
return True
|
||||||
|
|
Loading…
Reference in New Issue