为什么未使用我配置的记录器?

时间:2019-02-07 08:24:15

标签: python logging

阅读日志记录HOWTO(https://docs.python.org/3/howto/logging.html)令我印象深刻,如果我配置了记录器,则随后可以通过logging.getLogger()从工厂请求记录器,而python将知道如何获取记录器正确的记录器(我配置的记录器),一切都会自动进行,即,我不需要在代码中传递配置的记录器实例,我可以在需要的地方索要它。相反,我观察到了一些不同的东西。

文件log_tester.py

from util.logging_custom import SetupLogger
import logging
import datetime

def test():
    logger = logging.getLogger()
    logger.debug("In test()")

def main():
    logger = SetupLogger("logger_test")
    logger.setLevel(logging.DEBUG)
    logger.info(f"now is {datetime.datetime.now()}", )
    logger.debug("In main()")
    test()


if __name__ == '__main__':
    main()

文件util/logging_custom.py

import os
import time
import logging
from logging.handlers import RotatingFileHandler

def SetupLogger(name_prefix):
    if not os.path.exists("log"):
        os.makedirs("log")

    recfmt = logging.Formatter('%(asctime)s.%(msecs)03d %(levelname)s %(message)s')

    handler = RotatingFileHandler(time.strftime(f"log/{name_prefix}.log"),maxBytes=5000000, backupCount=10)
    handler.setFormatter(recfmt)
    handler.setLevel(logging.DEBUG)

    logger = logging.getLogger(f"{name_prefix} {__name__}")
    logger.addHandler(handler)

    return logger

当我运行此代码时,只有main()中的debug语句最终出现在日志文件中。来自test()的debug语句结束了,我不确定确切的位置。

log/logger_test.log的内容:

2019-02-07 09:14:39,906.906 INFO now is 2019-02-07 09:14:39.906848
2019-02-07 09:14:39,906.906 DEBUG In main()

我期望In test()也会出现在我的日志文件中。我是否对python日志记录的工作方式做出了一些不正确的假设?如何使程序中的所有日志(具有许多类和模块)都转到相同的配置日志记录器?在main()中创建记录器实例之后,是否无需在各处传递记录器实例,是否可能?

谢谢。

2 个答案:

答案 0 :(得分:2)

getLogger函数将按其名称(单例类型)返回记录器:

  • 如果它不存在,它将创建它
  • 如果已经存在,则将其返回

然后您可以做的是:

util / logging_custom.py

def SetupLogger(logger_name, level=logging.INFO):
    if not os.path.exists("log"):
        os.makedirs("log")

    recfmt = logging.Formatter('%(asctime)s.%(msecs)03d %(levelname)s %(message)s')
    handler = RotatingFileHandler(time.strftime(f"log/{logger_name}.log"),maxBytes=5000000, backupCount=10)
    handler.setFormatter(recfmt)
    handler.setLevel(level)

    logger = logging.getLogger(logger_name)
    logger.addHandler(handler)

    # no need to return the logger, I would even advice not to do so

log_tester.py

from util.logging_custom import SetupLogger
import logging
import datetime

logger = SetupLogger("logger_test", logging.DEBUG)  # you only need to run this once, in your main script.
logger = logging.getLogger("logger_test")

def test():
    logger.debug("In test()")

def main():
    logger.info(f"now is {datetime.datetime.now()}", )
    logger.debug("In main()")
    test()

if __name__ == '__main__':
    main()

any_other.py

import logging
logger = logging.getLogger("logger_test")  # this will return the logger you already instantiate in log_tester.py

logger.info("that works!")

更新

要设置 root记录器的级别和处理方式,而不使用您设置的级别,请使用logging.getLogger()而不传递任何名称:

root_logger = logging.getLogger()
root_logger.addHandler(your_handler)
root_logger.setLevel(logging.DEBUG)

root_logger.info("hello world")

答案 1 :(得分:1)

从文档中

  

多次调用具有相同名称的getLogger()将返回一个   引用同一记录器对象。

您的假设是正确的。这里的问题是您在getLogger()中调用test()的方式。您应该传递在SetupLogger()的{​​{1}}中使用的名称,即getLogger()