Ticket #16288: 16288.diff
File 16288.diff, 15.0 KB (added by , 13 years ago) |
---|
-
django/conf/__init__.py
diff --git a/django/conf/__init__.py b/django/conf/__init__.py index 8964b1b..d5de56a 100644
a b class Settings(BaseSettings): 135 135 logging_config_module = importlib.import_module(logging_config_path) 136 136 logging_config_func = getattr(logging_config_module, logging_config_func_name) 137 137 138 # Backwards-compatibility shim for #16288 fix 139 compat_patch_logging_config(self.LOGGING) 140 138 141 # ... then invoke it with the logging settings 139 142 logging_config_func(self.LOGGING) 140 143 … … class UserSettingsHolder(BaseSettings): 165 168 166 169 settings = LazySettings() 167 170 171 172 173 def compat_patch_logging_config(logging_config): 174 """ 175 Backwards-compatibility shim for #16288 fix. Takes initial value of 176 ``LOGGING`` setting and patches it in-place (issuing deprecation warning) 177 if "mail_admins" logging handler is configured but has no filters. 178 179 """ 180 # Shim only if LOGGING["handlers"]["mail_admins"] exists, 181 # but has no "filters" key 182 if "filters" not in logging_config.get( 183 "handlers", {}).get( 184 "mail_admins", {"filters": []}): 185 186 warnings.warn( 187 "You have no filters defined on the 'mail_admins' logging " 188 "handler. Since uncaught request exceptions are now logged " 189 "in DEBUG mode as well as in production " 190 "(see https://code.djangoproject.com/ticket/16288), " 191 "to maintain backward-compatibility Django is adding a " 192 "filter for you to prevent emailing admins in DEBUG mode. " 193 "To get rid of this warning, add the filter explicitly " 194 "in your LOGGING config " 195 "(see http://docs.djangoproject.com/en/dev/releases/1.4/" 196 "#request-exceptions-are-now-always-logged).", 197 PendingDeprecationWarning) 198 199 filter_name = "require_debug_false" 200 201 filters = logging_config.setdefault("filters", {}) 202 while filter_name in filters: 203 filter_name = filter_name + "_" 204 205 def _callback(record): 206 from django.conf import settings 207 return not settings.DEBUG 208 209 filters[filter_name] = { 210 "()": "django.utils.log.CallbackFilter", 211 "callback": _callback 212 } 213 214 logging_config["handlers"]["mail_admins"]["filters"] = [filter_name] -
django/conf/global_settings.py
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index ab31c15..fedea55 100644
a b LOGGING_CONFIG = 'django.utils.log.dictConfig' 525 525 LOGGING = { 526 526 'version': 1, 527 527 'disable_existing_loggers': False, 528 'filters': { 529 'require_debug_false': { 530 '()': 'django.utils.log.CallbackFilter', 531 'callback': lambda r: not DEBUG 532 } 533 }, 528 534 'handlers': { 529 535 'mail_admins': { 530 536 'level': 'ERROR', 537 'filters': ['require_debug_false'], 531 538 'class': 'django.utils.log.AdminEmailHandler' 532 539 } 533 540 }, -
django/conf/project_template/settings.py
diff --git a/django/conf/project_template/settings.py b/django/conf/project_template/settings.py index e719dec..794522b 100644
a b INSTALLED_APPS = ( 125 125 126 126 # A sample logging configuration. The only tangible logging 127 127 # performed by this configuration is to send an email to 128 # the site admins on every HTTP 500 error .128 # the site admins on every HTTP 500 error when DEBUG=False. 129 129 # See http://docs.djangoproject.com/en/dev/topics/logging for 130 130 # more details on how to customize your logging configuration. 131 131 LOGGING = { 132 132 'version': 1, 133 133 'disable_existing_loggers': False, 134 'filters': { 135 'require_debug_false': { 136 '()': 'django.utils.log.CallbackFilter', 137 'callback': lambda r: not DEBUG 138 } 139 }, 134 140 'handlers': { 135 141 'mail_admins': { 136 142 'level': 'ERROR', 143 'filters': ['require_debug_false'], 137 144 'class': 'django.utils.log.AdminEmailHandler' 138 145 } 139 146 }, -
django/core/handlers/base.py
diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index 7cae42e..5529097 100644
a b class BaseHandler(object): 198 198 if settings.DEBUG_PROPAGATE_EXCEPTIONS: 199 199 raise 200 200 201 if settings.DEBUG:202 from django.views import debug203 return debug.technical_500_response(request, *exc_info)204 205 201 logger.error('Internal Server Error: %s' % request.path, 206 202 exc_info=exc_info, 207 203 extra={ … … class BaseHandler(object): 210 206 } 211 207 ) 212 208 209 if settings.DEBUG: 210 from django.views import debug 211 return debug.technical_500_response(request, *exc_info) 212 213 213 # If Http500 handler is not installed, re-raise last exception 214 214 if resolver.urlconf_module is None: 215 215 raise exc_info[1], None, exc_info[2] -
django/utils/log.py
diff --git a/django/utils/log.py b/django/utils/log.py index 969a9d9..d0f5109 100644
a b class AdminEmailHandler(logging.Handler): 70 70 reporter = ExceptionReporter(request, is_email=True, *exc_info) 71 71 html_message = self.include_html and reporter.get_traceback_html() or None 72 72 mail.mail_admins(subject, message, fail_silently=True, html_message=html_message) 73 74 75 class CallbackFilter(logging.Filter): 76 """ 77 A logging filter that checks the return value of a given callable (which 78 takes the record-to-be-logged as its only parameter) to decide whether to 79 log a record. 80 81 """ 82 def __init__(self, callback): 83 self.callback = callback 84 85 86 def filter(self, record): 87 if self.callback(record): 88 return 1 89 return 0 -
docs/internals/deprecation.txt
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 131f813..cd65a89 100644
a b their deprecation, as per the :ref:`Django deprecation policy 210 210 * Legacy ways of calling 211 211 :func:`~django.views.decorators.cache.cache_page` will be removed. 212 212 213 * The backward-compatibility shim to automatically add a debug-false 214 filter to the ``'mail_admins'`` logging handler will be removed. The 215 :setting:`LOGGING` setting should include this filter explicitly if 216 it is desired. 217 213 218 * 2.0 214 219 * ``django.views.defaults.shortcut()``. This function has been moved 215 220 to ``django.contrib.contenttypes.views.shortcut()`` as part of the -
docs/releases/1.4.txt
diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt index 7cc3fb1..0635ece 100644
a b releases 8.0 and 8.1 was near (November 2010.) 387 387 388 388 Django 1.4 takes that policy further and sets 8.2 as the minimum PostgreSQL 389 389 version it officially supports. 390 391 Request exceptions are now always logged 392 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 393 394 When :doc:`logging support </topics/logging/>` was added to Django in 1.3, the 395 admin error email support was moved into the 396 :class:`django.utils.log.AdminEmailHandler`, attached to the 397 ``'django.request'`` logger. In order to maintain the established behavior of 398 error emails, the ``'django.request'`` logger was called only when 399 :setting:`DEBUG` was `False`. 400 401 To increase the flexibility of request-error logging, the ``'django.request'`` 402 logger is now called regardless of the value of :setting:`DEBUG`, and the 403 default settings file for new projects now includes a separate filter attached 404 to :class:`django.utils.log.AdminEmailHandler` to prevent admin error emails in 405 `DEBUG` mode:: 406 407 'filters': { 408 'require_debug_false': { 409 '()': 'django.utils.log.CallbackFilter', 410 'callback': lambda r: not DEBUG 411 } 412 }, 413 'handlers': { 414 'mail_admins': { 415 'level': 'ERROR', 416 'filters': ['require_debug_false'], 417 'class': 'django.utils.log.AdminEmailHandler' 418 } 419 }, 420 421 If your project was created prior to this change, your :setting:`LOGGING` 422 setting will not include this new filter. In order to maintain 423 backwards-compatibility, Django will detect that your ``'mail_admins'`` handler 424 configuration includes no ``'filters'`` section, and will automatically add 425 this filter for you and issue a pending-deprecation warning. This will become a 426 deprecation warning in Django 1.5, and in Django 1.6 the 427 backwards-compatibility shim will be removed entirely. 428 429 The existence of any ``'filters'`` key under the ``'mail_admins'`` handler will 430 disable this backward-compatibility shim and deprecation warning. -
docs/topics/logging.txt
diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt index 06050af..9137038 100644
a b Python logging module. 501 501 :ref:`Filtering error reports<filtering-error-reports>`. 502 502 503 503 .. _django-sentry: http://pypi.python.org/pypi/django-sentry 504 505 506 Filters 507 ------- 508 509 Django provides one log filter in addition to those provided by the 510 Python logging module. 511 512 .. class:: CallbackFilter(callback) 513 514 .. versionadded:: 1.4 515 516 This filter accepts a callback function (which should accept a single 517 argument, the record to be logged), and calls it for each record that passes 518 through the filter. Handling of that record will not proceed if the callback 519 returns False. 520 521 This filter is used as follows in the default :setting:`LOGGING` 522 configuration to ensure that the :class:`AdminEmailHandler` only sends error 523 emails to admins when :setting:`DEBUG` is `False`:: 524 525 'filters': { 526 'require_debug_false': { 527 '()': 'django.utils.log.CallbackFilter', 528 'callback': lambda r: not DEBUG 529 } 530 }, 531 'handlers': { 532 'mail_admins': { 533 'level': 'ERROR', 534 'filters': ['require_debug_false'], 535 'class': 'django.utils.log.AdminEmailHandler' 536 } 537 }, -
new file tests/regressiontests/logging_tests/tests.py
diff --git a/tests/regressiontests/logging_tests/__init__.py b/tests/regressiontests/logging_tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/regressiontests/logging_tests/models.py b/tests/regressiontests/logging_tests/models.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/regressiontests/logging_tests/tests.py b/tests/regressiontests/logging_tests/tests.py new file mode 100644 index 0000000..e2da4d4
- + 1 from __future__ import with_statement 2 3 import copy 4 5 from django.conf import compat_patch_logging_config 6 from django.test import TestCase 7 from django.utils.log import CallbackFilter 8 9 10 # logging config prior to using filter with mail_admins 11 OLD_LOGGING = { 12 'version': 1, 13 'disable_existing_loggers': False, 14 'handlers': { 15 'mail_admins': { 16 'level': 'ERROR', 17 'class': 'django.utils.log.AdminEmailHandler' 18 } 19 }, 20 'loggers': { 21 'django.request': { 22 'handlers': ['mail_admins'], 23 'level': 'ERROR', 24 'propagate': True, 25 }, 26 } 27 } 28 29 30 31 class PatchLoggingConfigTest(TestCase): 32 def test_filter_added(self): 33 """ 34 Test that debug-false filter is added to mail_admins handler if it has 35 no filters. 36 37 """ 38 config = copy.deepcopy(OLD_LOGGING) 39 compat_patch_logging_config(config) 40 41 self.assertEqual( 42 config["handlers"]["mail_admins"]["filters"], 43 ['require_debug_false']) 44 45 46 def test_filter_configuration(self): 47 """ 48 Test that the debug-false filter is a CallbackFilter with a callback 49 that works as expected (returns ``not DEBUG``). 50 51 """ 52 config = copy.deepcopy(OLD_LOGGING) 53 compat_patch_logging_config(config) 54 55 flt = config["filters"]["require_debug_false"] 56 57 self.assertEqual(flt["()"], "django.utils.log.CallbackFilter") 58 59 callback = flt["callback"] 60 61 with self.settings(DEBUG=True): 62 self.assertEqual(callback("record is not used"), False) 63 64 with self.settings(DEBUG=False): 65 self.assertEqual(callback("record is not used"), True) 66 67 68 def test_no_patch_if_filters_key_exists(self): 69 """ 70 Test that the logging configuration is not modified if the mail_admins 71 handler already has a "filters" key. 72 73 """ 74 config = copy.deepcopy(OLD_LOGGING) 75 config["handlers"]["mail_admins"]["filters"] = [] 76 new_config = copy.deepcopy(config) 77 compat_patch_logging_config(new_config) 78 79 self.assertEqual(config, new_config) 80 81 def test_no_patch_if_no_mail_admins_handler(self): 82 """ 83 Test that the logging configuration is not modified if the mail_admins 84 handler is not present. 85 86 """ 87 config = copy.deepcopy(OLD_LOGGING) 88 config["handlers"].pop("mail_admins") 89 new_config = copy.deepcopy(config) 90 compat_patch_logging_config(new_config) 91 92 self.assertEqual(config, new_config) 93 94 95 class CallbackFilterTest(TestCase): 96 def test_sense(self): 97 f_false = CallbackFilter(lambda r: False) 98 f_true = CallbackFilter(lambda r: True) 99 100 self.assertEqual(f_false.filter("record"), False) 101 self.assertEqual(f_true.filter("record"), True) 102 103 def test_passes_on_record(self): 104 collector = [] 105 def _callback(record): 106 collector.append(record) 107 return True 108 f = CallbackFilter(_callback) 109 110 f.filter("a record") 111 112 self.assertEqual(collector, ["a record"]) -
tests/regressiontests/views/views.py
diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py index 732ff28..7d59257 100644
a b def raises_template_does_not_exist(request): 134 134 135 135 def send_log(request, exc_info): 136 136 logger = getLogger('django.request') 137 # The default logging config has a logging filter to ensure admin emails are 138 # only sent with DEBUG=False, but since someone might choose to remove that 139 # filter, we still want to be able to test the behavior of error emails 140 # with DEBUG=True. So we need to remove the filter temporarily. 141 admin_email_handler = [ 142 h for h in logger.handlers 143 if h.__class__.__name__ == "AdminEmailHandler" 144 ][0] 145 orig_filters = admin_email_handler.filters 146 admin_email_handler.filters = [] 137 147 logger.error('Internal Server Error: %s' % request.path, 138 148 exc_info=exc_info, 139 149 extra={ … … def send_log(request, exc_info): 141 151 'request': request 142 152 } 143 153 ) 154 admin_email_handler.filters = orig_filters 144 155 145 156 def non_sensitive_view(request): 146 157 # Do not just use plain strings for the variables' values in the code