如何子类化logging.Logger而不破坏logging.Formatter的插值语法中的%(文件名)

问题描述 投票:0回答:1

我正在尝试编写一个自定义的

logging.Logger
子类,该子类大部分工作正常,但是在尝试使用包含自定义格式中的插值
logging.Formatter
%(filename)
时遇到问题,它打印我的自定义的文件名子类是,而不是调用日志记录功能的代码的文件名。

我找到了许多关于 Logger 子类化的教程,但没有一个解决这对文件名插值的影响。有没有一个简单的解决方案,而不必覆盖

logging.Logger
的大部分内容?

定义我的自定义记录器的示例代码:

#-------------------------------------
# custom_logger.py
#-------------------------------------
import logging
import io
class CustomLogger(logging.Logger):
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setLevel(logging.DEBUG)
        
        # create the record format
        formatter = logging.Formatter(fmt = "%(filename)s - %(message)s")
        
        # create the handler
        self.stream = io.StringIO()
        handler = logging.StreamHandler(self.stream)
        handler.setFormatter(formatter)
        self.addHandler(handler)
    
    def debug(self, msg, *args, **kwargs):
        super().debug(msg, *args, **kwargs)
        
        # do some other stuff
        ...        
#-------------------------------------
# test.py
#-------------------------------------
from custom_logger import CustomLogger
import logging

logging.setLoggerClass(CustomLogger)
myLog = logging.getLogger("myLog")
myLog.debug("hello world")
print(myLog.stream.getvalue())

预期输出:

>>> test.py - hello world

实际产量:

>>> custom_logger.py - hello world

python logging python-logging
1个回答
0
投票

这已经在https://stackoverflow.com/a/59492341/2138700

中得到了回答

解决方案是在您的 custom_logger 代码中调用

super().debug
时使用 stacklevel 关键字参数。这是文档

的相关部分

第三个可选关键字参数是stacklevel,默认为1。如果大于1,则在计算设置的行号和函数名时会跳过相应数量的堆栈帧。 为日志记录事件创建的 LogRecord。这可以用于日志记录 helpers 以便记录函数名、文件名和行号 不是辅助函数/方法的信息,而是它的信息 来电者。

所以修改后的代码应该是

import logging
import io
class CustomLogger(logging.Logger):
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setLevel(logging.DEBUG)
        
        # create the record format
        formatter = logging.Formatter(fmt = "%(filename)s - %(message)s")
        
        # create the handler
        self.stream = io.StringIO()
        handler = logging.StreamHandler(self.stream)
        handler.setFormatter(formatter)
        self.addHandler(handler)
    
    def debug(self, msg, *args, **kwargs):
        super().debug(msg, *args, stacklevel=2, **kwargs)

现在输出将是

test.py - hello world

© www.soinside.com 2019 - 2024. All rights reserved.