Python日志消息重复出现

167 投票
16 回答
116791 浏览
提问于 2025-04-16 21:45

我在用Python的日志功能,但不知道为什么,我的所有信息都出现了两次。

我有一个模块用来设置日志:

# BUG: It's outputting logging messages twice - not sure why - it's not the propagate setting.
def configure_logging(self, logging_file):
    self.logger = logging.getLogger("my_logger")
    self.logger.setLevel(logging.DEBUG)
    self.logger.propagate = 0
    # Format for our loglines
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    # Setup console logging
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    ch.setFormatter(formatter)
    self.logger.addHandler(ch)
    # Setup file logging as well
    fh = logging.FileHandler(LOG_FILENAME)
    fh.setLevel(logging.DEBUG)
    fh.setFormatter(formatter)
    self.logger.addHandler(fh)

之后,我调用这个方法来配置日志:

if __name__ == '__main__':
    tom = Boy()
    tom.configure_logging(LOG_FILENAME)
    tom.buy_ham()

然后在比如说,buy_ham模块里,我会调用:

self.logger.info('Successfully able to write to %s' % path)

但不知道为什么,所有的信息都出现了两次。我把其中一个流处理器注释掉了,结果还是一样。这个情况有点奇怪,我不太明白为什么会这样。我想我可能漏掉了什么明显的东西。

16 个回答

14

我还是个Python新手,不过这个方法对我来说好像有效(Python 2.7)

while logger.handlers:
     logger.handlers.pop()
111

如果你遇到这个问题,而且你确认没有重复添加处理器,那么可以看看abarnert的回答,在这里

根据文档

注意:如果你把一个处理器附加到一个记录器上,同时也附加到它的一个或多个父记录器上,那么它可能会多次输出同样的记录。一般来说,你不需要把处理器附加到多个记录器上——只要把它附加到层级中最高的那个记录器上,它就能看到所有子记录器记录的事件,只要它们的传播设置保持为True。一个常见的做法是只把处理器附加到根记录器上,然后让传播处理其余的事情。

所以,如果你想在“test”上使用一个自定义处理器,并且不想让它的消息也发送到根处理器,那么解决办法很简单:关闭它的propagate标志:

logger.propagate = False
185

你在调用 configure_logging 这个方法两次(可能是在 Boy__init__ 方法里)。虽然 getLogger 会返回同一个对象,但 addHandler 不会检查这个日志记录器是否已经添加了相似的处理器。

你可以试着追踪一下这个方法的调用,看看能不能去掉其中一个。或者在 Boy__init__ 方法里设置一个标志 logging_initialized,初始值为 False,然后修改 configure_logging 方法,让它在 logging_initializedTrue 时什么都不做,并在你初始化日志记录器后把它设置为 True

如果你的程序创建了多个 Boy 实例,你需要改变一下处理方式,使用一个全局的 configure_logging 函数来添加处理器,而 Boy.configure_logging 方法只负责初始化 self.logger 属性。

解决这个问题的另一种方法是检查你的日志记录器的处理器属性:

logger = logging.getLogger('my_logger')
if not logger.handlers:
    # create the handlers and call logger.addHandler(logging_handler)

撰写回答