Python日志记录:调试消息记录到stderr,即使处理程序级别为INFO

问题描述 投票:1回答:1

虽然在现有项目上修改代码,但是我发现即使这些日志的处理程序级别设置为INFO级别,调试消息也正在输出到stderr,因此我不希望有任何调试消息。该行为的原因似乎是导入正在使用logging.debug(),在此之后调用它更改了将消息输出到控制台的方式。

我将问题简化为下面的代码示例,以帮助您了解为何记录这些调试级别消息的原因:

import logging
import sys

# get root logger singleton
root_logger = logging.getLogger()

# create my own logger object
test_logger = logging.getLogger("test_logger")
test_logger.setLevel(logging.DEBUG)

# add handler to my logger
sh = logging.StreamHandler(sys.stdout)
sh.setLevel(logging.INFO)
test_logger.addHandler(sh)

test_logger.info("Info message from test_logger")

test_logger.debug("Debug message before logging.debug")
print("test_logger handlers before: " + str(test_logger.handlers))
print("test_logger level before: " + str(test_logger.getEffectiveLevel()))
print("Root before: " + str(root_logger.handlers) + " level: "+ str(root_logger.getEffectiveLevel()))

# This call causes the debug messages after it to go to stderr
# Also, it results in the root logger object having a handler added to it 
logging.debug("Debug message from logging")

test_logger.debug("Debug message after logging.debug")
print("test_logger handlers after: " + str(test_logger.handlers))
print("test_logger logging level after: " + str(test_logger.getEffectiveLevel()))
print("Root after: " + str(root_logger.handlers) + " level: " + str(root_logger.getEffectiveLevel()))

上面的代码具有以下输出:

DEBUG:test_logger:Debug message after logging.debug
Info message from test_logger
test_logger handlers before: [<StreamHandler <stdout> (INFO)>]
test_logger level before: 10
Root before: [] level: 30
test_logger handlers after: [<StreamHandler <stdout> (INFO)>]
test_logger logging level after: 10
Root after: [<StreamHandler <stderr> (NOTSET)>] level: 30

对我来说,为什么自从调用logging.debug()以来就将StreamHandler添加到根记录器,而在根目录上没有处理程序,它将添加一个。 https://docs.python.org/3.5/howto/logging.html#logging-flow处的图似乎也很相关,因为它显示了来自具有父级的记录器的消息会转到父级,而根记录器应是test_logger的父级。

添加以下代码行将阻止在stderr中生成调试消息,因此似乎问题与该消息传播给其祖先有关。但是,我不确定这是合适的解决方案还是解决方法。

test_logger.propagate = False

https://docs.python.org/3/library/logging.html#logging.Logger.propagate上的文档对此进行了解释:

消息直接传递到祖先记录器的处理程序-所讨论的祖先记录器的级别或过滤器都不会考虑。

对我来说,这意味着根记录器应该收到此消息,但是打印的调试消息将记录器显示为test_logger DEBUG:test_logger:Debug message after logging.debug,因此它似乎不是来自根记录器。根记录器也具有默认的记录级别.WARN(30),我的理解是,如果记录器的处理程序处理调试消息,则仅当记录器上的日志级别等于或低于消息级别时才打印该记录?

有人能够解释这里发生了什么,如果我可能缺少一些强制性的步骤?例如,在此代码中,我应该初始化根记录程序,以免添加默认处理程序,即使我创建了命名记录程序并计划使用该记录程序也可以吗?

虽然在现有项目上修改代码,但是我发现即使这些日志的处理程序级别设置为INFO级别,调试消息也正在输出到stderr,所以我不希望有任何调试...

python logging
1个回答
0
投票
似乎您在误读文档。传播消息时,它们不会传播到父记录器。它们直接传播到父级的处理程序。实际情况并非如此,但可以这样考虑:传播将父级的处理程序添加到子级记录器。由于您的test_logger的级别为DEBUG,并且直接调用logging.debug()会导致将NOTSET级别的处理程序添加到作为test_logger父级的root中,因此情况似乎test_logger拥有此处理程序,它将记录所有消息,因此发送到test_logger的所有调试消息都将由此处理程序记录。
© www.soinside.com 2019 - 2024. All rights reserved.