使用自定义格式化器类与Python的logging.config模块
我有一个日志记录的类,它在代码中作为格式化器使用时效果很好。这个类是基于一个已有的格式化器扩展的,它在要记录的消息前面加上一个字符串,以帮助显示这个消息的重要性。(我不只是使用%(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 个回答
因为你在使用Python 2.7,所以可以用基于字典的配置方法,使用dictConfig()
。这个方法比fileConfig()
更灵活,因为它允许你使用任意的可调用对象来返回,比如处理器、格式化器或过滤器。
如果你必须使用fileConfig()
,那么你需要构建一个可调用的函数,这个函数接受format
和datefmt
的字符串值,并返回你自己类的一个实例。这里的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试过,效果很好 :-)