简单python日志配置中的重复输出

Too*_*ink 22 python logging

我正在设置python日志记录如下:

def setup_logging():
    loggers = (logging.getLogger("amcat"), logging.getLogger("scrapers"),logging.getLogger(__name__))
    filename = "somefile.txt"
    sys.stderr = open(filename, 'a')
    handlers = (logging.StreamHandler(sys.stdout),logging.FileHandler(filename))
    formatter = AmcatFormatter(date = True)

    for handler in handlers:
        handler.setLevel(logging.INFO)
        handler.setFormatter(formatter)

    for logger in loggers:
        logger.propagate = False
        logger.setLevel(logging.INFO)
        for handler in handlers:        
            logger.addHandler(handler)
    logging.getLogger().handlers = []
Run Code Online (Sandbox Code Playgroud)

启用了2个主要模块记录器,它们都应该记录到控制台以及文件.错误被重定向到文件(理想情况下,错误也会显示在控制台中,但我还没有实现)

之后,我检查事情是否正确:

should_work = [
    "amcat.scraping.scraper",
    "amcat.scraping.htmltools",
    "amcat.scraping.controller",
    "__main__"]

loggerdict = logging.Logger.manager.loggerDict #all loggers
for name, logger in loggerdict.items():
    if name in should_work:
        print("\nlogger: "+name)
        #iterate through parents see if effective handlers are set correctly
        print(effectivehandlers(logger))
        #test logger
        logger.info("test for {name}".format(**locals()))

def effectivehandlers(logger):
    handlers = logger.handlers
    while True:
        logger = logger.parent
        handlers.extend(logger.handlers)
        if not (logger.parent and logger.propagate):
            break
    return handlers
Run Code Online (Sandbox Code Playgroud)

控制台输出:

logger: __main__
[<logging.StreamHandler object at 0x3425d50>, <logging.FileHandler object at 0x3425dd0>]
[2013-10-24 10:27:30 daily.py:133 INFO] test for __main__

logger: amcat.scraping.controller
[<logging.StreamHandler object at 0x3425d50>, <logging.FileHandler object at 0x3425dd0>]
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.controller
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.controller

logger: amcat.scraping.htmltools
[<logging.StreamHandler object at 0x3425d50>, <logging.FileHandler object at 0x3425dd0>]
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.htmltools
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.htmltools

logger: amcat.scraping.scraper
[<logging.StreamHandler object at 0x3425d50>, <logging.FileHandler object at 0x3425dd0>]
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.scraper
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.scraper
Run Code Online (Sandbox Code Playgroud)

这是文件输出:

[2013-10-24 10:27:30 daily.py:133 INFO] test for __main__
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.controller
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.controller
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.htmltools
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.htmltools
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.scraper
[2013-10-24 10:27:30 daily.py:133 INFO] test for amcat.scraping.scraper
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,输出是双倍的,尽管已禁用传播并确保不存在重复的处理程序.这出了什么问题?

Pac*_*aco 61

基本上,当您的一个子记录器显示一条消息时,它会在层次结构中向后移动,并且父节点也会记录相同的内容.

要取消该行为,您可以添加以下内容:

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

当它击中孩子时,它不会在事后击中父母.

以下是有关此行为的一些文档.

  • 一个重要的注意事项:至少在py36上,要使.propagate = False起作用,您的记录器必须使用非空字符串来命名,因此.getLogger()将不起作用,.getLogger('')也将不起作用。它必须是.getLogger('my name')。 (3认同)
  • 即使他们有处理程序,行为仍然相同 (2认同)

Too*_*ink 10

我想出来了,谢谢Paco指出我正确的方向

事实证明,当getLogger调用时,会向其添加处理程序:

>>> print(effectivehandlers(logger))
[<logging.StreamHandler object at 0x305ad90>, <logging.FileHandler object at 0x305ae10>]
>>> logging.getLogger(name) #the same logger
<logging.Logger object at 0x7fa08fb9b2d0>
>>> print(effectivehandlers(logger))
[<logging.StreamHandler object at 0x305ad90>, <logging.FileHandler object at 0x305ae10>, <logging.StreamHandler object at 0x305ad90>, <logging.FileHandler object at 0x305ae10>]
Run Code Online (Sandbox Code Playgroud)

现在,孩子和父母都有相同的处理程序.因此重复输出.

  • 我理解为什么你有双重记录,但是你做了什么来解决你的问题?你有没有停止在整个地方调用`logging.getLogger`? (8认同)
  • 如记录所述,`logging.info()`等调用`basicConfig()`,如果没有处理程序,它将添加一个控制台处理程序.这些模块级功能并不意味着与其他配置机制混合 - 它们是最简单的用法. (2认同)