practices - python logging variables
Cómo usar diferentes formateadores con el mismo controlador de registro en python (2)
¿Es posible iniciar sesión en un solo destino (es decir, usar un FileHandler
) con múltiples registradores (es decir, logging.getLogger("base.foo")
y logging.getLogger("base.bar")
), y usar diferentes formateadores para cada uno de los madereros
A mi entender, solo es posible asignar un formateador a cada identificador. ¿Quizás es posible asociar el formateador con un registrador en lugar de con el controlador?
Es fácil enviar a diferentes formateadores basados en record.name
. A continuación se muestra el código de ejemplo de prueba de concepto:
import logging
class DispatchingFormatter:
def __init__(self, formatters, default_formatter):
self._formatters = formatters
self._default_formatter = default_formatter
def format(self, record):
formatter = self._formatters.get(record.name, self._default_formatter)
return formatter.format(record)
handler = logging.StreamHandler()
handler.setFormatter(DispatchingFormatter({
''base.foo'': logging.Formatter(''FOO: %(message)s''),
''base.bar'': logging.Formatter(''BAR: %(message)s''),
},
logging.Formatter(''%(message)s''),
))
logging.getLogger().addHandler(handler)
logging.getLogger(''base.foo'').error(''Log from foo'')
logging.getLogger(''base.bar'').error(''Log from bar'')
logging.getLogger(''base.baz'').error(''Log from baz'')
Otra forma es abrir el archivo manualmente y crear dos manejadores de flujo desde él con diferentes formateadores.
Pequeño remedio a la excelente solución de Denis.
Sistema de nombres de registro basado en estructura jerárquica:
El
name
es potencialmente un valor jerárquico separado porfoo.bar.baz
, comofoo.bar.baz
(aunque también podría ser simplementefoo
, por ejemplo). Los registradores que están más abajo en la lista jerárquica son hijos de los registradores más arriba en la lista. Por ejemplo, dado un registrador con un nombre defoo
, los registradores con nombres defoo.bar
,foo.bar.baz
yfoo.bam
son todos descendientes defoo
.
Por ejemplo, cuando setLevel() para algún registrador, este nivel también se aplicará a registradores secundarios. Es por eso que es posible que desee que su formateador se use para el registrador y también para los registradores secundarios. Por ejemplo, ''one.two''
formateador ''one.two''
también debe aplicarse al registrador ''one.two.three''
(si no hay un formateador para ''one.two.three''
). Aquí está la versión de DispatchingFormatter que hace el trabajo (código de Python 3):
class DispatchingFormatter:
"""Dispatch formatter for logger and it''s sub logger."""
def __init__(self, formatters, default_formatter):
self._formatters = formatters
self._default_formatter = default_formatter
def format(self, record):
# Search from record''s logger up to it''s parents:
logger = logging.getLogger(record.name)
while logger:
# Check if suitable formatter for current logger exists:
if logger.name in self._formatters:
formatter = self._formatters[logger.name]
break
else:
logger = logger.parent
else:
# If no formatter found, just use default:
formatter = self._default_formatter
return formatter.format(record)
Ejemplo:
handler = logging.StreamHandler()
handler.setFormatter(DispatchingFormatter({
''one'': logging.Formatter(''%(message)s -> one''),
''one.two'': logging.Formatter(''%(message)s -> one.two''),
},
logging.Formatter(''%(message)s -> <default>''),
))
logging.getLogger().addHandler(handler)
print(''Logger used -> formatter used:'')
logging.getLogger(''one'').error(''one'')
logging.getLogger(''one.two'').error(''one.two'')
logging.getLogger(''one.two.three'').error(''one.two.three'') # parent formatter ''one.two'' will be used here
logging.getLogger(''other'').error(''other'')
# OUTPUT:
# Logger used -> formatter used:
# one -> one
# one.two -> one.two
# one.two.three -> one.two
# other -> <default>