用Python(通过日志记录模块)临时更改日志消息格式的最简单方法是什么?如何在Python中临时更改记录消息的格式?
目标是拥有一些标准的消息格式,同时能够临时添加有关正在读取的某个文件(如其名称)的信息;当文件不再被读取时,消息格式应该恢复为默认值。产生这些消息的程序是而不是意识到正在读取什么文件,所以如果它的消息自动包含相关的文件名(如果错误消息是:“ERROR ,同时读取文件 ***: ...“而不是”错误:...“)。
用Python(通过日志记录模块)临时更改日志消息格式的最简单方法是什么?如何在Python中临时更改记录消息的格式?
目标是拥有一些标准的消息格式,同时能够临时添加有关正在读取的某个文件(如其名称)的信息;当文件不再被读取时,消息格式应该恢复为默认值。产生这些消息的程序是而不是意识到正在读取什么文件,所以如果它的消息自动包含相关的文件名(如果错误消息是:“ERROR ,同时读取文件 ***: ...“而不是”错误:...“)。
这是一个简单的解决方案,可以从Vinay Sajip自己的HOWTO推导出来;它基本上更新日志记录格式化与setFormatter()
:
import logging
logger = logging.getLogger() # Logger
logger_handler = logging.StreamHandler() # Handler for the logger
logger.addHandler(logger_handler)
# First, generic formatter:
logger_handler.setFormatter(logging.Formatter('%(message)s'))
logger.error('error message') # Test
# New formatter for the handler:
logger_handler.setFormatter(logging.Formatter('PROCESSING FILE xxx - %(message)s'))
logger.error('error message') # Test
此正确地产生:
error message
PROCESSING FILE xxx - error message
(其中xxx
可以动态地设置到正在处理的文件,如在问题问)。
不知道为什么这被认为是解决方案。处理程序确定日志目标,格式化程序确定日志格式;这两个可以被认为是正交的。如果我想临时更改特定记录器的日志格式(例如记录器'package1.module2')以添加一些特定于模块的上下文信息,我希望为记录器的所有处理程序执行此操作。枚举所有其他记录器可能使用的处理程序,临时更改格式,然后将其更改回来以免打破其他记录器,这不是一个解决方案。 – dtheodor
这确实是在这种更极端的情况下必须要做的事情,在这种情况下,人们几乎无法控制处理程序在记录器中的分布情况。这是一个具体而不幸的案例。现在,这样做仍然可以按照这个答案完成,所以对我来说看起来很好(免责声明:我都问过这个问题并提供了这个答案)。有趣的是在上面的评论中针对案例大纲提出具体问题,并附上相应的具体答案;这属于另一个StackOverflow条目。 – EOL
有几种方法。除了already documented ones(extra
参数记录调用,LoggerAdapter
,Filter
)之外,另一种方法是指定一个自定义格式类,其实例可以随时了解正在处理的文件。例如:
class FileProcessingFormatter(logging.Formatter):
def __init__(self, fmt, datefmt=None, current_file=None):
super(FileProcessingFormatter, self).__init__(fmt, datefmt)
self.orig_fmt = fmt
self.current_file = current_file
def format(self, record):
if self.current_file is None:
self._fmt = self.orig_fmt.replace('__FILE_PLACEHOLDER__', '')
else:
self._fmt = self.orig_fmt.replace('__FILE_PLACEHOLDER__',
' while processing %r' % self.current_file)
return super(FileProcessingFormatter, self).format(record)
实例化格式化......
f = FileProcessingFormatter('%(levelname)s__FILE_PLACEHOLDER__ %(message)s')
for h in relevant_handlers:
h.setFormatter(f)
进程文件...
f.current_file = fn
process_file(fn)
f.current_file = None
这是非常简单的 - 例如,而不是在线程环境,如果使用文件处理由不同的线程同时完成。
更新:尽管根记录器的处理程序可通过logging.getLogger().handlers
访问,但这是可能更改的实现细节。由于您的要求不是那么基本,您可以使用dictConfig()
来配置您的日志记录(可通过针对旧版Python的logutils项目进行配置)。
我更新了我的答案。 –