Ведение журнала Python.Форматер использует «%»-форматирование вместо » { » , даже если указано «{«

#python #python-3.x #logging #formatting

Вопрос:

Я попытался создать пользовательский регистратор с пользовательским форматером, унаследовав их от logging.Logger и logging.Formatter соответственно. Однако, несмотря на то , что я указал style "{" , что это так, я получаю ошибку. Насколько я понял, эта ошибка вызвана тем, что форматер пытается форматировать, используя % форматирование в старом стиле.

Вот пример моего logger.py , formatter.py и main.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') -gt; 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 "lt;stdingt;", line 1, in lt;modulegt; Message: 'info_msg {}' Arguments: (1,)  

Должно быть, я делаю что-то не так, но я не могу понять, что именно. Любая помощь будет признательна.

Комментарии:

1. Это опечатка ? Разве это не должна быть строка f: format_string_for_console = f'[{levelname}] {name}: {message}' ?

2. @MauriceMeyer, определенно нет. Все делается в соответствии с документами. Использование { означает, что эта строка должна быть сформирована с помощью .format() метода. Как вы, вероятно, знаете, этот метод поддерживает кварги. levelname , name и message неизвестны в __init__ , но они будут вставлены позже logging библиотекой автоматически, когда она отформатирует строку с .format() помощью метода. Проблема здесь в том, что, однако format_string_for_console , отформатировано правильно (с .format ), аргументы, переданные logger.warning не являются (они пытаются использовать % форматирование в стиле)

Ответ №1:

Существует два уровня форматирования:

  1. Форматирование сообщения и аргументов, переданных в вызове регистрации. Они всегда форматируются с использованием % , для обратной совместимости — ведение журнала предшествует другим видам форматирования.
  2. Форматирование сообщения, сгенерированного на предыдущем шаге, вместе с другими данными, такими как время события, идентификатор процесса, идентификатор потока, текущая функция, текущий модуль и любая другая контекстная информация, переданная вызову регистрации. Этот уровень может использовать style переданное в средство форматирования, чтобы решить, как отформатировать сообщение. На этом более высоком уровне форматирования message в строке формата средства форматирования будет содержаться значение, определенное на предыдущем шаге.

Комментарии:

1. Итак, правильно ли я понимаю, что нет способа сделать так, чтобы аргументы, передаваемые на logger.warning (или любой другой уровень журнала), формировались с помощью '{}'.format() ? Если так, то это выглядит странно. Я понимаю проблемы с обратной связью, но в любом случае странно

2. Верно. Это не особенно странно, так как в то время это было единственное, что требовалось для форматирования. С тех пор у нас было string.Template {} форматирование и f-строки. Сейчас это невозможно изменить из-за большого объема существующего кода, который использует % — форматирование.