如何在Python中临时更改日志消息格式?

34 投票
5 回答
32753 浏览
提问于 2025-04-16 22:22

在Python中,最简单的方法是什么,可以临时改变日志信息的格式(通过日志模块)?

我们的目标是有一个标准的消息格式,同时能够临时添加一些关于正在读取的文件的信息(比如文件名);当不再读取文件时,消息格式应该恢复到默认状态。生成这些消息的程序并不知道正在读取哪个文件,所以如果它的消息能自动包含相关的文件名就好了(比如错误信息会变成:“错误 在读取文件 ***: …”而不是“错误: …”)。

5 个回答

6

我不太推荐这样做;不过你可以假设第一个根处理程序有问题,然后直接修改它。

import logging
ROOT_LOGGER = logging.getLogger()
ROOT_LOGGER.handlers[0].setFormatter(logging.Formatter(
    '%(asctime)s:%(levelname)s:%(name)s:%(message)s\n'
))

如果你在一个有管理日志的系统中,这样做可能会给自己带来麻烦;最好还是能准确找到你想修改的处理程序,然后去修改它。

不过如果它能正常工作,谁会在乎它有多糟糕呢?

9

有几种方法可以做到这一点。除了已经记录的方式(比如在记录日志时使用extra参数、LoggerAdapterFilter),还有一种方法是指定一个自定义的格式化类,你可以让这个类知道正在处理哪个文件。例如:

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()来配置你的日志记录(在logutils项目中可以找到适用于旧版本Python的相关内容)。

23

这里有一个简单的解决方案,可以从 Vinay Sajip教程 中推导出来;它基本上是通过 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 可以动态设置为正在处理的文件,这正是问题中所要求的)。

撰写回答