Django中Python日志的优雅设置
我还没有找到一种方法来设置Django的Python日志记录,我很满意。我的要求是相当简单:Django中Python日志的优雅设置
- 为不同的事件不同的日志处理 - 也就是说,我希望能够登录到不同的文件
- 到记录器轻松访问我的模块。该模块应该能够毫不费力地找到它的记录器。
- 应该很容易适用于命令行模块。系统的一部分是独立的命令行或守护进程。记录应该很容易与这些模块一起使用。
我目前的设置是在我登录的每个模块中使用logging.conf
文件和安装日志记录。它感觉不对。
你有喜欢的日志记录设置吗?请详细说明:您如何设置配置(您是使用logging.conf
还是将其设置为代码),您何时/何时启动记录器,以及如何在模块中访问它们等。
迄今为止发现的最佳方式是在settings.py中初始化日志记录设置 - 无处不在。您可以使用配置文件,也可以通过编程方式逐步执行 - 这取决于您的要求。关键是我通常将我想要的处理程序添加到根记录器,使用级别并有时记录。筛选器将我想要的事件添加到适当的文件,控制台,系统日志等。您当然可以将处理程序添加到任何其他记录器根据我的经验,通常不需要这样做。
在每个模块中,我定义使用
logger = logging.getLogger(__name__)
,并用这些模块中记录事件记录器(如果我想区分进一步)使用记录仪是创造了记录器的孩子以上。
如果我的应用程序是要在不settings.py中配置日志记录的网站可能被使用,我某处定义NullHandler如下:
#someutils.py
class NullHandler(logging.Handler):
def emit(self, record):
pass
null_handler = NullHandler()
,并确保它的一个实例是添加到我的应用程序中使用日志记录模块中创建的所有记录器。 (注:NullHandler已经在日志包为Python 3.1,并会在Python 2.7)。所以:
logger = logging.getLogger(__name__)
logger.addHandler(someutils.null_handler)
这样做是为了确保你的模块在不配置日志网站发挥很好在settings.py中,并且你不会感到讨厌“记录器XYZ没有找到处理程序”消息(这是关于可能错误配置的日志记录的警告)。
这样做,这样满足你们所要求的:
- 您可以设置为不同的事件不同的日志处理程序,因为你目前做的。
- 轻松访问模块中的记录器 - 使用
getLogger(__name__)
。 - 很容易适用于命令行模块 - 它们也导入
settings.py
。
更新:注意,从1.3版本,Django的现在合并support for logging。
这不会要求每个模块都有一个在配置中定义的处理程序(您不能使用foo的处理程序来处理foo.bar)?请参阅我们多年前在http://groups.google.com/group/comp.lang.python/browse_thread/thread/6a199393bcee6c1b/2ddf482a44bc4bb1 – 2010-10-04 00:04:22
@andrew cooke上的对话:您*可以*使用'foo'的处理程序来处理处理记录到'foo.bar'的事件。回覆。该线程 - fileConfig和dictConfig现在都有选项来防止禁用旧的记录器。看到这个问题:http://bugs.python.org/issue3136,在你的问题http://bugs.python.org/issue2697发布几个月后 - 无论如何,它已被整理出2008年6月以来。 – 2010-10-04 12:01:16
wouldn 'logger = someutils.getLogger(__ name __)'是更好的方法吗?其中'someutils.getLogger'从已经添加了null_handler的'logging.getLogger'返回记录器? – 7yl4r 2016-10-11 05:12:35
我们使用logging.ini
文件初始化登录顶级urls.py
中的日志。
logging.ini
的位置在settings.py
中提供,但仅此而已。
每个模块,然后做
logger = logging.getLogger(__name__)
为了区分测试,开发和生产的情况下,我们有不同的logging.ini文件。大多数情况下,我们有一个“控制台日志”,只有错误才会发送到stderr。我们有一个“应用程序日志”,它使用转到日志目录的常规滚动日志文件。
我知道这已经是一个解决的答案,但根据django> = 1.3,有一个新的日志记录设置。
从旧到新不是自动的,所以我想我会在这里写下来。
当然结账the django doc一些更多。
这是基本的conf,默认情况下使用Django管理员的createProject V1.3创建 - 里程可能与最新的Django版本更改:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
}
}
}
这种结构是基于标准Python logging dictConfig,这决定了以下块:
-
formatters
- 对应的值将是一个字典,其中每个键是一个格式化器ID和每个值是描述如何配置对应格式化实例的字典。 -
filters
- 相应的值将是一个字典,其中每个键是一个过滤器ID,每个值是一个字典,描述如何配置相应的过滤器实例。 -
handlers
- 相应的值将是一个字典,其中每个键是一个处理程序ID,每个值是一个字典,描述如何配置相应的Handler实例。每个处理器具有以下键:-
class
(强制性)。这是处理程序类的完全限定名称。 -
level
(可选)。处理程序的级别。 -
formatter
(可选)。此处理程序的格式化程序的ID。 -
filters
(可选)。此处理程序的过滤器的id列表。
-
我通常至少这一点:
- 添加.log文件
- 配置我的应用程序写入此日志
换算成:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'handlers': {
'null': {
'level':'DEBUG',
'class':'django.utils.log.NullHandler',
},
'console':{
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
# I always add this handler to facilitate separating loggings
'log_file':{
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(VAR_ROOT, 'logs/django.log'),
'maxBytes': '16777216', # 16megabytes
'formatter': 'verbose'
},
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
'apps': { # I keep all my of apps under 'apps' folder, but you can also add them one by one, and this depends on how your virtualenv/paths are set
'handlers': ['log_file'],
'level': 'INFO',
'propagate': True,
},
},
# you can also shortcut 'loggers' and just configure logging for EVERYTHING at once
'root': {
'handlers': ['console', 'mail_admins'],
'level': 'INFO'
},
}
编辑
见request exceptions are now always logged和Ticket #16288:
我更新了上述样品的conf明确包括mail_admins正确的过滤器,这样,在默认情况下,电子邮件不会在调试是真发。
你应该添加过滤器:
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
,并将其应用到mail_admins处理程序:
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
}
否则django.core.handers.base.handle_uncaught_exception
不传递错误,如果设置了 'django.request' 记录仪.DEBUG是真的。
如果你不这样做在Django 1.5,你会得到一个
DeprecationWarning:你有没有关于“mail_admins”日志处理程序定义的过滤器:添加隐调试假只能过滤
但事情仍然会正常工作在Django 1.4和Django 1.5中。
**结束编辑**
那的conf强烈由Django的文档样本的conf的启发,但添加日志文件的一部分。
我也经常做到以下几点:
LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO'
...
'level': LOG_LEVEL
...
然后在我的Python代码,我总是在增加的情况下没有日志记录的conf是任何定义的NullHandler。这避免了没有指定Handler的警告。对于库特别有用的不一定只调用在Django(ref)
import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
class NullHandler(logging.Handler): #exists in python 3.1
def emit(self, record):
pass
nullhandler = logger.addHandler(NullHandler())
# here you can also add some local logger should you want: to stdout with streamhandler, or to a local file...
[...]
logger.warning('etc.etc.')
希望这有助于!
您可能会发现以下屏幕视频有用 - http://ericholscher.com/blog/2008/aug/29/screencast-2-logging-fun-and-profit/。另外,Simon Willison提出了更好的登录Django的支持(参见http://simonwillison.net/2009/Sep/28/ponies/)。 – 2009-10-21 05:20:00
@Dominic Rodger - 您可以在Django中灵活地记录应用程序,Simon的建议主要是为了便于在Django内部进行日志记录。Python正在开展工作,将基于字典的配置添加到Python日志记录中,Django可能从中受益。 – 2009-10-21 06:05:43