使用自定义格式化器类与Python的logging.config模块

8 投票
1 回答
15383 浏览
提问于 2025-04-17 12:40

我有一个日志记录的类,它在代码中作为格式化器使用时效果很好。这个类是基于一个已有的格式化器扩展的,它在要记录的消息前面加上一个字符串,以帮助显示这个消息的重要性。(我不只是使用%(levelname)s在格式字符串中,因为我不想显示DEBUG或INFO这样的前缀。)

class PrependErrorLevelFormatter(logging.Formatter):
    def __init__(self, default):
        self._default_formatter = default
    def format(self, record):
        if record.levelno == logging.WARNING:
            record.msg = "[WARNING] " + record.msg
        elif record.levelno == logging.ERROR:
            record.msg = "[ERROR] " + record.msg
        elif record.levelno == logging.CRITICAL:
            record.msg = "[CRITICAL] " + record.msg
        return self._default_formatter.format(record)

现在我想通过一个配置文件来使用它,这个配置文件是通过logging.config.fileConfig()加载的。我尝试过这样的语法:

[formatter_PrependErrorLevelFormatter]
format=%(asctime)s  %(message)s
datefmt=%X
class=PrependErrorLevelFormatter

不幸的是,我在解析这个类时遇到了错误:

  File "C:\Python27\lib\logging\config.py", line 70, in fileConfig
    formatters = _create_formatters(cp)
  File "C:\Python27\lib\logging\config.py", line 127, in _create_formatters
    c = _resolve(class_name)
  File "C:\Python27\lib\logging\config.py", line 88, in _resolve
    found = __import__(used)
ImportError: No module named PrependErrorLevelFormatter

我尝试在类名之前加上它所在模块的名字,但还是出现了同样的错误。即使能够解析这个类,由于我需要提供额外的默认格式化器参数,它可能也无法正常工作。

我该如何使用logging.config系统来实现我想要的效果呢?

1 个回答

13

因为你在使用Python 2.7,所以可以用基于字典的配置方法,使用dictConfig()。这个方法比fileConfig()更灵活,因为它允许你使用任意的可调用对象来返回,比如处理器、格式化器或过滤器。

如果你必须使用fileConfig(),那么你需要构建一个可调用的函数,这个函数接受formatdatefmt的字符串值,并返回你自己类的一个实例。这里的class值只需要能变成一个可调用的对象,而不一定是一个实际的类。这里有一个可以工作的设置:在这个链接里,我有一个文件custfmt.py,里面包含了格式化器的定义,还有一个脚本fcfgtest.py,它通过fileConfig()来使用这个格式化器。只需把这些文件放到一个临时目录中,然后运行fcfgtest.py,你应该能看到类似这样的输出:

20:17:59 debug message
20:17:59 info message
20:17:59 [WARNING] warning message
20:17:59 [ERROR] error message
20:17:59 [CRITICAL] critical message

看起来这正是你需要的。

注意,你可以使用另一种设计来实现你的格式化器,这样也能完成同样的工作:

class AltCustomFormatter(logging.Formatter):
    def format(self, record):
        if record.levelno in (logging.WARNING,
                              logging.ERROR,
                              logging.CRITICAL):
            record.msg = '[%s] %s' % (record.levelname, record.msg)
        return super(AltCustomFormatter , self).format(record)

使用这个方法,你不需要一个单独的工厂函数,所以你可以直接使用

class=custfmt.AltCustomFormatter

而不是

class=custfmt.factory

这样就可以了——我刚刚在测试时用Python 2.7.1试过,效果很好 :-)

撰写回答