Python 2.7:在两个python脚本中使用`logging`模块时,日志显示两次

Mr_*_*uet 12 python logging python-2.7

语境:

Python 2.7.

同一文件夹中的两个文件:

  • 第一:主要脚本.
  • 第二:自定义模块.

目标:

可以在logging没有任何冲突的情况下使用模块(参见下面的输出).

文件:

a.py:

import logging
from b import test_b

def test_a(logger):
    logger.debug("debug")
    logger.info("info")
    logger.warning("warning")
    logger.error("error")

if __name__ == "__main__":
    # Custom logger.
    logger = logging.getLogger("test")

    formatter = logging.Formatter('[%(levelname)s] %(message)s')
    handler = logging.StreamHandler()
    handler.setFormatter(formatter)

    logger.setLevel(logging.DEBUG)
    logger.addHandler(handler)

    # Test A and B.
    print "B"
    test_b()
    print "A"
    test_a(logger)
Run Code Online (Sandbox Code Playgroud)

b.py:

import logging

def test_b():
    logging.debug("debug")
    logging.info("info")
    logging.warning("warning")
    logging.error("error")
Run Code Online (Sandbox Code Playgroud)

输出:

如下所示,日志显示两次.

python a.py
B
WARNING:root:warning
ERROR:root:error
A
[DEBUG] debug
DEBUG:test:debug
[INFO] info
INFO:test:info
[WARNING] warning
WARNING:test:warning
[ERROR] error
ERROR:test:error
Run Code Online (Sandbox Code Playgroud)

有人会有解决方案吗?

编辑:未运行test_b()将导致没有日志重复和正确的日志格式(预期).

aba*_*ert 31

我不确定我理解你的情况,因为描述与输出不符......但我想我知道你的问题是什么.

正如文档解释:

注意:如果将处理程序附加到记录器及其一个或多个祖先,则它可能会多次发出相同的记录.通常,您不需要将处理程序附加到多个记录器 - 如果您只是将其附加到记录器层次结构中最高的相应记录器,那么它将看到所有后代记录器记录的所有事件,前提是它们的传播设置左侧设置为True.常见的情况是仅将处理程序附加到根记录程序,并让传播处理其余部分.

而"常见场景"通常效果很好,但我认为你需要附加一个自定义处理程序来"测试",而不会影响根记录器.

因此,如果您想在"test"上使用自定义处理程序,并且您不希望其消息也转到根处理程序,那么答案很简单:关闭其propagate标志:

logger.propagate = False
Run Code Online (Sandbox Code Playgroud)

这种情况只会在您调用时发生test_b,否则,根记录器永远不会被初始化.第一次登录到尚未配置的任何记录器时,它会有效地basicConfig()对该记录器执行操作.因此,调用logging.getLogger().info(msg)logging.info(msg)将配置根记录器.但是从儿童记录器传播不会.

我相信这是双方在日志HOWTO或食谱,地方解释的HOWTO,但在实际模块的文档,它埋在即将线程音符的中间logging.log:

注意:委托给根记录器的上述模块级函数不应该在早于2.7.1和3.2的Python版本的线程中使用,除非在线程启动之前已经将至少一个处理程序添加到根记录器中.这些便捷函数调用basicConfig()以确保至少有一个处理程序可用; ; 在早期版本的Python中,这可以(在极少数情况下)导致处理程序被多次添加到根记录器,这反过来可以导致同一事件的多个消息.

很容易看出你怎么会错过它!

  • 对不起,措辞不好,我想这个问题使我一直很困惑。但是您的解决方案就是诀窍。不敢相信我没有在文档中找到它。。。很棒的解释,谢谢:) (2认同)
  • @Mr_Pouet:我很难在文档中找到它,即使我知道我在寻找什么,所以我并不感到惊讶.但如果您还没有阅读HOWTO和食谱,那真的是值得的. (2认同)