Eu uso o recurso de registro para python 2.7.3. A documentação para esta versão Python diz :
o pacote de registro é anterior às opções de formatação mais recentes, como str.format () e string.Template. Essas opções de formatação mais recentes são suportadas ...
Eu gosto do 'novo' formato com chaves. Então, estou tentando fazer algo como:
log = logging.getLogger("some.logger")
log.debug("format this message {0}", 1)
E obter o erro:
TypeError: nem todos os argumentos convertidos durante a formatação da string
O que eu sinto falta aqui?
PS eu não quero usar
log.debug("format this message {0}".format(1))
porque neste caso a mensagem está sempre sendo formatada, independentemente do nível do logger.
python
python-2.7
string-formatting
MajesticRa
fonte
fonte
log.debug("format this message%d" % 1)
Formatter
para usar '{' como estiloRespostas:
EDIT: dê uma olhada na
StyleAdapter
abordagem na resposta do @Dunes ao contrário desta resposta; permite usar estilos de formatação alternativos sem o clichê ao chamar os métodos do logger (debug (), info (), error (), etc).Dos documentos - Uso de estilos de formatação alternativos :
E:
Copie e cole no
wherever
módulo: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)
Então:
from wherever import BraceMessage as __ log.debug(__('Message with {0} {name}', 2, name='placeholders'))
Nota: a formatação real é atrasada até que seja necessária, por exemplo, se as mensagens DEBUG não forem registradas, a formatação não será executada.
fonte
num = 2; name = 'placeholders'; log.debug(f'Message with {num} {name}')
Aqui está outra opção que não possui os problemas de palavra-chave mencionados na resposta de Dunes. Ele pode lidar apenas com
{0}
argumentos posicionais ( ) e não com argumentos de palavra-chave ({foo}
). Também não requer duas chamadas para formatar (usando o sublinhado). Ele tem o fator ick de subclassestr
: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
Você o usa assim:
logger = StyleAdapter(logging.getLogger(__name__)) logger.info("knights:{0}", "ni", style="{") logger.info("knights:{}", "shrubbery", style="{")
Obviamente, você pode remover a marca de verificação com
# optional
para forçar todas as mensagens através do adaptador a usar a formatação de novo estilo.Observação para quem ler esta resposta anos depois : a partir do Python 3.2 , você pode usar o parâmetro style com
Formatter
objetos:Os documentos fornecem o exemplo
logging.Formatter('{asctime} {name} {levelname:8s} {message}', style='{')
Observe que, neste caso, você ainda não pode chamar o
logger
com o novo formato. Ou seja, o seguinte ainda não funcionará:logger.info("knights:{say}", say="ni") # Doesn't work! logger.info("knights:{0}", "ni") # Doesn't work either
fonte
Formatter
, o que está correto agora (eu acho). OStyleAdapter
ainda funciona,BraceString
é uma subclasse de string, é seguro retornar de__str__
A solução mais fácil seria usar o módulo excelente
logbook
import logbook import sys logbook.StreamHandler(sys.stdout).push_application() logbook.debug('Format this message {k}', k=1)
Ou o mais completo:
>>> 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
fonte
Essa foi a minha solução para o problema quando descobri que o log só usa a formatação no estilo printf. Ele permite que as chamadas de registro permaneçam as mesmas - sem sintaxe especial como
log.info(__("val is {}", "x"))
. A mudança necessária para codificar é envolver o logger em aStyleAdapter
.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}
O uso é:
log = StyleAdapter(logging.getLogger(__name__)) log.info("a log message using {type} substitution", type="brace")
É importante notar que esta implementação tem problemas se as palavras-chave utilizadas para substituição cinta incluem
level
,msg
,args
,exc_info
,extra
oustack_info
. Esses são nomes de argumentos usados pelolog
método deLogger
. Se precisar de um desses nomes, modifiqueprocess
para excluí-los ou apenas removê-loslog_kwargs
da_log
chamada. Em uma nota adicional, esta implementação também ignora silenciosamente palavras-chave com erros ortográficos destinadas ao Logger (por exemplo.ectra
).fonte
Como outras respostas mencionam, a formatação estilo chave introduzida no Python 3.2 é usada apenas na string de formato, não nas mensagens de log reais.
Para habilitar a formatação do tipo chave na mensagem de log real, podemos corrigir um pouco do código do logger.
O seguinte corrige o
logging
módulo para criar umaget_logger
função que retornará um logger que usa a formatação de novo estilo para cada registro de log que ele controla.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
Uso:
>>> log = get_logger() >>> log.warning("{!r}", log) <logging.RootLogger object at 0x4985a4d3987b>
Notas:
logging.getLogger
porget_logger
)get_logger
função (não quebra pacotes de terceiros).logging.getLogger()
chamada normal , a formatação do novo estilo ainda será aplicada.exc_info
,stack_info
,stacklevel
eextra
).logging.LogRecord
objetos como de costume (útil em alguns casos com manipuladores de log personalizados).logging
código - fonte do módulo , parece que ele deve funcionar desde o Python 2.6 quandostr.format
foi introduzido (mas eu só testei no 3.5 e superior)fonte
Experimente
logging.setLogRecordFactory
no 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)
fonte
%
formatação, pois a fábrica de registros é global para o módulo de registro.Criei um formatador personalizado, chamado ColorFormatter, que lida com o problema desta forma:
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…
Isso o mantém compatível com várias bibliotecas. A desvantagem é que provavelmente não tem desempenho devido à possível tentativa de formatação da string duas vezes.
fonte
Solução semelhante à pR0Ps', envolvimento
getMessage
emLogRecord
pelo embrulhomakeRecord
(em vez dehandle
em sua resposta) em casos deLogger
que deve ser nova formatação habilitado: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
Eu testei isso com Python 3.5.3.
fonte
Aqui está algo bem simples que funciona:
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))
Então:
mydebuglog("hello {} {val}", "Python", val="World")
fonte