繁体   English   中英

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

[英]How to change the format of logged messages temporarily, in Python?

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

目标是拥有一些标准的消息格式,同时能够临时添加有关正在读取的某些文件的信息(如其名称); 当不再读取文件时,消息格式应恢复为默认值。 生成消息的程序知道正在读取哪个文件,因此如果其消息自动包含相关文件名(错误消息将是:“读取文件时出错 ***:……”而不是“错误: …”)。

这是一个简单的解决方案,可以从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可以动态设置为正在处理的文件,如问题中所要求)。

有几种方法。 除了已经记录的那些(记录调用的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访问根记录器的处理logging.getLogger().handlers ,但这是一个可能会更改的实现细节。 由于您的要求不是那么基本,您也许可以使用dictConfig()来配置您的日志记录(可通过logutils项目获取旧版本的 Python)。

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

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

如果您在任何具有托管日志记录的系统中; 这可能会射你的脚; 最好能够确定对要修改和修改的处理程序的确切引用;

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

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

import logging
from logging.config import dictConfig    
FI_PATH_CONSUMERS_LOG = "/project/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(
    filename=FI_PATH_CONSUMERS_LOG,
    format=LOG_FORMAT,
    level=getattr(logging, LOG_LEVEL),
    datefmt=LOG_DATEFMT,
)
logger = logging.getLogger()  # root logger
logger_2 = logging.getLogger("2")  # child logger with name "2"
msg_test = "TEST TEST TEST"

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

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

如果你想动态改变日志的格式。 它可以像这样制作。

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'))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM