Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I color Python logging output?

Some time ago, I saw a Mono application with colored output, presumably because of its log system (because all the messages were standardized).

Now, Python has the logging module, which lets you specify a lot of options to customize output. So, I'm imagining something similar would be possible with Python, but I can’t find out how to do this anywhere.

Is there any way to make the Python logging module output in color?

What I want (for instance) errors in red, debug messages in blue or yellow, and so on.

Of course this would probably require a compatible terminal (most modern terminals are); but I could fallback to the original logging output if color isn't supported.

Any ideas how I can get colored output with the logging module?

like image 328
airmind Avatar asked Dec 21 '08 03:12

airmind


People also ask

How do you add color to logging in Python?

Just use the color variables $BLACK - $WHITE in your log formatter string. To set the background just use $BG-BLACK - $BG-WHITE.

What are the five levels of logging in Python?

In Python, the built-in logging module can be used to log events. Log messages can have 5 levels - DEBUG, INGO, WARNING, ERROR and CRITICAL. They can also include traceback information for exceptions. Logs can be especially useful in case of errors to help identify their cause.


1 Answers

I already knew about the color escapes, I used them in my bash prompt a while ago. Thanks anyway.
What I wanted was to integrate it with the logging module, which I eventually did after a couple of tries and errors.
Here is what I end up with:

BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)  #The background is set with 40 plus the number of the color, and the foreground with 30  #These are the sequences need to get colored ouput RESET_SEQ = "\033[0m" COLOR_SEQ = "\033[1;%dm" BOLD_SEQ = "\033[1m"  def formatter_message(message, use_color = True):     if use_color:         message = message.replace("$RESET", RESET_SEQ).replace("$BOLD", BOLD_SEQ)     else:         message = message.replace("$RESET", "").replace("$BOLD", "")     return message  COLORS = {     'WARNING': YELLOW,     'INFO': WHITE,     'DEBUG': BLUE,     'CRITICAL': YELLOW,     'ERROR': RED }  class ColoredFormatter(logging.Formatter):     def __init__(self, msg, use_color = True):         logging.Formatter.__init__(self, msg)         self.use_color = use_color      def format(self, record):         levelname = record.levelname         if self.use_color and levelname in COLORS:             levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ             record.levelname = levelname_color         return logging.Formatter.format(self, record) 

And to use it, create your own Logger:

# Custom logger class with multiple destinations class ColoredLogger(logging.Logger):     FORMAT = "[$BOLD%(name)-20s$RESET][%(levelname)-18s]  %(message)s ($BOLD%(filename)s$RESET:%(lineno)d)"     COLOR_FORMAT = formatter_message(FORMAT, True)     def __init__(self, name):         logging.Logger.__init__(self, name, logging.DEBUG)                          color_formatter = ColoredFormatter(self.COLOR_FORMAT)          console = logging.StreamHandler()         console.setFormatter(color_formatter)          self.addHandler(console)         return   logging.setLoggerClass(ColoredLogger) 

Just in case anyone else needs it.

Be careful if you're using more than one logger or handler: ColoredFormatter is changing the record object, which is passed further to other handlers or propagated to other loggers. If you have configured file loggers etc. you probably don't want to have the colors in the log files. To avoid that, it's probably best to simply create a copy of record with copy.copy() before manipulating the levelname attribute, or to reset the levelname to the previous value, before returning the formatted string (credit to Michael in the comments).

like image 80
airmind Avatar answered Sep 28 '22 07:09

airmind