2016-01-27 16 views
5

Ich möchte Python Logging-Ausgabe in Form von Baum entsprechend Logger-Baum haben. Schauen Sie sich nur ein Beispiel an.Format Protokollmeldungen als Baum

Können sagen, wir haben einen Code:

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

Der Ausgang etwas sein sollte:

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

I Formatierer für jedes der Protokoll von Hand schreiben konnte, aber nicht lösen das Problem, etwas wie o < - "ab" richtig einzufügen, und ich würde es vorziehen, Offset automatisch durch Protokollierung der Struktur zu berechnen.

Es gibt ein Modul namens logging tree. Es druckt das Protokollierungslayout. Was ich möchte, ist Protokollnachrichten ungefähr auf die gleiche Weise zu drucken.

Kennen Sie irgendwelche Bibliotheken, Möglichkeiten, es einfach zu tun?

+0

Ich denke, Sie müssen Ihre eigenen Log-Handler schreiben, vielleicht von der integrierten 'Logging.StreamHandler' erben. –

+0

Es wäre nicht schwer, die Standardausgabe in diesen Baum zu transformieren: Holen Sie den Modulnamen, geteilt durch Punkt, zeichnen Sie Baum vor der Nachricht. Scheint so, als hättest du schon alle Informationen, benötige nur eine Ansichtstransformation. – viraptor

+0

Wahrscheinlich könnte das genug sein – MajesticRa

Antwort

3

Basierend auf Ihrem Beispiel habe ich eine benutzerdefinierte Formatter erstellt, die den Baum behandelt.

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

Sie können es dann verwenden, um den Logger der ersten Ebene zu erstellen (hier a). Der Rest des Codes ist unverändert. Hier

ein Beispiel:

# 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") 

Was schön ist, dass das Logging-Paket Einbauten automatisch die gleiche Prozedur für den Subpackages verwenden (a.b, a.b.c). Also, indem Sie diesen Code ausgeführt wird, erhalten Sie:

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

Ein Nachteil ist, dass die Protokolle verwirrend sein, wenn Sie mehr als eine Pakethierarchie haben. Aber die TreeFormatter Klasse ist einfach an Ihre Bedürfnisse anzupassen.

Verwandte Themen