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_())
Related Topics
How Does Condensed Distance Matrix Work? (Pdist)
Pip Installing in Global Site-Packages Instead of Virtualenv
Spark Dataframe Distinguish Columns with Duplicated Name
Numpy Index Slice Without Losing Dimension Information
Pandas/Python: Set Value of One Column Based on Value in Another Column
Let JSON Object Accept Bytes or Let Urlopen Output Strings
Could Not Find a Version That Satisfies the Requirement Tensorflow
Jupyter Notebook with Python 3.8 - Notimplementederror
How to Generate a Random Number with a Specific Amount of Digits
Virtualenv --No-Site-Packages and Pip Still Finding Global Packages
How to Plot Multiple Functions on the Same Figure, in Matplotlib
Could Pandas Use Column as Index
How to Change Values in a Tuple
Format Floats with Standard JSON Module
Django Upgrading to 1.9 Error "Appregistrynotready: Apps Aren't Loaded Yet."