首页 > 解决方案 > 如何处理日志消息模板中的 Python 格式错误?

问题描述

我有时会弄乱 Pythonlogging模块的模板字符串格式,例如:

import logging
logging.warning('%d', 1, 2)  # BROKEN

在控制台中,我可以看到一条警告消息(省略了堆栈跟踪):

--- Logging error ---
Traceback (most recent call last):
  File ".../python3.7/logging/__init__.py", line 1034, in emit
    msg = self.format(record)
  File ".../python3.7/logging/__init__.py", line 880, in format
    return fmt.format(record)
  File ".../python3.7/logging/__init__.py", line 619, in format
    record.message = record.getMessage()
  File ".../python3.7/logging/__init__.py", line 380, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Call stack:
    ...
Message: '%d'
Arguments: (1, 2)

但是,我的消息和此警告都不会发送到日志处理程序,该处理程序实际上会将其写入日志文件,将其发送到 logstash 等。

我知道我可以通过 pylint 使用 logging-too-few-args (E1206) 和 logging-too-many-args (E1205) 找到这些错误,但是我仍然更喜欢某种运行时回退,以防其中一个滑过。

因此,除非有人从 Python 外部监控 stderr,否则这些错误很容易被忽视。

有没有办法仍然用标记和基本部分记录消息,例如:

[LogBug] 消息='%d',参数=(1, 2)

这样,原始信息仍将被保留,并且可以定期扫描日志文件以查找[LogBug]标记。

标签: pythontemplatesloggingformat

解决方案


你可以使用try/except吗?可能re用于从异常消息中提取消息和参数

import re

try:
    logging.warning('%d', 1, 2)
except TypeError as e:
    message = re.search(r'Message: ([^\n]*)[\n$]', e.message).group(1)
    arguments = re.search(r'Arguments: ([^\n]*)[\n$]', e.message).group(1)
    logging.error("[LogBug] message=%s, arguments=%s",message, arguments)
    # if you want, you could re-raise this exception

如果您确实使用此解决方案,您可能还必须适应错误处理,以防万一TypeError不是您期望的格式,因此正则表达式将无法工作,并且会AttributeError在您尝试调用.group()它时引发。

潜在地,您可以进行多深的检查是没有限制的,但是如果您确实确定此检查正常工作,那么它可能能够捕获其他检查。


或者,如果您使用的是最新版本的 python,您可以使用格式字符串,而不是信任logging包进行参数插入,这样就不会为这种歧义留下空间:

i, j = 1, 2
logging.warning(f"{i}")

推荐阅读