diff --git a/django/conf/__init__.py b/django/conf/__init__.py
index 4337bd4..3b829ce 100644
a
|
b
|
def compat_patch_logging_config(logging_config):
|
199 | 199 | while filter_name in filters: |
200 | 200 | filter_name = filter_name + "_" |
201 | 201 | |
202 | | def _callback(record): |
203 | | from django.conf import settings |
204 | | return not settings.DEBUG |
205 | | |
206 | 202 | filters[filter_name] = { |
207 | | "()": "django.utils.log.CallbackFilter", |
208 | | "callback": _callback |
209 | | } |
| 203 | "()": "django.utils.log.RequireDebugFalse", |
| 204 | } |
210 | 205 | |
211 | 206 | logging_config["handlers"]["mail_admins"]["filters"] = [filter_name] |
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 637b5f4..29c9812 100644
a
|
b
|
LOGGING_CONFIG = 'django.utils.log.dictConfig'
|
514 | 514 | # The default logging configuration. This sends an email to |
515 | 515 | # the site admins on every HTTP 500 error. All other log |
516 | 516 | # records are sent to the bit bucket. |
| 517 | |
517 | 518 | LOGGING = { |
518 | 519 | 'version': 1, |
519 | 520 | 'disable_existing_loggers': False, |
520 | 521 | 'filters': { |
521 | 522 | 'require_debug_false': { |
522 | | '()': 'django.utils.log.CallbackFilter', |
523 | | 'callback': lambda r: not DEBUG |
| 523 | '()': 'django.utils.log.RequireDebugFalse', |
524 | 524 | } |
525 | 525 | }, |
526 | 526 | 'handlers': { |
diff --git a/django/conf/project_template/settings.py b/django/conf/project_template/settings.py
index 3a2243f..b92c116 100644
a
|
b
|
LOGGING = {
|
128 | 128 | 'disable_existing_loggers': False, |
129 | 129 | 'filters': { |
130 | 130 | 'require_debug_false': { |
131 | | '()': 'django.utils.log.CallbackFilter', |
132 | | 'callback': lambda r: not DEBUG |
| 131 | '()': 'django.utils.log.RequireDebugFalse' |
133 | 132 | } |
134 | 133 | }, |
135 | 134 | 'handlers': { |
diff --git a/django/utils/log.py b/django/utils/log.py
index a8098fc..8ce37f5 100644
a
|
b
|
logger = getLogger('django')
|
30 | 30 | if not logger.handlers: |
31 | 31 | logger.addHandler(NullHandler()) |
32 | 32 | |
| 33 | |
33 | 34 | class AdminEmailHandler(logging.Handler): |
34 | 35 | """An exception log handler that emails log entries to site admins. |
35 | 36 | |
… |
… |
class CallbackFilter(logging.Filter):
|
82 | 83 | def __init__(self, callback): |
83 | 84 | self.callback = callback |
84 | 85 | |
85 | | |
86 | 86 | def filter(self, record): |
87 | 87 | if self.callback(record): |
88 | 88 | return 1 |
89 | 89 | return 0 |
| 90 | |
| 91 | |
| 92 | class RequireDebugFalse(logging.Filter): |
| 93 | def filter(self, record): |
| 94 | return not settings.DEBUG |
diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt
index 90c5e24..f12db28 100644
a
|
b
|
to :class:`django.utils.log.AdminEmailHandler` to prevent admin error emails in
|
593 | 593 | |
594 | 594 | 'filters': { |
595 | 595 | 'require_debug_false': { |
596 | | '()': 'django.utils.log.CallbackFilter', |
597 | | 'callback': lambda r: not DEBUG |
| 596 | '()': 'django.utils.log.RequireDebugFalse' |
598 | 597 | } |
599 | 598 | }, |
600 | 599 | 'handlers': { |
diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt
index f23b529..3b4e26a 100644
a
|
b
|
Python logging module.
|
504 | 504 | Filters |
505 | 505 | ------- |
506 | 506 | |
507 | | Django provides one log filter in addition to those provided by the |
| 507 | Django provides two log filter in addition to those provided by the |
508 | 508 | Python logging module. |
509 | 509 | |
510 | 510 | .. class:: CallbackFilter(callback) |
… |
… |
Python logging module.
|
516 | 516 | through the filter. Handling of that record will not proceed if the callback |
517 | 517 | returns False. |
518 | 518 | |
| 519 | .. class:: RequireDebugFalse() |
| 520 | |
| 521 | .. versionadded:: 1.4 |
| 522 | |
| 523 | This filter will only proceed records when settings.DEBUG is False. |
| 524 | |
519 | 525 | This filter is used as follows in the default :setting:`LOGGING` |
520 | 526 | configuration to ensure that the :class:`AdminEmailHandler` only sends error |
521 | 527 | emails to admins when :setting:`DEBUG` is `False`:: |
522 | 528 | |
523 | 529 | 'filters': { |
524 | 530 | 'require_debug_false': { |
525 | | '()': 'django.utils.log.CallbackFilter', |
526 | | 'callback': lambda r: not DEBUG |
| 531 | '()': 'django.utils.log.RequireDebugFalse', |
527 | 532 | } |
528 | 533 | }, |
529 | 534 | 'handlers': { |
diff --git a/tests/regressiontests/logging_tests/tests.py b/tests/regressiontests/logging_tests/tests.py
index 76c5185..354950c 100644
a
|
b
|
from __future__ import with_statement
|
2 | 2 | |
3 | 3 | import copy |
4 | 4 | |
5 | | from django.conf import compat_patch_logging_config |
| 5 | from django.conf import compat_patch_logging_config, settings, global_settings |
6 | 6 | from django.test import TestCase |
| 7 | |
| 8 | from django.utils.log import CallbackFilter, RequireDebugFalse, getLogger |
7 | 9 | from django.test.utils import override_settings |
8 | | from django.utils.log import CallbackFilter, getLogger |
9 | 10 | from django.core import mail |
10 | 11 | |
11 | 12 | |
12 | | |
13 | 13 | # logging config prior to using filter with mail_admins |
14 | 14 | OLD_LOGGING = { |
15 | 15 | 'version': 1, |
… |
… |
OLD_LOGGING = {
|
30 | 30 | } |
31 | 31 | |
32 | 32 | |
33 | | |
34 | 33 | class PatchLoggingConfigTest(TestCase): |
35 | 34 | """ |
36 | 35 | Tests for backward-compat shim for #16288. These tests should be removed in |
… |
… |
class PatchLoggingConfigTest(TestCase):
|
50 | 49 | config["handlers"]["mail_admins"]["filters"], |
51 | 50 | ['require_debug_false']) |
52 | 51 | |
53 | | |
54 | 52 | def test_filter_configuration(self): |
55 | 53 | """ |
56 | | Test that the debug-false filter is a CallbackFilter with a callback |
57 | | that works as expected (returns ``not DEBUG``). |
| 54 | Test that the require_debug_false filter (RequireDebugFalse) is added |
| 55 | to the settings when not explicitly specified in the settings. |
58 | 56 | |
59 | 57 | """ |
60 | 58 | config = copy.deepcopy(OLD_LOGGING) |
61 | 59 | compat_patch_logging_config(config) |
62 | 60 | |
63 | 61 | flt = config["filters"]["require_debug_false"] |
| 62 | self.assertEqual(flt["()"], "django.utils.log.RequireDebugFalse") |
64 | 63 | |
65 | | self.assertEqual(flt["()"], "django.utils.log.CallbackFilter") |
66 | | |
67 | | callback = flt["callback"] |
| 64 | def test_require_debug_false_filter(self): |
| 65 | """Test the RequireDebugFalse filter""" |
| 66 | filter_ = RequireDebugFalse() |
68 | 67 | |
69 | 68 | with self.settings(DEBUG=True): |
70 | | self.assertEqual(callback("record is not used"), False) |
| 69 | self.assertEqual(filter_.filter("record is not used"), False) |
71 | 70 | |
72 | 71 | with self.settings(DEBUG=False): |
73 | | self.assertEqual(callback("record is not used"), True) |
74 | | |
| 72 | self.assertEqual(filter_.filter("record is not used"), True) |
75 | 73 | |
76 | 74 | def test_no_patch_if_filters_key_exists(self): |
77 | 75 | """ |
… |
… |
class PatchLoggingConfigTest(TestCase):
|
100 | 98 | self.assertEqual(config, new_config) |
101 | 99 | |
102 | 100 | |
| 101 | class TestRequireDebugFalseNoLoggingSetting(TestCase): |
| 102 | """ |
| 103 | Test that RequireDebugFalse works as excpected when LOGGING is not |
| 104 | specified in the project settings. See #16568. |
| 105 | """ |
| 106 | def test_require_debug_no_logging_setting(self): |
| 107 | filter_ = RequireDebugFalse() |
| 108 | |
| 109 | with self.settings(DEBUG=True): |
| 110 | self.assertEqual(filter_.filter("record is not used"), False) |
| 111 | |
| 112 | with self.settings(DEBUG=False): |
| 113 | self.assertEqual(filter_.filter("record is not used"), True) |
| 114 | |
| 115 | |
103 | 116 | class CallbackFilterTest(TestCase): |
104 | 117 | def test_sense(self): |
105 | 118 | f_false = CallbackFilter(lambda r: False) |
… |
… |
class CallbackFilterTest(TestCase):
|
110 | 123 | |
111 | 124 | def test_passes_on_record(self): |
112 | 125 | collector = [] |
| 126 | |
113 | 127 | def _callback(record): |
114 | 128 | collector.append(record) |
115 | 129 | return True |