2016-01-27 10 views
5

Mi piacerebbe avere l'output di registrazione Python in forma di albero corrispondente all'albero del logger. Guarda l'esempio.Formato messaggi di registro come albero

consente di dire che abbiamo un codice:

import logging 

logger_a = logging.getLogger("a") 
logger_a_b = logging.getLogger("a.b") 
logger_a_b_c = logging.getLogger("a.b.c") 
# ... 


logger_a.debug("One") 

logger_a_b.warning("two") 
logger_a_b.warning("three") 

logger_a_b_c.critical("Four") 

logger_a_b.warning("Five") 

L'output dovrebbe essere qualcosa del tipo:

<--"a" 
    | DEBUG: One 
    | 
    o<--"a.b" 
    | | WARNING: Two 
    | | WARNING: Three 
    | | 
    | o<--"a.b.c" 
    |  | CRITICAL: Four 
    |  | 
    | | WARNING: Five 

Potrei scrivere formattatori per ciascuno dei log a mano, ma non risolve il problema di inserire qualcosa come o < - "ab" a destra e preferirei calcolare l'offset automaticamente tramite la struttura di registrazione.

C'è un modulo chiamato logging tree. Stampa il layout di registrazione. Quello che vorrei, è stampare i messaggi di registro all'incirca nello stesso modo.

Conosci qualche biblioteca, modi per farlo in modo semplice?

+0

Penso che sarà necessario scrivere il proprio gestore di log, magari ereditando dal 'logging.StreamHandler' incorporato. –

+0

Tuttavia, non sarebbe difficile trasformare l'output standard in questo albero: ottenere il nome del modulo, diviso per punto, disegnare l'albero prima del messaggio. Sembra che tu abbia già tutte le informazioni, solo bisogno di una trasformazione della vista. – viraptor

+0

Probabilmente potrebbe essere sufficiente – MajesticRa

risposta

3

In base all'esempio, ho creato un numero personalizzato Formatter che gestirà l'albero.

import logging 

# custom tree formatter 
class TreeFormatter(logging.Formatter): 
    formatPrefix = {} # map loggername, formatPrefix 

    def format(self, record): 
     s = "" 
     # first time this name is encountered: create the prefix and print the name 
     if not record.name in self.formatPrefix: 
      f = self.getFormatPrefix(record) 
      s += "%s \"%s\"\n" % (f, record.name) 

     # print the actual message 
     s += "%s %s: %s" % (self.formatPrefix[record.name], record.levelname, record.msg) 
     return s 


    # create the format prefix for the given package name 
    # (stored in self.formatPrefix[record.name]) 
    # and return the first line to print 
    def getFormatPrefix(self, record): 
     depth = record.name.count(".") 
     self.formatPrefix[record.name] = " |" * (depth+1) 

     if depth == 0: 
      return "<--" 

     return "%so<--" % ((" |" * depth)[:-1]) 

È quindi possibile utilizzarlo per creare il logger di primo livello (qui a). Il resto del codice è invariato.

Ecco un esempio:

# use this to create the first level logger 
def createTreeLogger(name, level=logging.DEBUG): 
    logger = logging.getLogger(name) 
    logger.setLevel(level) 
    ch = logging.StreamHandler() 
    ch.setLevel(level) 
    ch.setFormatter(TreeFormatter()) 
    logger.addHandler(ch) 
    return logger 


if __name__ == '__main__': 

    logger_a = createTreeLogger("a") # first level: use createLogger 
    # then create your loggers as always 
    logger_a_b = logging.getLogger("a.b") 
    logger_a_b_c = logging.getLogger("a.b.c") 


    logger_a.debug("One") 

    logger_a_b.warning("two") 
    logger_a_b.warning("three") 

    logger_a_b_c.critical("Four") 

    logger_a_b.warning("Five") 
    logger_a.warning("Six") 

Ciò che è bello è che i meccanismi interni del pacchetto di registrazione utilizzeranno automaticamente lo stesso gestore per i sottopacchetti (a.b, A.B.C). Così, per l'esecuzione di questo codice, si ottiene:

<-- "a" 
    | DEBUG: One 
    o<-- "a.b" 
    | | WARNING: two 
    | | WARNING: three 
    | o<-- "a.b.c" 
    | | | CRITICAL: Four 
    | | WARNING: Five 
    | WARNING: Six 

Uno svantaggio è che i registri di generare confusione se si dispone di più di una gerarchia pacchetto. Ma la classe TreeFormatter è facile da modificare in base alle proprie esigenze.