如何在Python中临时更改已记录消息的格式?

Eri*_*got 13 python logging error-logging

在Python中(通过日志记录模块)临时更改日志消息格式的最简单方法是什么?

目标是拥有一些标准的消息格式,同时能够临时添加有关正在读取的文件的信息(如其名称); 当文件不再被读取时,消息格式应恢复为默认值.产生消息的程序知道正在读取什么文件,所以如果它的消息自动包含相关文件名会很好(错误信息将是:" 读取文件时出错:***:..."而不是"错误:......").

Eri*_*got 10

这是一个简单的解决方案,可以从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
Run Code Online (Sandbox Code Playgroud)

这正确地产生:

error message
PROCESSING FILE xxx - error message
Run Code Online (Sandbox Code Playgroud)

(xxx可以动态设置到正在处理的文件,如问题中所要求的那样).

  • 不知道为什么这被认为是一个解决方案。处理程序确定日志目的地,格式化程序确定日志格式;这两个可以被认为是正交的。如果我想临时更改特定记录器(例如记录器“package1.module2”)的日志格式以添加一些特定于模块的上下文信息,我希望对*所有*记录器的处理程序执行此操作。枚举可能被所有其他记录器使用的所有处理程序,暂时更改格式,然后将其更改回来以免破坏其他记录器并不是解决方案。 (3认同)

Vin*_*jip 8

有几种方法.除了已经记录的那些(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)
Run Code Online (Sandbox Code Playgroud)

实例化格式化程序......

f = FileProcessingFormatter('%(levelname)s__FILE_PLACEHOLDER__ %(message)s')
for h in relevant_handlers:
    h.setFormatter(f)
Run Code Online (Sandbox Code Playgroud)

处理文件......

f.current_file = fn
process_file(fn)
f.current_file = None
Run Code Online (Sandbox Code Playgroud)

这非常简单 - 例如,如果文件处理由不同的线程同时完成,则不适用于线程环境.

更新:虽然可以通过访问根记录器的处理程序logging.getLogger().handlers,但这是一个可能会更改的实现细节.由于您的要求不是那么基本,您可以使用dictConfig()配置日志记录(可通过logutils项目获得旧版本的Python).


Tho*_*ner 6

我不推荐这样做;但你可以说假设第一个根处理程序是搞砸的并直接修改它

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

如果您处于任何具有托管日志记录的系统中;这可能会让你的脚受伤;最好能够确定对要修改的处理程序的准确引用并对其进行修改;

但没人关心如果它工作正常的话它有多坏?/s