如何在不传递记录器变量的情况下使用不同的记录器?(Python 日志记录)

Ann*_*wan 6 python logging

我有多个模块使用相同的utils.py包。如何使记录器utils.py不同而不必从调用者(即 ClassA 或 ClassB)传递记录器变量?

非常简单的示例代码如下。实际上,我在 中有很多函数和类utils.py,这就是为什么我不想将logger变量传递到utils.py.

~/test-two-loggers$ tree .

??? main.py
??? configs.py
??? ClassA.py
??? ClassB.py
??? utils.py

0 directories, 5 files
Run Code Online (Sandbox Code Playgroud)

主文件

import ClassA
import ClassB

ClassA.func()
ClassB.func()
Run Code Online (Sandbox Code Playgroud)

类A.py

import utils
import configs
import logging

def func():
    logger = logging.getLogger("classA")
    logger.info("in ClassA")
    utils.common_func(logger)  # I want to change this line!!!!
Run Code Online (Sandbox Code Playgroud)

类B.py

import utils
import configs
import logging

def func():
    logger = logging.getLogger("classB")
    logger.info("in ClassB")
    utils.common_func(logger)  # I want to change this line!!!!
Run Code Online (Sandbox Code Playgroud)

实用程序.py

def common_func(logger):  # I want to change this line!!!!
    # do a lot of things ClassA and ClassB both need to do
    logger.info("in utils - step one finished")
    # do a lot of things ClassA and ClassB both need to do
    logger.info("in utils - step two finished")
    # do a lot of things ClassA and ClassB both need to do
    logger.info("in utils - step three finished")
Run Code Online (Sandbox Code Playgroud)

配置文件

import logging.config

logging_config = {
        "version": 1, 
        "formatters": {
            "formatter_a": {
                "format": u"[A][%(levelname)s] %(module)s.%(lineno)d: %(message)s"
            },
            "formatter_b": {
                "format": u"[B][%(levelname)s] %(module)s.%(lineno)d: %(message)s"
            },
        },
        "handlers": {
            "console_a": {
                "class": "logging.StreamHandler",
                "level": "DEBUG",
                "formatter": "formatter_a",
                "stream": "ext://sys.stdout"
            },
            "console_b": {
                "class": "logging.StreamHandler",
                "level": "DEBUG",
                "formatter": "formatter_b",
                "stream": "ext://sys.stdout"
            },
        },
        "loggers": {
            "classA": {
                "level": "DEBUG",
                "handlers": ["console_a"],
                "propagate": "no"
            },
            "classB": {
                "level": "DEBUG",
                "handlers": ["console_b"],
                "propagate": "no"
            },
        },
}

logging.config.dictConfig(logging_config)
Run Code Online (Sandbox Code Playgroud)

我想要的结果:

~/test-two-loggers$ python main.py 
[A][INFO] ClassA.7: in ClassA
[A][INFO] utils.3: in utils - step one finished
[A][INFO] utils.5: in utils - step two finished
[A][INFO] utils.7: in utils - step three finished
[B][INFO] ClassB.7: in ClassB
[B][INFO] utils.3: in utils - step one finished
[B][INFO] utils.5: in utils - step two finished
[B][INFO] utils.7: in utils - step three finished
Run Code Online (Sandbox Code Playgroud)

但我想要除此之外的另一种解决方案。我不想将logger变量传递给utils.

Gus*_*rra -1

您可以更改格式化程序并使用extra关键字参数将额外的字典参数传递给日志消息。这允许您传递任何您想要假装正在调用记录器的“模块”。

因此,将您的格式化程序更改为:

"[A][%(levelname)s] %(module)s.%(lineno)d: %(message)s"
Run Code Online (Sandbox Code Playgroud)

到:

"[A][%(levelname)s] %(mymodule)s.%(lineno)d: %(message)s"
Run Code Online (Sandbox Code Playgroud)

并将您的函数称为:

logger.info("in utils", extra={'mymodule':'somemodule'})
Run Code Online (Sandbox Code Playgroud)

如果您想使用正在调用的真实'somemodule'模块,请更改为__name__.

我也虽然可能只是覆盖module(所以你必须更改你的格式化程序)的值,但logging不允许这样做,所以看来你必须更改你的格式化程序。


编辑:

为了更加清楚,您的func()inClassA.py应该更改为:

def func():
    logger = logging.getLogger("classA")
    logger.info("in ClassA", extra={'mymodule':__name__)
    logger.info("in utils", extra={'mymodule':'utils')
    utils.common_func() #call the function without passing the logger
Run Code Online (Sandbox Code Playgroud)

在你的字典中,你应该logging_config将字符串更改module为.logging_config['formatters']['formatter_a']['format']mymodule

对于B类也同样如此。显然你应该删除common_funcusing的行logger


进一步参考: