【问题标题】:Python logging multiple modules logger not working outside main programPython记录多个模块记录器在主程序之外不起作用
【发布时间】:2017-07-14 20:37:20
【问题描述】:

我的目标是从多个模块进行记录,同时只在一个地方配置记录器 - 在主程序中。如this answer所示,应包含

logging.config.fileConfig('/path/to/logging.conf') 

在主程序中,然后在所有其他模块中包含

logger = logging.getLogger(__name__)

我相信这就是我在下面所做的,但我得到了意想不到的行为。

c.py

​​>
# c.py
import logging
import logging.config
import d

logging.config.fileConfig("logging.conf")
logger = logging.getLogger(__name__)

logger.warning('logging from c')
d.foo()

d.py

​​>
# d.py
import logging

logger = logging.getLogger(__name__)

# this will print when d is imported
logger.warning('logging from d on import')

def foo():
    # this does not print
    logger.warning("logging from d on call foo()")

输出

$ python c.py
logging from d on import
logging from c

我期望的是,当d.foo()c.py 中执行时,会从d 记录一条消息,但是,情况并非如此。这很令人困惑,因为当从 d 中的模块级别调用记录器时,它会将消息记录到控制台,但从 foo() 内部调用时则不会。

配置文件

[loggers]
keys=root

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(message)s
datefmt=

进一步分析

所以我注意到如果我删除该行

logging.config.fileConfig("logging.conf")

来自c.py,然后从d.foo() 记录按预期工作。所以要么是配置文件有问题,要么是因为我提供一个配置文件,导致d.py中的记录器搞砸了。

问题

  1. 为什么从模块级别调用时会从d 记录消息,而不是从d.foo() 内部记录?
  2. 而我怎样才能实现从多个模块进行日志记录的目标,而只在主程序中配置日志记录呢?

【问题讨论】:

    标签: python logging


    【解决方案1】:

    我认为 d 的导入是在记录器的配置之前发生的,所以这样做可能会得到你想要的?

    # c.py
    import logging
    import logging.config
    
    logging.config.fileConfig("logging.conf")
    logger = logging.getLogger(__name__)
    
    import d
    
    
    logger.warning('logging from c')
    d.foo()
    

    它给了我这些结果

    logging from d on import
    logging from c
    logging from d on call foo()
    

    编辑

    查看代码可能更有意义的是,拥有一个单独的文件来设置日志记录,然后将它导入到主文件中,然后其他模块就会拥有它,并且看起来不那么混乱。所以也许有一个像这样的logsetup.py

    import logging
    import logging.config
    
    logging.config.fileConfig("logging.conf")
    

    然后 c.py 看起来像这样,仍然给出相同的结果

    # c.py
    import logsetup
    import logging
    import d
    
    logger = logging.getLogger(__name__)
    
    logger.warning('logging from c')
    d.foo()
    

    【讨论】:

    • 我明白了。我猜当我在配置记录器之前import d 时,d 中的记录器没有处理程序,所以它不会在任何地方打印。但是,当我根本不包含声明 logging.config.fileConfig("logging.conf") 时,我希望两个记录器都不会打印任何东西(事实并非如此,它们都打印到控制台)。但我想在那种情况下,两个记录器最终都会有一个默认的控制台处理程序......
    • 是的,我认为这是一个公平的评估。我已经更新了我的答案,以略有不同。我认为最好有一个单独的文件来设置记录器。类似于django或flask之类的框架可能有一个settings.py文件来处理这种事情,希望对您有所帮助
    • 我喜欢你的第二种方法。如果我没有从其他人那里得到另一个观点,我会在一段时间后接受这个答案。感谢您的帮助。
    • 嘿@FilipKilibarda 你最后找到其他解决方案了吗?
    • 嘿@davidejones,我已经用我认为最简单的解决方案回答了我自己的问题。
    【解决方案2】:

    问题在于

    import d
    

    先于

    logging.config.fileConfig("logging.conf")
    

    正如@davidejones 指出的那样。以下是原因:

    docs 中所述,当调用logging.config.fileConfig() 时,其默认行为是禁用任何现有的记录器。所以当import d 发生时,loggerd 中被初始化,然后当logging.config.fileConfig() 被调用时,d 中的logger 被禁用,这就是为什么我们在d.foo() 时没有看到任何日志记录的原因被调用了。

    解决方案

    logging.config.fileConfig() 接受一个参数disable_existing_loggers,默认为True。使用

    logging.config.fileConfig("logging.conf", disable_existing_loggers=False)
    

    输出变成了

    >>> python c.py
    logging from d on import
    logging from c
    logging from d on call foo()
    

    正如预期的那样。

    【讨论】:

    • 啊,太好了,我忘了禁用记录器设置,很高兴你找到了你需要的东西,这似乎是一个更好的解决方案
    • 谢谢。你绝对帮助我走上正轨。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    相关资源
    最近更新 更多