Me gustaría tener TRACE (5) de nivel de registro para mi aplicación, ya que no creo que debug()
sea suficiente. Además log(5, msg)
no es lo que quiero. ¿Cómo puedo agregar un nivel de registro personalizado a un registrador de Python?
Tengo una mylogger.py
con el siguiente contenido:
import logging
@property
def log(obj):
myLogger = logging.getLogger(obj.__class__.__name__)
return myLogger
En mi código lo uso de la siguiente manera:
class ExampleClass(object):
from mylogger import log
def __init__(self):
'''The constructor with the logger'''
self.log.debug("Init runs")
Ahora me gustaria llamar self.log.trace("foo bar")
Gracias de antemano por tu ayuda.
Editar (8 de diciembre de 2016): cambié la respuesta aceptada a pfa que es, en mi humilde opinión, una excelente solución basada en la muy buena propuesta de Eric S.
fuente
logging.DEBUG_LEVEL_NUM = 9
para que pueda acceder a ese nivel de depuración en cualquier lugar donde importe el registrador en su código?DEBUG_LEVEL_NUM = 9
, debería definirlogging.DEBUG_LEVEL_NUM = 9
. De esta manera, podrá utilizarlo delog_instance.setLevel(logging.DEBUG_LEVEL_NUM)
la misma manera que utiliza el conocimiento correctologging.DEBUG
ologging.INFO
logging.DEBUGV = DEBUG_LEVELV_NUM
ylogging.__all__ += ['DEBUGV']
La segunda no es muy importante, pero la primera es necesaria si tiene algún código que ajusta dinámicamente el nivel de registro y desea poder hacer algo comoif verbose: logger.setLevel(logging.DEBUGV)
`Tomé la respuesta "evitar ver lambda" y tuve que modificar dónde se estaba agregando log_at_my_log_level. Yo también vi el problema que hizo Paul "No creo que esto funcione. ¿No necesitas logger como primer argumento en log_at_my_log_level?" Esto funcionó para mi
fuente
__init__.py
y sé feliz: DTypeError: not all arguments converted during string formatting
pero funciona bien con *. (Python 3.4.3). ¿Es un problema de la versión de Python o algo que me falta?AttributeError: module 'logging' has no attribute 'debugv'
Combinando todas las respuestas existentes con un montón de experiencia de uso, creo que he elaborado una lista de todas las cosas que se deben hacer para garantizar un uso completamente fluido del nuevo nivel. Los pasos a continuación asumen que está agregando un nuevo nivel
TRACE
con valorlogging.DEBUG - 5 == 5
:logging.addLevelName(logging.DEBUG - 5, 'TRACE')
debe invocarse para que el nuevo nivel se registre internamente para que se pueda hacer referencia a él por su nombre.logging
sí mismo para mantener la coherencia:logging.TRACE = logging.DEBUG - 5
.trace
necesario agregar un método llamado allogging
módulo. Se debe comportarse igualdebug
,info
, etc.trace
necesario agregar un método llamado a la clase de registrador configurada actualmente. Dado que esto no está 100% garantizadologging.Logger
, utilícelologging.getLoggerClass()
en su lugar.Todos los pasos se ilustran en el método siguiente:
fuente
Oldest
y apreciará que esta es la mejor respuesta de todas.args
en lalogForLevel
implementación es intencional / requerida?Esta pregunta es bastante antigua, pero simplemente traté el mismo tema y encontré una forma similar a las ya mencionadas que me parece un poco más limpia. Esto se probó en 3.4, por lo que no estoy seguro de si los métodos utilizados existen en versiones anteriores:
fuente
get
ysetLoggerClass
exactamente hacer y por qué se necesitan?TRACE
nivel a la biblioteca de registro predeterminada. +1¿Quién inició la mala práctica de usar métodos internos (
self._log
) y por qué cada respuesta se basa en eso? La solución pitónica sería usarself.log
en su lugar para que no tenga que meterse con ninguna cosa interna:fuente
Me resulta más fácil crear un nuevo atributo para el objeto del registrador que pasa la función log (). Creo que el módulo del registrador proporciona addLevelName () y log () por esta misma razón. Por lo tanto, no se necesitan subclases ni nuevos métodos.
ahora
debería funcionar como se esperaba.
fuente
_log
, nolog
.Si bien ya tenemos muchas respuestas correctas, lo siguiente es, en mi opinión, más pitónico:
Si desea usar
mypy
en su código, se recomienda agregar# type: ignore
para evitar que las advertencias agreguen atributos.fuente
logging.trace = partial(logging.log, logging.TRACE) # type: ignore
?Creo que tendrás que crear una subclase de la
Logger
clase y agregar un método llamadotrace
que básicamente llamaLogger.log
con un nivel inferior aDEBUG
. No he probado esto, pero esto es lo que indican los documentos .fuente
logging.getLogger
para devolver su subclase en lugar de la clase incorporada.setLoggerClass(MyClass)
y luego llamargetLogger()
como de costumbre ...Consejos para crear un registrador personalizado:
_log
, uselog
(no tiene que verificarisEnabledFor
)getLogger
, por lo que deberá configurar la clase a través desetLoggerClass
__init__
para el registrador, clase si no está almacenando nadaCuando llame a este registrador, utilice
setLoggerClass(MyLogger)
para convertirlo en el registrador predeterminado degetLogger
Necesitará
setFormatter
,setHandler
ysetLevel(TRACE)
en lahandler
y en lalog
misma a SE realidad esta traza bajo nivelfuente
Esto funcionó para mí:
El problema lambda / funcName se soluciona con logger._log como señaló @marqueed. Creo que usar lambda parece un poco más limpio, pero el inconveniente es que no puede aceptar argumentos de palabras clave. Yo nunca lo he usado, así que no es problema.
fuente
En mi experiencia, esta es la solución completa al problema de la operación ... para evitar ver "lambda" como la función en la que se emite el mensaje, profundice:
Nunca intenté trabajar con una clase de registrador independiente, pero creo que la idea básica es la misma (use _log).
fuente
logger
como primer argumentolog_at_my_log_level
?Adición al ejemplo de Mad Physicists para obtener el nombre de archivo y el número de línea correctos:
fuente
basado en la respuesta fijada, escribí un pequeño método que crea automáticamente nuevos niveles de registro
config puede algo así:
fuente
Como alternativa a agregar un método adicional a la clase Logger, recomendaría usar el
Logger.log(level, msg)
método.fuente
Estoy confundido; con python 3.5, al menos, simplemente funciona:
salida:
fuente
logger.trace('hi')
lo que creo que es el objetivo principalEn caso de que alguien quiera una forma automatizada de agregar un nuevo nivel de registro al módulo de registro (o una copia del mismo) dinámicamente, he creado esta función, expandiendo la respuesta de @ pfa:
fuente
setattr
en su lugar ...