【问题标题】:Python logging.Formatter uses "%"-formatting instead of "{" even when "{" specified即使指定了“{”,Python logging.Formatter 也使用“%”格式而不是“{”
【发布时间】:2021-11-10 14:30:17
【问题描述】:

我尝试使用自定义格式化程序创建自定义记录器,并相应地从 logging.Loggerlogging.Formatter 继承它们。但是,即使我将style 指定为"{",我也会收到错误消息。据我了解,此错误是由格式化程序尝试使用旧式% 格式化造成的。

这是我的logger.pyformatter.pymain.py 的示例,以重现此内容。

# logger.py
import logging

from formatter import CustomFormatter

class CustomLogger(logging.Logger):
    def __init__(self, name: 'str'):
        super().__init__(name)
        self._console_handler = logging.StreamHandler()

        format_string_for_console = '[{levelname}] {name}: {message}'
        time_format_string = '%Y-%m-%d %H:%M:%S%Z'

        console_formatter = CustomFormatter(
            fmt=format_string_for_console,
            datefmt=time_format_string,
            style='{')

        self._console_handler.setFormatter(console_formatter)
# formatter.py
import copy
import logging

class CustomFormatter(logging.Formatter):
    def __init__(self, fmt: 'str' = None, datefmt: 'str' = None, style: 'str' = '%'):
        self.__format = f'Some modification to default format {fmt}'
        self.__date_format = datefmt
        self.__style = style
        super().__init__(fmt, datefmt, style)

    def format(self, record: 'logging.LogRecord') -> str:
        record_copy = copy.copy(record)
        return logging.Formatter(
            fmt=self.__format,
            datefmt=self.__date_format,
            style=self.__style
        ).format(record_copy)
# main.py
from logger import CustomLogger as CL

logger = CL('test_logger')
logger.warning('info_msg {}', 1)

不要告诉我这个 MVP 的荒谬之处,它被极度缩小到尽可能少,但仍然会重现错误。我得到的错误有这个堆栈跟踪:

--- Logging error ---
Traceback (most recent call last):
  File "/usr/lib/python3.8/logging/__init__.py", line 1085, in emit
    msg = self.format(record)
  File "/usr/lib/python3.8/logging/__init__.py", line 929, in format
    return fmt.format(record)
  File "/usr/lib/python3.8/logging/__init__.py", line 668, in format
    record.message = record.getMessage()
  File "/usr/lib/python3.8/logging/__init__.py", line 373, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Call stack:
  File "<stdin>", line 1, in <module>
Message: 'info_msg {}'
Arguments: (1,)

我一定做错了什么,但我不知道是什么。任何帮助将不胜感激。

【问题讨论】:

  • 是错字吗?不应该是 f-string:format_string_for_console = f'[{levelname}] {name}: {message}' 吗?
  • @MauriceMeyer,绝对不是。一切都按照文档完成。使用{ 意味着该字符串必须使用.format() 方法格式化。您可能知道,此方法支持 kwargs。 levelnamenamemessage__init__ 中是未知的,但它们稍后将由logging 库自动插入,届时它将使用.format() 方法格式化字符串。这里的问题是,尽管format_string_for_console 的格式正确(使用.format),但传递给logger.warning 的参数却不是(他们尝试使用% 样式的格式)

标签: python python-3.x logging formatting


【解决方案1】:

有两个级别的格式化:

  1. 格式化在日志调用中传递的消息和参数。这些总是使用% 格式化,以实现向后兼容性 - 日志记录早于其他类型的格式化。
  2. 将上一步生成的消息与事件时间、进程 ID、线程 ID、当前函数、当前模块和传递给日志调用的任何其他上下文信息等其他内容一起格式化。此级别可以使用传递给格式化程序的style 来决定如何格式化消息。在这种更高级别的格式化中,格式化程序的格式字符串中的message 将保存上一步中确定的值。

【讨论】:

  • 好吧,我理解正确吗,没有办法让传递给logger.warning(或任何其他日志级别)的参数通过'{}'.format() 格式化?如果是这样,它看起来很奇怪。我了解向后兼容问题,但无论如何都很奇怪
  • 没错。这并不是特别奇怪,因为它是当时唯一进行格式化的事情。从那时起,我们就有了string.Template{}-formatting 和 f-strings。现在无法更改,因为使用 %-formatting 的大量现有代码。
猜你喜欢
  • 1970-01-01
  • 2015-12-05
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 2023-01-29
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多