2009-11-16 13 views
14

Es posible iniciar sesión en un solo destino (es decir, usando uno FileHandler) con varios registradores (es decir, logging.getLogger("base.foo") y logging.getLogger("base.bar")) y usar diferentes formateadores para cada uno de los registradores.Cómo usar diferentes formateadores con el mismo controlador de inicio de sesión en python

A mi entender, solo es posible asignar un formateador a cada manejador. ¿Tal vez sea posible asociar el formateador con un registrador en lugar del manejador?

Respuesta

11

Es fácil de enviar a los diferentes formateadores basados ​​en record.name. A continuación se prueba de concepto de código de ejemplo:

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 posible abrir el archivo manualmente y crear dos controladores de flujo de ella con diferentes formateadores.

+0

excelente solución, elegante. Para el registro esto también funciona basado en record.levelno, de modo que la clave del diccionario de formateadores podría ser 'logging.DEBUG' en lugar de' 'base.foo'' – lorenzog

1

Poco arreglo a la excelente solución de Denis.

Logging name system basado en estructura jerárquica:

El name es potencialmente un valor jerárquico período separados, como foo.bar.baz (aunque también podría ser simplemente foo, por ejemplo). Los registradores que están más abajo en la lista jerárquica son hijos de registradores más arriba en la lista. Por ejemplo, dado un registrador con un nombre de foo, los registradores con nombres de foo.bar, foo.bar.baz y foo.bam son todos descendientes de foo.

Por ejemplo, cuando setLevel() para algún registrador, este nivel también se aplicará a los registradores de niños. Es por eso que es posible que desee que su formateador se utilice para el registrador y también para los registradores hijos. Por ejemplo, el formateador 'one.two' también se debe aplicar al registrador 'one.two.three' (si no se configuró ningún formateador para 'one.two.three'). Aquí está la versión de DispatchingFormatter que hacer el trabajo (código 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> 
+0

¿sabe cómo hacer esto con el manejador de archivos? ¿Mismo camino? – Henry

+0

@Henry, sí, simplemente cambie en el segundo fragmento 'StreamHandler()' a 'FileHandler (nombre de archivo)'. El formateador en sí se puede aplicar a cualquier tipo de controlador. –

Cuestiones relacionadas