Eu gostaria de ter o nível de log TRACE (5) para meu aplicativo, pois não acho que debug()
seja suficiente. Além disso, log(5, msg)
não é o que eu quero. Como posso adicionar um nível de log personalizado a um logger Python?
Tenho um mylogger.py
com o seguinte conteúdo:
import logging
@property
def log(obj):
myLogger = logging.getLogger(obj.__class__.__name__)
return myLogger
No meu código, eu o uso da seguinte maneira:
class ExampleClass(object):
from mylogger import log
def __init__(self):
'''The constructor with the logger'''
self.log.debug("Init runs")
Agora eu gostaria de ligar self.log.trace("foo bar")
Agradeço antecipadamente por sua ajuda.
Editar (8 de dezembro de 2016): Eu mudei a resposta aceita para pfa's que é, IMHO, uma excelente solução baseada na muito boa proposta de Eric S.
fonte
logging.DEBUG_LEVEL_NUM = 9
tal adicionar para que você possa acessar esse nível de depuração em qualquer lugar que você importar o logger em seu código?DEBUG_LEVEL_NUM = 9
você deve definirlogging.DEBUG_LEVEL_NUM = 9
. Desta forma, você poderá usarlog_instance.setLevel(logging.DEBUG_LEVEL_NUM)
da mesma forma que usa o right knowlogging.DEBUG
orlogging.INFO
logging.DEBUGV = DEBUG_LEVELV_NUM
elogging.__all__ += ['DEBUGV']
A segunda não é muito importante, mas a primeira é necessária se você tiver qualquer código que ajusta dinamicamente o nível de registro e quiser ser capaz de fazer algo comoif verbose: logger.setLevel(logging.DEBUGV)
`Peguei a resposta "evitar ver lambda" e tive que modificar onde o log_at_my_log_level estava sendo adicionado. Eu também vi o problema que Paul fez "Eu não acho que isso funciona. Você não precisa do logger como o primeiro argumento em log_at_my_log_level?" Isso funcionou para mim
fonte
__init__.py
e seja feliz: DTypeError: not all arguments converted during string formatting
mas funciona bem com *. (Python 3.4.3). É um problema de versão do python ou algo que estou perdendo?AttributeError: module 'logging' has no attribute 'debugv'
Combinando todas as respostas existentes com um monte de experiência de uso, acho que vim com uma lista de todas as coisas que precisam ser feitas para garantir o uso totalmente contínuo do novo nível. As etapas abaixo pressupõem que você está adicionando um novo nível
TRACE
com valorlogging.DEBUG - 5 == 5
:logging.addLevelName(logging.DEBUG - 5, 'TRACE')
precisa ser chamado para obter o novo nível registrado internamente para que possa ser referenciado pelo nome.logging
si para a consistência:logging.TRACE = logging.DEBUG - 5
.trace
precisa ser adicionado aologging
módulo. Ele deve se comportar exatamente comodebug
,info
, etc.trace
precisa ser adicionado à classe de logger configurada atualmente. Como isso não é 100% garantidologging.Logger
, use em seulogging.getLoggerClass()
lugar.Todas as etapas são ilustradas no método abaixo:
fonte
Oldest
e você perceberá que esta é a melhor resposta de todas!args
nalogForLevel
implementação é intencional / necessária?Essa questão é um tanto antiga, mas eu apenas tratei do mesmo assunto e encontrei uma forma semelhante às já mencionadas que me parece um pouco mais limpa. Isso foi testado no 3.4, então não tenho certeza se os métodos usados existem em versões mais antigas:
fonte
get
esetLoggerClass
exatamente e por que são necessários?TRACE
nível à biblioteca de registro padrão. +1Quem iniciou a má prática de usar métodos internos (
self._log
) e por que cada resposta é baseada nisso ?! A solução pythônica seria usar emself.log
vez disso, para que você não tenha que mexer com qualquer coisa interna:fonte
Acho mais fácil criar um novo atributo para o objeto logger que passa a função log (). Acho que o módulo logger fornece o addLevelName () e o log () por esse motivo. Portanto, nenhuma subclasse ou novo método é necessário.
agora
deve funcionar como esperado.
fonte
_log
, nãolog
.Embora já tenhamos muitas respostas corretas, o seguinte é, na minha opinião, mais pitônico:
Se você deseja usar
mypy
em seu código, é recomendado adicionar# type: ignore
para suprimir avisos de adição de atributo.fonte
logging.trace = partial(logging.log, logging.TRACE) # type: ignore
?Acho que você terá que criar uma subclasse da
Logger
classe e adicionar um método chamadotrace
que basicamente chamaLogger.log
com um nível inferior aDEBUG
. Não tentei fazer isso, mas é o que os documentos indicam .fonte
logging.getLogger
para retornar sua subclasse em vez da classe interna.setLoggerClass(MyClass)
e ligargetLogger()
normalmente ...Dicas para criar um registrador personalizado:
_log
, uselog
(você não precisa verificarisEnabledFor
)getLogger
, então você precisará definir a classe viasetLoggerClass
__init__
para o logger, classe se você não estiver armazenando nadaAo chamar este registrador, use
setLoggerClass(MyLogger)
para torná-lo o registrador padrão dogetLogger
Você precisará
setFormatter
,setHandler
esetLevel(TRACE)
nahandler
e sobre alog
própria para realmente se Este traço de baixo nívelfonte
Isso funcionou para mim:
O problema lambda / funcName foi corrigido com logger._log conforme @marqueed apontado. Acho que usar lambda parece um pouco mais limpo, mas a desvantagem é que ele não aceita argumentos de palavra-chave. Eu nunca usei isso, então não é nada demais.
fonte
Na minha experiência, esta é a solução completa para o problema da operação ... para evitar ver "lambda" como a função na qual a mensagem é emitida, vá mais fundo:
Nunca tentei trabalhar com uma classe de logger autônoma, mas acho que a ideia básica é a mesma (use _log).
fonte
logger
ser o primeiro argumentolog_at_my_log_level
?Adição ao exemplo do Mad Physicists para obter o nome do arquivo e o número da linha corretos:
fonte
com base na resposta fixada, escrevi um pequeno método que cria automaticamente novos níveis de registro
config pode funcionar assim:
fonte
Como alternativa para adicionar um método extra à classe Logger, eu recomendaria usar o
Logger.log(level, msg)
método.fonte
Estou confuso; com python 3.5, pelo menos, ele simplesmente funciona:
resultado:
fonte
logger.trace('hi')
que acredito ser o objetivo principalCaso alguém queira uma maneira automatizada de adicionar um novo nível de registro ao módulo de registro (ou uma cópia dele) dinamicamente, criei esta função, expandindo a resposta de @pfa:
fonte
setattr