#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:
Существует два уровня форматирования:
- Форматирование сообщения и аргументов, переданных в вызове регистрации. Они всегда форматируются с использованием
%
, для обратной совместимости — ведение журнала предшествует другим видам форматирования. - Форматирование сообщения, сгенерированного на предыдущем шаге, вместе с другими данными, такими как время события, идентификатор процесса, идентификатор потока, текущая функция, текущий модуль и любая другая контекстная информация, переданная вызову регистрации. Этот уровень может использовать
style
переданное в средство форматирования, чтобы решить, как отформатировать сообщение. На этом более высоком уровне форматированияmessage
в строке формата средства форматирования будет содержаться значение, определенное на предыдущем шаге.
Комментарии:
1. Итак, правильно ли я понимаю, что нет способа сделать так, чтобы аргументы, передаваемые на
logger.warning
(или любой другой уровень журнала), формировались с помощью'{}'.format()
? Если так, то это выглядит странно. Я понимаю проблемы с обратной связью, но в любом случае странно2. Верно. Это не особенно странно, так как в то время это было единственное, что требовалось для форматирования. С тех пор у нас было
string.Template
{}
форматирование и f-строки. Сейчас это невозможно изменить из-за большого объема существующего кода, который использует % — форматирование.