从不同的脚本登录到同一文件?

时间:2019-01-15 05:13:41

标签: python logging module

我有一个叫main.py的顶级core.py。我希望两个文件都写入相同的时间。我的代码:

文件main.py

import core

import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
logger.addHandler(ch)

fh = logging.FileHandler("main.log",mode="w")
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)

logger.info("I am in main.")

core.myclass()

文件core.py

import logging
class myclass():
    def __init__(self):
        logger = logging.getLogger("main")
        print(logger)
        logger.debug("Debug message")
        logger.warn("Warning message")

据我了解, logger = logging.getLogger("main")应该获得原始日志的引用,因此无需再次设置。但是,来自core.py的消息处于默认警告级别,不会写入文件。

是否可以在不同模块之间维护相同的设置?

2 个答案:

答案 0 :(得分:1)

最好的方法是创建一个基本的日志记录模块,并将其导入并在所有文件中使用。

示例如下

class BaseLogging():

    def __init__(self):
        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.INFO)
        self.formatter = logging.Formatter('%(asctime)s:%(mod_name)s,%(levelname)s:%(message)s')
        self.file_handler = logging.FileHandler('debug.log')
        self.file_handler.setFormatter(self.formatter)
        self.logger.addHandler(self.file_handler)

    def debug(self, msg):
        module_stack = inspect.stack()[1][1]
        mod_name = inspect.getmodulename(module_stack)
        d = {'mod_name': mod_name}
        self.logger.debug(msg, extra=d)
  

我在这里只显示了调试代码,但是类似地,您可以   编写警告,关键和全部警告的方法。

然后只需将该BaseLogging导入到所需的模块中,就可以轻松记录消息。记录器会将所有日志消息写到一个文件中,并指出写入日志条目的模块。

答案 1 :(得分:1)

我不打算发布自己的答案,但是我不同意其他答案,所以我们开始:)

我看不到创建基本日志模块的意义。已经有一个叫logging,在我看来它做得很好。

另一个答案中概述的解决方案有一个缺陷:尽管它确实创建了一个记录器*,但是它还创建了多个处理程序和格式化程序,每次实例化BaseLogging时都设置一个。

* 因为__name__BaseLogging中没有更改,无论您从何处导入。这也是打破%(module)s属性并要求inspect进行“ hacks”以获取调用方模块名称的原因

core.py

from base_logging import BaseLogging

class myclass():
    def __init__(self):
        # just instantiate the class, don't even call any method on it
        blogger = BaseLogging()

main.py

from base_logging import BaseLogging
import core

blog = BaseLogging() # fist instance, one handler and one formatter attached to the logger
core.myclass() # creates the second instance during instantiation
blog.debug("Can I get a sibling, mommy?")

注意:在base_logging.BaseLogging中,我向初始化器添加了self.logger.setLevel(logging.DEBUG),以使这项工作有效,而无需实现WARNING及更高版本的方法。

如果您现在运行main.py,则日志将如下所示:

2019-01-16 11:54:23,305:main,DEBUG:Can I get a sibling, mommy?
2019-01-16 11:54:23,305:main,DEBUG:Can I get a sibling, mommy?

logging已在全局名称空间中工作。您一次创建和配置的记录器可从过程中的任何位置访问。您只需要知道要问哪个。您可以随时随地查看logging.Logger.manager.loggerDict,以查看当前已知的记录器。
(注意:它可能不应该被认为是正式API的一部分,因此,我宁愿不使用它生产,但我发现它在开发和调试中很有用)

main.py

[your main.py up to this point]
print("before:", logging.Logger.manager.loggerDict)
#logger.info("I am in main.")

core.myclass()
print("after:", logging.Logger.manager.loggerDict)

core.py

class myclass():
    def __init__(self):
        logger = logging.getLogger("main")
        print("in myclass", logging.Logger.manager.loggerDict)
        #logger.debug("Debug message")
        #logger.warn("Warning message")

输出:

before: {'__main__': <Logger __main__ (DEBUG)>}
in myclass {'__main__': <Logger __main__ (DEBUG)>, 'main': <Logger main (WARNING)>}
after: {'__main__': <Logger __main__ (DEBUG)>, 'main': <Logger main (WARNING)>}

因此,您需要确保的是,如果要获得相同的记录器,请使用相同的名称,即在这种情况下使用logger = logging.getLogger("__main__"),或者更好的是,使用专用名称正确从一开始就避免__name__的值基于脚本是执行还是导入而具有不同值的问题。

main.py

[...]
logger = logging.getLogger("main_logger")
[...]

core.py

# in myclass.__init__()
[...]
logger = logging.getLogger("main_logger")
[...]

=> main.log

I am in main.
Debug message
Warning message