我正在尝试编写一个自定义的
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
这已经在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