简体   繁体   English

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

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

What is the simplest method for temporarily changing the logging message format, in Python (through the logging module)?在 Python 中(通过 logging 模块)临时更改日志消息格式的最简单方法是什么?

The goal is to have some standard message format, while being able to temporarily add information about some file being read (like its name);目标是拥有一些标准的消息格式,同时能够临时添加有关正在读取的某些文件的信息(如其名称); the message format should revert to its default when the file is not being read anymore.当不再读取文件时,消息格式应恢复为默认值。 The program that produces the messages is not aware of what file is being read, so it would be nice if its message automatically included the relevant file name (the error message would be: "ERROR while reading file ***: …" instead of "ERROR: …").生成消息的程序知道正在读取哪个文件,因此如果其消息自动包含相关文件名(错误消息将是:“读取文件时出错 ***:……”而不是“错误: …”)。

Here is a simple solution, that can be deduced from Vinay Sajip 's own HOWTO ;这是一个简单的解决方案,可以从Vinay Sajip自己的HOWTO推导出来; it basically updates the logging formatter with setFormatter() :它基本上使用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

This correctly produces:这正确地产生:

error message
PROCESSING FILE xxx - error message

(where xxx can be set dynamically to the file being processed, as asked for in the question). (其中xxx可以动态设置为正在处理的文件,如问题中所要求)。

There are several ways.有几种方法。 Apart from the already documented ones ( extra argument to logging calls, LoggerAdapter , Filter ) , another way would be to specify a custom formatting class, whose instance you can keep informed about the file being processed.除了已经记录的那些(记录调用的extra参数, LoggerAdapterFilter ),另一种方法是指定自定义格式类,您可以随时了解正在处理的文件的实例。 For example:例如:

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)

Instantiate the formatter ...实例化格式化程序...

f = FileProcessingFormatter('%(levelname)s__FILE_PLACEHOLDER__ %(message)s')
for h in relevant_handlers:
    h.setFormatter(f)

Process files ...处理文件...

f.current_file = fn
process_file(fn)
f.current_file = None

This is very simplistic - for example, not for use in threaded environments if file processing is done by different threads concurrently.这是非常简单的 - 例如,如果文件处理由不同的线程并发完成,则不适用于线程环境。

Update: Although the root logger's handlers are accessible via logging.getLogger().handlers , this is an implementation detail that could change.更新:虽然可以通过logging.getLogger().handlers访问根记录器的处理logging.getLogger().handlers ,但这是一个可能会更改的实现细节。 As your requirement is not that basic, you could perhaps use dictConfig() to configure your logging (available via the logutils project for older versions of Python).由于您的要求不是那么基本,您也许可以使用dictConfig()来配置您的日志记录(可通过logutils项目获取旧版本的 Python)。

I don't recommend this;我不推荐这个; but you can say assume the first root handler is the one that's screwed up and modify it directly但是你可以说假设第一个根处理程序被搞砸了并直接修改它

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

if you are in any system with managed logging;如果您在任何具有托管日志记录的系统中; this is probably going to shoot your foot;这可能会射你的脚; it really would be best to be able to determine an exact reference to the handler you want to modify and modify that;最好能够确定对要修改和修改的处理程序的确切引用;

but nobody cares how broken it is if it works right?/s但没有人关心它是否正常工作?/s

Using dictConfig() , as mentioned in the update by @Vinay Sajip, seems to be the way to go.正如@Vinay Sajip 在更新中提到的那样,使用dictConfig()似乎是要走的路。 Here is a working implementation in Python 3.8.这是 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)

Which will give you:这会给你:

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

if you want to dynamic change format of log.如果你想动态改变日志的格式。 it could be made like this.它可以像这样制作。

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