Format log messages as tree

I would like the output of python log to be in the form of a tree corresponding to the logger tree. Just look at an example.

Let's say we have a code:

import logging logger_a = logging.getLogger("a") logger_a_b = logging.getLogger("ab") logger_a_b_c = logging.getLogger("abc") # ... 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") 

The result should look something like this:

 <--"a" | DEBUG: One | o<--"ab" | | WARNING: Two | | WARNING: Three | | | o<--"abc" | | CRITICAL: Four | | | | WARNING: Five 

I could write formatters for each of the logs manually, but this does not solve the problem of inserting something like o <- "ab" to the right, and I would prefer to automatically calculate the offset from the logging structure.

There is a module called the logging tree . He prints a logging layout. I would like to print log messages about the same.

Do you know any libraries, ways to do this easily?

+5
source share
1 answer

Based on your example, I created a custom Formatter that will process the tree.

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

Then you can use it to create a first level registrar (here a). The rest of the code does not change.

Here is an example:

 # 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("ab") logger_a_b_c = logging.getLogger("abc") 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") 

It’s good that the inside of the logging package will automatically use the same handler for subpackages (ab, abc). So, by running this code, you will get:

 <-- "a" | DEBUG: One o<-- "ab" | | WARNING: two | | WARNING: three | o<-- "abc" | | | CRITICAL: Four | | WARNING: Five | WARNING: Six 

One of the drawbacks is that logs become confusing if you have more than one package hierarchy. But the TreeFormatter class TreeFormatter itself easily to your needs.

+3
source

Source: https://habr.com/ru/post/1241666/


All Articles