【问题标题】:Per-object logging across multiple modules in Python在 Python 中跨多个模块的每个对象日志记录
【发布时间】:2019-09-05 21:19:03
【问题描述】:

我有一个 Python 代码,它实现了一个用于处理独立数据集的类。对于每个数据集,我从类中实例化一个对象,该对象处理数据集。我想实现一个日志功能,在控制台和与每个数据集一起存储的日志文件中显示日志消息。

我在模块级别实现了一个根记录器,并在创建每个对象时实现了一个带有 FileHandler 的特定记录器。它可以记录课堂内部发生的一些信息,但我也在使用另一个工具箱模块,那里发生的事情只记录在控制台中,而不是记录在日志文件中。

为了说明问题,我实现了一个演示模块:

├──log
│  ├── __init__.py
│  ├── my_object.py
│  ├── toolbox.py

__init__.py的内容:

import logging

logging.basicConfig(format='%(name)12s - %(levelname)5s - %(message)s')
_log = logging.getLogger(__name__)
_log.setLevel(logging.DEBUG)

my_object.py的内容:

import logging
from . import toolbox

class MyObject():
    def __init__(self, name):
        self._name = name

        # configure logging
        logger = logging.getLogger(name)
        logger.setLevel(logging.DEBUG)
        if logger.hasHandlers():
            for hdlr in logger.handlers:
                logger.removeHandler(hdlr)

        handler = logging.FileHandler('/home/user/Desktop/test/{}.log'.format(name), mode='w', encoding='utf-8')
        formatter = logging.Formatter('%(name)12s - %(levelname)5s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)

        self._logger = logger


    def do_something(self):
        self._logger.info('{} is doing something'.format(self._name))

        toolbox.use_tool(self._name)

toolbox.py的内容:

import logging

_log = logging.getLogger(__name__)


def use_tool(name):
    _log.info('Using some tool for {}'.format(name))

然后,我运行这个:

import log
from log.my_object import MyObject

obj = MyObject('object1')
obj.do_something()

这是我在控制台中得到的:

     object1 -  INFO - object1 is doing something
 log.toolbox -  INFO - Using some tool for object1

这是我在/home/user/Desktop/test/object1.log 文件中得到的内容:

     object1 -  INFO - object1 is doing something

如何让 log.toolbox 也显示在 object1.log 文件中?

【问题讨论】:

    标签: python logging


    【解决方案1】:

    罪魁祸首在于你如何调用getLogger 函数。你有两次这样做:

    1. logger = logging.getLogger(name)my_object.py
    2. _log = logging.getLogger(__name__)toolbox.py

    如果您比较这些调用返回的对象,它们是 2 个单独的对象(您可以通过print(id(obj)) 打印它们的地址)。这就是为什么logger 从不调用工具箱内的行的原因 - 那里有一个不同的记录器 (_log)!

    要修复您的错误,只需为您的记录器指定相同的名称 - 例如“global”:

    1. logger = logging.getLogger("global")
    2. _log = logging.getLogger("global")

    文件的输出现在如下:

    global -  INFO - object1 is doing something
    global -  INFO - Using some tool for object1
    

    在您的具体示例中,您可以将toolbox.py 中的代码调整为:

    import logging
    
    
    def use_tool(name):
        _log = logging.getLogger(name)
        _log.info('Using some tool for {}'.format(name))
    

    并将记录器保留在my_object.py 中(logger = logging.getLogger(name))。如果您随后在main.py 中执行以下操作:

    obj = MyObject('object1')
    obj2 = MyObject('object2')
    obj.do_something()
    obj2.do_something()
    

    你最终会得到 2 个日志文件:

    object1.log

    object1 -  INFO - object1 is doing something
    object1 -  INFO - Using some tool for object1
    

    object2.log

    object2 -  INFO - object2 is doing something
    object2 -  INFO - Using some tool for object2
    

    【讨论】:

    • 如果object1object2 一起创建,并且随后调用obj1.do_something()obj2.do_something(),则此解决方案不起作用。在这种情况下,object1.log 为空,object2.log 包含两个对象的所有日志。
    • 那是因为您使用的是相同的记录器对象。您需要传递记录器 - 您应该在 use_tool 中获取/更新记录器参考。稍后我会更新我的答案以包含更强大的解决方案。
    • @Arthur 我已经按照您的确切示例使用解决方案更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-16
    • 1970-01-01
    • 2017-07-28
    • 2013-03-24
    • 2013-03-21
    • 2014-04-12
    相关资源
    最近更新 更多