为什么日志记录在python中以这种方式运行

时间:2014-04-14 10:45:42

标签: python logging

所以,最近,我在我的项目中经历了一些奇怪的行为,所以我做了一个小测试来重现行为。这是一个完整的代码:

import logging
from logging import config

config.dictConfig({
    'version': 1,
    'formatters': {
        'fmt_root':    {'format': '[ /        ] - %(levelname)s - %(name)s - %(message)s'},
        'fmt_pkg':     {'format': '[ /pkg     ] - %(levelname)s - %(name)s - %(message)s'},
        'fmt_pkg_sub': {'format': '[ /pkg/sub ] - %(levelname)s - %(name)s - %(message)s'},
    },
    'handlers': {
        'hnd_root': {
            'class': 'logging.StreamHandler',
            'level': logging.DEBUG,
            'stream': 'ext://sys.stdout',
            'formatter': 'fmt_root',
        },
        'hnd_pkg': {
            'class': 'logging.StreamHandler',
            'level': logging.DEBUG,
            'stream': 'ext://sys.stdout',
            'formatter': 'fmt_pkg',
        },
        'hnd_pkg_sub': {
            'class': 'logging.StreamHandler',
            'level': logging.DEBUG,
            'stream': 'ext://sys.stdout',
            'formatter': 'fmt_pkg_sub',
        },
    },
    'root': {
        'handlers': ['hnd_root'],
        'level': logging.DEBUG,
    },
    'loggers': {
        'pkg': {
            'handlers': ['hnd_pkg'],
            'level': logging.WARNING,
            'propagate': True,
        },
        'pkg.sub': {
            'handlers': ['hnd_pkg_sub'],
            'level': logging.INFO,
            'propagate': True,
        },
    },
})

logging.getLogger().info('message 1')
logging.getLogger('pkg').info('message 2')
logging.getLogger('pkg.sub').info('message 3')

这个小程序的输出是:

[ /        ] - INFO - root - message 1
[ /pkg/sub ] - INFO - pkg.sub - message 3
[ /pkg     ] - INFO - pkg.sub - message 3
[ /        ] - INFO - pkg.sub - message 3

现在,这不是我自然期望的输出。为什么“消息2”未记录在根记录器上(消息级别为info,root接受调试级别)以及为什么“消息3”记录在“pkg”记录器上(消息级别为info,pkg接受警告)?

我做了一些研究,我发现消息级别仅针对记录器直接发布消息进行检查 - 未检查直到根的所有父记录器级别,只检查其处理程序级别。 这对我来说似乎很奇怪。对此有解释吗?为什么它会这样?有什么用例?

PS:我期望从这段代码中获得的行为是我在切换处理程序和记录器级别时会得到的确切内容:

[ /        ] - INFO - root - message 1
[ /        ] - INFO - pkg - message 2
[ /pkg/sub ] - INFO - pkg.sub - message 3
[ /        ] - INFO - pkg.sub - message 3

1 个答案:

答案 0 :(得分:3)

首先使用记录器级别作为开始/不去检查。这是因为您可以为记录器提供多个处理程序。例如,您可以使用FileHandler写入磁盘INFO及更高版本,并SMTPHandler只发送电子邮件CRITICAL。 如果它通过了该检查,那么日志将被发送到记录器处理程序,并且当propagate设置为True时,它也会被发送到您调用的日志的父记录器的处理程序,忽略该级别检查那些记录器。

这样,message 2根本不会打印,因为它没有通过记录器的级别检查,但message 3将打印3次,因为该记录器设置为低于INFO'的级别,\pkgpgk.sub的处理程序设置为低于INFO的级别。

简而言之,记录器级别意味着"我应该将其发送给处理程序吗?"处理程序级别意味着"我应该将其写入磁盘/控制台/套接字等吗?"。

示例1。

Logger  | Logger level | Handler Level
/       | CRITICAL     | DEBUG
pkg     | CRITICAL     | DEBUG
pkg.sub | DEBUG        | DEBUG

使用logging.getLogger('pkg.sub').debug('message 3')将打印:

[ /pkg/sub ] - DEBUG - pkg.sub - message 3
[ /pkg     ] - DEBUG - pkg.sub - message 3
[ /        ] - DEBUG - pkg.sub - message 3

示例2。

Logger  | Logger level | Handler Level
/       | CRITICAL     | INFO
pkg     | CRITICAL     | DEBUG
pkg.sub | DEBUG        | DEBUG

使用logging.getLogger('pkg.sub').debug('message 3')将打印:

[ /pkg     ] - DEBUG - pkg.sub - message 3
[ /        ] - DEBUG - pkg.sub - message 3

示例3。

Logger  | Logger level | Handler Level
/       | CRITICAL     | DEBUG
pkg     | CRITICAL     | INFO
pkg.sub | DEBUG        | DEBUG

使用logging.getLogger('pkg.sub').debug('message 3')将打印:

[ /pkg/sub ] - DEBUG - pkg.sub - message 3
[ /        ] - DEBUG - pkg.sub - message 3

为了获得您想要的结果,您需要进行以下设置:

Logger  | Logger level | Handler Level
/       | DEBUG        | DEBUG
pkg     | INFO         | WARNING
pkg.sub | INFO         | DEBUG