在Python中(通过日志记录模块)临时更改日志消息格式的最简单方法是什么?
目标是拥有一些标准的消息格式,同时能够临时添加有关正在读取的文件的信息(如其名称);当文件不再被读取时,消息格式应恢复为默认值。生成消息的程序不知道正在读取什么文件,所以如果它的消息自动包含相关文件名将会很好(错误消息将是:“ERROR while阅读文件 ***:...“而不是”错误:......“)。
答案 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 ones(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)
实例化格式化程序......
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'))