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

标签 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”没有记录在根记录器上(消息级别是信息,根接受调试级别),为什么“消息 3”记录在“pkg”记录器上(消息级别是信息,pkg 接受警告)?

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

PS:如果我切换处理程序和记录器级别,我从这段代码中得到的行为正是我所期望的行为:

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

最佳答案

首先使用记录器的级别,作为通过/不通过检查。这是因为一个记录器可以有多个处理程序。例如,您可以有一个 FileHandler写入磁盘 INFO 及以上和 SMTPHandler仅发送电子邮件 CRITICAL
如果通过该检查,则日志将发送到记录器处理程序,并且当传播设置为 True 时,它还会发送到您调用的日志的父记录器的处理程序,忽略级别检查在那些记录器中。

这样,message 2根本不会打印,因为它没有通过logger的级别检查,但是message 3会打印3次,因为那个logger设置为低于 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

关于python - 为什么日志记录在 python 中以这种方式运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23058087/

相关文章:

python - 在提示符下仅键入 "python"时如何选择运行的 python 版本?

tomcat - tomcat 日志中 SLF4JBridgeHandler 中的处理程序错误

java - 即使级别设置为信息,记录器是否始终读取调试,它是否有任何重大影响?

python - 使用一些重复元素从 CSV 文件中构建和提取多维 Python 字典中的值

logging - CXF 日志拦截器

python - 类型错误 : 'Logger' object is not callable when try to use already created logger object

python - 如何在多处理进程中保护日志记录对象免受垃圾收集器的影响?

python - 导出时使用大JSON会导致内存问题

python - 在 Python 中检测 Windows 注销

python - 使用 Python 和 Google Sheets API 将工作表移动到特定位置