2009-11-16 8 views
14

È possibile accedere a una singola destinazione (ad esempio utilizzando uno FileHandler) con più logger (ad esempio logging.getLogger("base.foo") e logging.getLogger("base.bar")) e utilizzare diversi formattatori per ciascuno dei logger.Come utilizzare diversi formattatori con lo stesso gestore di registrazione in python

A mio parere è possibile solo assegnare un formattatore a ciascun handle. Forse è possibile associare il formattatore a un logger piuttosto che al gestore?

risposta

11

È facile da inviare a diversi formattatori basati su record.name. Qui di seguito è dimostrare-of-concept codice di esempio:

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') 

Un altro modo è quello di aprire il file manualmente e creare due gestori di flusso da esso con differenti formattatori.

+0

Eccellente, soluzione elegante. Per la cronaca funziona anche su record.levelno, in modo che la chiave del dizionario di formattazione possa essere 'logging.DEBUG' invece di' 'base.foo'' – lorenzog

1

Piccola soluzione all'eccellente soluzione di Denis.

Logging name system base alla struttura gerarchica:

Il name è potenzialmente un valore gerarchico periodo separati, come foo.bar.baz (ma potrebbe anche essere semplicemente foo, per esempio). I logger più in basso nell'elenco gerarchico sono figli dei logger più in alto nell'elenco. Ad esempio, dato un logger con un nome di foo, i logger con i nomi di foo.bar, foo.bar.baz e foo.bam sono tutti discendenti di foo.

Ad esempio, quando si utilizza il logger setLevel(), questo livello verrà applicato anche ai registratori di dati secondari. Ecco perché potresti volere che il tuo formattatore venga usato per il logger e anche per i logger dei bambini. Ad esempio, il programma di formattazione 'one.two' deve essere applicato anche al logger 'one.two.three' (se non è impostato alcun formattatore per 'one.two.three'). Ecco la versione di DispatchingFormatter che fanno lavoro (codice 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) 

Esempio:

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

sai come fare a filehandler? Stessa strada? – Henry

+0

@Henry, sì, basta cambiare il secondo snippet 'StreamHandler()' in 'FileHandler (nomefile)'. Il formattatore stesso può essere applicato a qualsiasi tipo di gestore. –

Problemi correlati