How to Color Python Logging Output

Color logging using logging module in Python

Thanks Dominic Kexel for this link. I saw this but did not pay attention to the answer.
The following code is more or less suitable for me

def setup_logger(logger):
logger.setLevel(logging.DEBUG)

sh = logging.StreamHandler()
formatter = logging.Formatter(LOG_FORMAT)
sh.setFormatter(formatter)

def decorate_emit(fn):
# add methods we need to the class
def new(*args):
levelno = args[0].levelno
if(levelno >= logging.CRITICAL):
color = '\x1b[31;1m'
elif(levelno >= logging.ERROR):
color = '\x1b[31;1m'
elif(levelno >= logging.WARNING):
color = '\x1b[33;1m'
elif(levelno >= logging.INFO):
color = '\x1b[32;1m'
elif(levelno >= logging.DEBUG):
color = '\x1b[35;1m'
else:
color = '\x1b[0m'
# add colored *** in the beginning of the message
args[0].msg = "{0}***\x1b[0m {1}".format(color, args[0].msg)

# new feature i like: bolder each args of message
args[0].args = tuple('\x1b[1m' + arg + '\x1b[0m' for arg in args[0].args)
return fn(*args)
return new
sh.emit = decorate_emit(sh.emit)
logger.addHandler(sh)

There is one flaw in this: I can't control the position of *** in the pattern but as I said it's suitable.

How to view colored logs files?

I think you can write your logs to a binary file and then you can read them from the binary file.

You can make a python program that reads your binary file (after you written your logs in that file) and output the content to console.

Add a new colored level logging

This requires the addition of a handful of lines, including this block (with the addition of another line to set the integer value for logging.SUCCESS:

def success(msg, *args, **kwargs):
if logging.getLogger().isEnabledFor(70):
logging.log(70, msg)

logging.addLevelName(70, "SUCCESS")
logging.SUCCESS = 70 # similar to logging.INFO -> 20
logging.success = success
logging.Logger.success = success

I've indicated the lines that have been added/modified here. To add further additional levels, defining the same structures for the new ones, and modifying the for loop and set_colour() functions should be enough.

import logging
import re
import time
import sys

def set_colour(level):
"""
Sets colour of text for the level name in
logging statements using a dispatcher.
"""
escaped = "[\033[1;%sm%s\033[1;0m]"
return {
'INFO': lambda: logging.addLevelName(logging.INFO, escaped % ('94', level)),
'WARNING': lambda: logging.addLevelName(logging.ERROR, escaped % ('93', level)),
'ERROR': lambda: logging.addLevelName(logging.WARNING, escaped % ('91', level)),
'SUCCESS': lambda: logging.addLevelName(logging.SUCCESS, escaped % ('31', level)) # new
}.get(level, lambda: None)()

class NoColorFormatter(logging.Formatter):
"""
Log formatter that strips terminal colour
escape codes from the log message.
"""

# Regex for ANSI colour codes
ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")

def format(self, record):
"""Return logger message with terminal escapes removed."""
return "%s %s %s" % (
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
re.sub(self.ANSI_RE, "", record.levelname),
record.msg,
)

def success(msg, *args, **kwargs): # new
if logging.getLogger().isEnabledFor(70): # new
logging.log(70, msg) # new

# Create logger
logger = logging.getLogger(__package__)

# Create formatters
logformatter = NoColorFormatter()
colorformatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")

# Create new level
logging.SUCCESS = 70 # new
logging.success = success # new
logging.Logger.success = success # new

# Set logging colours
for level in 'INFO', 'ERROR', 'WARNING', 'SUCCESS': # modified
set_colour(level)

# Set logging level
logger.setLevel(logging.INFO)

# Set log handlers
loghandler = logging.FileHandler("log.txt", mode="w", encoding="utf8")
streamhandler = logging.StreamHandler(sys.stdout)

# Set log formatters
loghandler.setFormatter(logformatter)
streamhandler.setFormatter(colorformatter)

# Attach log handlers to logger
logger.addHandler(loghandler)
logger.addHandler(streamhandler)

# Example logging statements
logging.info("This is just an information for you")
logging.warning("This is just an information for you")
logging.error("This is just an information for you")
logging.success("This is just an information for you")

PyCharm logging output colours

PyCharm doesn't support that feature natively, however you can download the Grep Console plugin and set the colors as you like.

Here's a screenshot:
http://plugins.jetbrains.com/files/7125/screenshot_14104.png (link is dead)

I hope it helps somewhat :) although it doesn't provide fully colorized console, but it's a step towards it.

Python: How to color logs while printing to a file?

It can be a solution to use the Windows PowerShell Get-Content function to print a file which contains ANSI escape sequences to color the log.

For example:

import coloredlogs
import logging

# Create a logger object.
logger = logging.getLogger(__name__)

# Create a filehandler object
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)

# Create a ColoredFormatter to use as formatter for the FileHandler
formatter = coloredlogs.ColoredFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)

# Install the coloredlogs module on the root logger
coloredlogs.install(level='DEBUG')

logger.debug("this is a debugging message")
logger.info("this is an informational message")
logger.warning("this is a warning message")
logger.error("this is an error message")
logger.critical("this is a critical message")

When opening a Windows PowerShell you can use Get-Content .\spam.log to print the logs in color.

add color in GUI logger

A possible option is to use HTML:

import logging
from PyQt4 import QtCore, QtGui

class CustomFormatter(logging.Formatter):
FORMATS = {
logging.ERROR: ("[%(levelname)-8s] %(message)s", QtGui.QColor("red")),
logging.DEBUG: ("[%(levelname)-8s] [%(filename)s:%(lineno)d] %(message)s", "green"),
logging.INFO: ("[%(levelname)-8s] %(message)s", "#0000FF"),
logging.WARNING: ('%(asctime)s - %(name)s - %(levelname)s - %(message)s', QtGui.QColor(100, 100, 0))
}

def format( self, record ):
last_fmt = self._style._fmt
opt = CustomFormatter.FORMATS.get(record.levelno)
if opt:
fmt, color = opt
self._style._fmt = "<font color=\"{}\">{}</font>".format(QtGui.QColor(color).name(),fmt)
res = logging.Formatter.format( self, record )
self._style._fmt = last_fmt
return res

class QPlainTextEditLogger(logging.Handler):
def __init__(self, parent=None):
super().__init__()
self.widget = QtGui.QPlainTextEdit(parent)
self.widget.setReadOnly(True)

def emit(self, record):
msg = self.format(record)
self.widget.appendHtml(msg)
# move scrollbar
scrollbar = self.widget.verticalScrollBar()
scrollbar.setValue(scrollbar.maximum())

class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
logTextBox = QPlainTextEditLogger()
logging.getLogger().addHandler(logTextBox)
logTextBox.setFormatter(CustomFormatter())
logging.getLogger().setLevel(logging.DEBUG)

lay = QtGui.QVBoxLayout(self)
lay.addWidget(logTextBox.widget)

QtCore.QTimer(self, interval=500,
timeout=self.on_timeout).start()

@QtCore.pyqtSlot()
def on_timeout(self):
import random
msgs = (
lambda: logging.debug('damn, a bug'),
lambda: logging.info('something to remember'),
lambda: logging.warning('that\'s not right'),
lambda: logging.error('foobar'),
lambda: logging.critical('critical :-(')
)
random.choice(msgs)()

if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = Dialog()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())

Sample Image



Related Topics



Leave a reply



Submit