使用Django 1.5.1:
DEBUG = False LOGGING = { 'version': 1, 'disable_existing_loggers': True, 'formatters': { 'verbose': { 'format': '%(levelname)s %(asctime)s %(module)s %(message)s' }, }, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'verbose', }, }, 'loggers': { # root logger '': { 'handlers': ['console'], }, #'django.request': { # 'handlers': ['console'], # 'level': 'DEBUG', # 'propagate': False, #}, } }
如果我取消注释行,并调用一个具有的视图1/0,则将回溯打印到控制台:
1/0
ERROR 2013-11-29 13:33:23,102 base Internal Server Error: /comment/*******/ Traceback (most recent call last): ... File "*****/comments/views.py", line 10, in post 1/0 ZeroDivisionError: integer division or modulo by zero WARNING 2013-11-29 13:33:23,103 csrf Forbidden (CSRF cookie not set.): /comment/******/ [29/Nov/2013 13:33:23] "POST /comment/******/ HTTP/1.0" 500 27
但是,如果这些行保持注释状态,则不会向控制台打印回溯信息,只是:
[29/Nov/2013 13:33:23] "POST /comment/******/ HTTP/1.0" 500 27
我以为如果django.request未配置logger,它将传播到root logger,后者将所有内容打印到控制台。
django.request
我没有发现任何django.request特别的信息。
为什么不起作用?
在这里我读到:
在Django 1.5之前,LOGGING设置始终会覆盖默认的Django日志记录配置。从Django 1.5开始,可以将项目的日志记录配置与Django的默认配置合并,因此您可以决定是否要添加或替换现有配置。 如果LOGGING dictConfig中的disable_existing_loggers键设置为True(默认设置),则默认配置将被完全覆盖。另外,您可以通过将disable_existing_loggers设置为False来重新定义部分或全部记录器。
在Django 1.5之前,LOGGING设置始终会覆盖默认的Django日志记录配置。从Django 1.5开始,可以将项目的日志记录配置与Django的默认配置合并,因此您可以决定是否要添加或替换现有配置。
如果LOGGING dictConfig中的disable_existing_loggers键设置为True(默认设置),则默认配置将被完全覆盖。另外,您可以通过将disable_existing_loggers设置为False来重新定义部分或全部记录器。
在django/utils/log.py:
django/utils/log.py
# 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', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', }, 'null': { 'class': 'django.utils.log.NullHandler', }, 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' } }, 'loggers': { 'django': { 'handlers': ['console'], }, 'django.request': { 'handlers': ['mail_admins'], 'level': 'ERROR', 'propagate': False, }, 'py.warnings': { 'handlers': ['console'], }, } }
所以默认django.request有propagate = False。但是就我而言'disable_existing_loggers': True。
propagate = False
'disable_existing_loggers': True
解决方案是防止Django配置日志记录并自行处理。幸运的是,这很容易。在settings.py:
settings.py
LOGGING_CONFIG = None LOGGING = {...} # whatever you want, as you already have import logging.config logging.config.dictConfig(LOGGING)
2015年3月更新 :Django已澄清其文档:
如果将LOGGING dictConfig中的disable_existing_loggers键设置为True,则将禁用默认配置中的所有记录器。禁用的记录器与已删除的记录器不同;记录器仍将存在,但会静默丢弃记录到该记录器的所有内容,甚至不会将条目传播到父记录器。因此,使用’disable_existing_loggers’应该非常小心。这可能不是您想要的。相反,您可以将disable_existing_loggers设置为False,然后重新定义一些或所有默认记录器。或者您可以将LOGGING_CONFIG设置为None并自己处理日志记录配置。
对于后代和细节: 解释?我认为大多数混淆都归因于Django对的拙劣解释disable_existing_loggers,即解释为True时,“默认配置被完全覆盖”。在您自己的答案中,您发现这是不正确的;发生的事情是Django已配置的现有记录器被 禁用 而不是替换。
disable_existing_loggers
Python日志记录文档对其进行了更好的解释(添加了重点):
disable_existing_loggers –如果指定为False,则在进行此调用时存在的记录器将被保留。默认值为True,因为它以向后兼容的方式启用了旧的行为。此行为是要 禁用 所有现有记录器,除非它们或它们的祖先在记录配置中明确命名。
根据Django文档,我们认为“用我自己的LOGGING配置覆盖默认值,任何我未指定的内容都会 冒出来 ”。我也超出了这个期望。我们期望的行为与 replace_existing_loggers相似 (这不是真品)。取而代之的是,Django记录器被 关闭, 没有 冒泡 。
首先,我们需要阻止这些Django记录器的设置,在这里Django文档更加有用:
如果您根本不想配置日志记录(或者想使用自己的方法手动配置日志记录),可以将LOGGING_CONFIG设置为None。这将禁用配置过程。 注意:将LOGGING_CONFIG设置为None仅表示禁用配置过程,而不记录自身。如果禁用配置过程,则Django仍会进行日志记录调用,而回退到已定义的默认日志记录行为。
如果您根本不想配置日志记录(或者想使用自己的方法手动配置日志记录),可以将LOGGING_CONFIG设置为None。这将禁用配置过程。
注意:将LOGGING_CONFIG设置为None仅表示禁用配置过程,而不记录自身。如果禁用配置过程,则Django仍会进行日志记录调用,而回退到已定义的默认日志记录行为。
Django仍将使用其记录器,但是由于配置未对其进行处理(然后禁用),因此这些记录器将按预期方式冒泡。使用上述设置的简单测试:
manage.py shell >>> import logging >>> logging.warning('root logger') WARNING 2014-03-11 13:35:08,832 root root logger >>> l = logging.getLogger('django.request') >>> l.warning('request logger') WARNING 2014-03-11 13:38:22,000 django.request request logger >>> l.propagate, l.disabled (1, 0)