Я использую средство ведения журнала для Python 2.7.3. В документации для этой версии Python говорится :
пакет регистрации предшествует новым параметрам форматирования, таким как str.format () и string.Template. Эти новые параметры форматирования поддерживаются ...
Мне нравится «новый» формат с фигурными скобками. Итак, я пытаюсь сделать что-то вроде:
log = logging.getLogger("some.logger")
log.debug("format this message {0}", 1)
И получите ошибку:
TypeError: не все аргументы преобразуются во время форматирования строки
Что мне здесь не хватает?
PS не хочу использовать
log.debug("format this message {0}".format(1))
потому что в этом случае сообщение всегда форматируется независимо от уровня регистратора.
python
python-2.7
string-formatting
MajesticRa
источник
источник
log.debug("format this message%d" % 1)
Formatter
использование '{' в качестве стиляОтветы:
РЕДАКТИРОВАТЬ: взгляните на
StyleAdapter
подход в ответе @Dunes в отличие от этого ответа; он позволяет использовать альтернативные стили форматирования без шаблона при вызове методов регистратора (debug (), info (), error () и т. д.).Из документации - Использование альтернативных стилей форматирования :
И:
Скопируйте и вставьте это в
wherever
модуль:class BraceMessage(object): def __init__(self, fmt, *args, **kwargs): self.fmt = fmt self.args = args self.kwargs = kwargs def __str__(self): return self.fmt.format(*self.args, **self.kwargs)
Потом:
from wherever import BraceMessage as __ log.debug(__('Message with {0} {name}', 2, name='placeholders'))
Примечание: фактическое форматирование откладывается до тех пор, пока оно не станет необходимым, например, если сообщения DEBUG не регистрируются, форматирование не выполняется вообще.
источник
num = 2; name = 'placeholders'; log.debug(f'Message with {num} {name}')
Вот еще один вариант, в котором нет проблем с ключевыми словами, упомянутых в ответе Дюны. Он может обрабатывать только
{0}
аргументы positional ( ), но не аргументы keyword ({foo}
). Также не требуется двух вызовов форматирования (с использованием подчеркивания). У него есть фактор подклассаstr
:class BraceString(str): def __mod__(self, other): return self.format(*other) def __str__(self): return self class StyleAdapter(logging.LoggerAdapter): def __init__(self, logger, extra=None): super(StyleAdapter, self).__init__(logger, extra) def process(self, msg, kwargs): if kwargs.pop('style', "%") == "{": # optional msg = BraceString(msg) return msg, kwargs
Вы используете это так:
logger = StyleAdapter(logging.getLogger(__name__)) logger.info("knights:{0}", "ni", style="{") logger.info("knights:{}", "shrubbery", style="{")
Конечно, вы можете удалить отметку, отмеченную значком,
# optional
чтобы заставить все сообщения, проходящие через адаптер, использовать форматирование нового стиля.Примечание для тех, кто читает этот ответ спустя годы : начиная с Python 3.2 , вы можете использовать параметр стиля с
Formatter
объектами:Документы предоставляют пример
logging.Formatter('{asctime} {name} {levelname:8s} {message}', style='{')
Обратите внимание, что в этом случае вы по-прежнему не можете вызвать
logger
с новым форматом. Т.е. по-прежнему не сработает следующее:logger.info("knights:{say}", say="ni") # Doesn't work! logger.info("knights:{0}", "ni") # Doesn't work either
источник
Formatter
, что сейчас правильно (я думаю). ВсеStyleAdapter
еще работает,BraceString
это строковый подкласс, можно безопасно вернуться из__str__
Более простым решением было бы использовать отличный
logbook
модульimport logbook import sys logbook.StreamHandler(sys.stdout).push_application() logbook.debug('Format this message {k}', k=1)
Или более полный:
>>> import logbook >>> import sys >>> logbook.StreamHandler(sys.stdout).push_application() >>> log = logbook.Logger('MyLog') >>> log.debug('Format this message {k}', k=1) [2017-05-06 21:46:52.578329] DEBUG: MyLog: Format this message 1
источник
Это было моим решением проблемы, когда я обнаружил, что при ведении журнала используется только форматирование в стиле printf. Это позволяет вести журнал вызовов неизменным - без специального синтаксиса, такого как
log.info(__("val is {}", "x"))
. Изменение, необходимое для кода, - заключить регистратор в файлStyleAdapter
.from inspect import getargspec class BraceMessage(object): def __init__(self, fmt, args, kwargs): self.fmt = fmt self.args = args self.kwargs = kwargs def __str__(self): return str(self.fmt).format(*self.args, **self.kwargs) class StyleAdapter(logging.LoggerAdapter): def __init__(self, logger): self.logger = logger def log(self, level, msg, *args, **kwargs): if self.isEnabledFor(level): msg, log_kwargs = self.process(msg, kwargs) self.logger._log(level, BraceMessage(msg, args, kwargs), (), **log_kwargs) def process(self, msg, kwargs): return msg, {key: kwargs[key] for key in getargspec(self.logger._log).args[1:] if key in kwargs}
Использование:
log = StyleAdapter(logging.getLogger(__name__)) log.info("a log message using {type} substitution", type="brace")
Стоит отметить , что эта реализация имеет проблемы , если ключевые слова , используемые для замены распорной включают
level
,msg
,args
,exc_info
,extra
илиstack_info
. Это имена аргументов, используемыеlog
методомLogger
. Если вам нужно одно из этих имен, измените,process
чтобы исключить эти имена или просто удалитьlog_kwargs
из_log
вызова. Кроме того, эта реализация также молча игнорирует ключевые слова с ошибками, предназначенные для Регистратора (напримерectra
).источник
Как упоминается в других ответах, форматирование в стиле скобок, представленное в Python 3.2, используется только в строке формата, а не в фактических сообщениях журнала.
Чтобы включить форматирование в виде фигурных скобок для фактического сообщения журнала, мы можем исправить немного кода регистратора.
Следующие исправления
logging
модуля позволяют создатьget_logger
функцию, которая будет возвращать средство ведения журнала, использующее форматирование нового стиля для каждой обрабатываемой записи журнала.import functools import logging import types def _get_message(record): """Replacement for logging.LogRecord.getMessage that uses the new-style string formatting for its messages""" msg = str(record.msg) args = record.args if args: if not isinstance(args, tuple): args = (args,) msg = msg.format(*args) return msg def _handle_wrap(fcn): """Wrap the handle function to replace the passed in record's getMessage function before calling handle""" @functools.wraps(fcn) def handle(record): record.getMessage = types.MethodType(_get_message, record) return fcn(record) return handle def get_logger(name=None): """Get a logger instance that uses new-style string formatting""" log = logging.getLogger(name) if not hasattr(log, "_newstyle"): log.handle = _handle_wrap(log.handle) log._newstyle = True return log
Применение:
>>> log = get_logger() >>> log.warning("{!r}", log) <logging.RootLogger object at 0x4985a4d3987b>
Ноты:
logging.getLogger
наget_logger
)get_logger
функцией (не нарушает сторонние пакеты).logging.getLogger()
вызова, форматирование в новом стиле все равно будет применяться.exc_info
,stack_info
,stacklevel
иextra
).logging.LogRecord
объектах как обычно (полезно в некоторых случаях с пользовательскими обработчиками журналов).logging
исходный код модуля, кажется, что он должен работать вплоть до Python 2.6, когдаstr.format
был представлен (но я тестировал его только в версии 3.5 и выше).источник
Попробуйте
logging.setLogRecordFactory
в Python 3.2+:import collections import logging class _LogRecord(logging.LogRecord): def getMessage(self): msg = str(self.msg) if self.args: if isinstance(self.args, collections.Mapping): msg = msg.format(**self.args) else: msg = msg.format(*self.args) return msg logging.setLogRecordFactory(_LogRecord)
источник
%
форматирование, поскольку фабрика записей является глобальной для модуля ведения журнала.Я создал собственный форматировщик под названием ColorFormatter, который решает проблему следующим образом:
class ColorFormatter(logging.Formatter): def format(self, record): # previous stuff, copy from logging.py… try: # Allow {} style message = record.getMessage() # printf except TypeError: message = record.msg.format(*record.args) # later stuff…
Это сохраняет его совместимость с различными библиотеками. Недостатком является то, что он, вероятно, неэффективен из-за возможной попытки форматирования строки дважды.
источник
Аналогичное решение для pR0Ps ', заключающееся
getMessage
вLogRecord
упаковкуmakeRecord
(вместоhandle
их ответа) в тех случаях,Logger
когда должно быть включено новое форматирование:def getLogger(name): log = logging.getLogger(name) def Logger_makeRecordWrapper(name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None): self = log record = logging.Logger.makeRecord(self, name, level, fn, lno, msg, args, exc_info, func, sinfo) def LogRecord_getMessageNewStyleFormatting(): self = record msg = str(self.msg) if self.args: msg = msg.format(*self.args) return msg record.getMessage = LogRecord_getMessageNewStyleFormatting return record log.makeRecord = Logger_makeRecordWrapper return log
Я тестировал это с помощью Python 3.5.3.
источник
Вот что-то очень простое, что работает:
debug_logger: logging.Logger = logging.getLogger("app.debug") def mydebuglog(msg: str, *args, **kwargs): if debug_logger.isEnabledFor(logging.DEBUG): debug_logger.debug(msg.format(*args, **kwargs))
Потом:
mydebuglog("hello {} {val}", "Python", val="World")
источник