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

时间:2011-07-27 16:25:21

标签: python logging error-logging

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

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

5 个答案:

答案 0 :(得分: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

这正确地产生:

error message
PROCESSING FILE xxx - error message

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

答案 1 :(得分:8)

有几种方法。除了记录调用的already documented onesextra参数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。)

答案 2 :(得分:0)

我不建议这样做;但是您可以假设第一个root处理程序是被搞砸并直接修改的处理程序

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

如果您在任何具有托管日志记录的系统中;这可能会让你大吃一惊;确实最好是能够确定要修改的处理程序的确切引用并进行修改;

但是没有人关心它能正常工作吗?/ s

答案 3 :(得分:0)

使用 dictConfig(),正如@Vinay Sajip 在更新中提到的那样,似乎是要走的路。这是 Python 3.8 中的一个有效实现。

import logging
from logging.config import dictConfig    
FI_PATH_CONSUMERS_LOG = "/tmp/test_log.log"
LOG_FORMAT = "%(asctime)s %(levelname)-8s [%(name)s] %(message)s"
LOG_LEVEL = "INFO"
LOG_DATEFMT = "%Y-%m-%d %H:%M:%S"

logging.basicConfig()

def create_new_format(add_stuff: str=""):
    alt_new_formats = {
        "event_format": {
            "format": LOG_FORMAT + add_stuff,
            "datefmt": LOG_DATEFMT,
        },
    }

    changed_setting = {
        "version": 1,
        "formatters": alt_new_formats,
        "handlers": {
            "to_file": {
                "class": "logging.FileHandler",
                "filename": FI_PATH_CONSUMERS_LOG,
                "formatter": "event_format",
                "level": LOG_LEVEL,
            },
        },
        "loggers": {
            "": {
                "handlers": ["to_file"],
            },
        },
        "disable_existing_loggers": False,
    }    
    return changed_setting

dictConfig(create_new_format())
logger = logging.getLogger()  # root logger
logger_2 = logging.getLogger("2")  # child logger with name "2"
msg_test = "TEST TEST TEST"


logger.info(msg_test)
logger_2.info(msg_test)

dictConfig(create_new_format("...adding some stuff"))
logger.info(msg_test)
logger_2.info(msg_test)

dictConfig(create_new_format())
logger.info(msg_test)
logger_2.info(msg_test)

哪个会给你:

2021-07-20 23:02:11 INFO     [root] TEST TEST TEST
2021-07-20 23:02:11 INFO     [2] TEST TEST TEST
2021-07-20 23:02:11 INFO     [root] TEST TEST TEST...adding some stuff
2021-07-20 23:02:11 INFO     [2] TEST TEST TEST...adding some stuff
2021-07-20 23:02:11 INFO     [root] TEST TEST TEST
2021-07-20 23:02:11 INFO     [2] TEST TEST TEST

答案 4 :(得分:-1)

如果要动态更改日志格式。 可以这样制作。

logger = logging.getLogger()
# Change format of handler for the logger
logger.handlers[0].setFormatter(logging.Formatter('%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s'))
# Print log
logging.info(log)
# return other format
logger.handlers[0].setFormatter(logging.Formatter('%(message)s'))