Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@nfarrar
Last active April 13, 2023 06:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nfarrar/f2f484a7a2e21bdef81e to your computer and use it in GitHub Desktop.
Save nfarrar/f2f484a7a2e21bdef81e to your computer and use it in GitHub Desktop.
Python Colored Logging
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = "Nathan Farrar"
__website__ = "http://crunk.io"
__email__ = "nfarrar@crunk.io"
__version__ = 0.1
import logging
import sys
class ColorFormatter(logging.Formatter):
""" A log formatter with color injection. """
def __init__(self, fmt='%(asctime)s %(name)-8s %(levelname)-8s %(message)s',
datefmt='%H:%M:%S', reset='\x1b[0m'):
""" Better format defaults. Reset code can be overridden if
necessary."""
logging.Formatter.__init__(self, fmt=fmt, datefmt=datefmt)
self.reset = reset
def format(self, record):
""" Inject color codes & color resets into log record messages. """
message = logging.Formatter.format(self, record)
try:
color = logging._levelColors[record.levelno]
message = color + message + self.reset
except:
pass
return message
class ColorStreamHandler(logging.StreamHandler):
""" StreamHandler with better defaults. """
def __init__(self, level=logging.DEBUG, stream=sys.stderr,
formatter=ColorFormatter()):
""" Sets the handler level to DEBUG (rather than ERROR) by default. Uses
stderr instead of stdout. Binds the ColorFormatter if another Formatter
hasn't been provided. """
logging.StreamHandler.__init__(self, stream=stream)
if formatter is not None:
self.setFormatter(formatter)
class ColorLogger(logging.Logger):
""" A ColorLogger class with default colormap and convenience methods. """
def __init__(self, name, level=logging.DEBUG, propagate=False,
handlers=[ColorStreamHandler()],
colormap={50: '\x1b[1;31m',
40: '\x1b[31m',
30: '\x1b[33m',
20: '\x1b[32m',
10: '\x1b[35m'}
):
# If logging._levelColors is not defined, define it.
try:
colors = logging._levelColors
except:
colors = logging._levelColors = colormap
# Set the logger's level.
logging.Logger.__init__(self, name, level=level)
# Disable propagation.
self.propagate = propagate
# Add any default handlers. By default this is the ColorHandler.
for handler in handlers:
self.addHandler(handler)
@staticmethod
def _getLevelNumbers():
""" Returns the integer keys from the levelNames dictionary. """
return [ik for ik in logging._levelNames.keys() if type(ik) is int]
@staticmethod
def _getLevelNames():
""" Returns the string keys from the levelNames dictionary. """
return [sk for sk in logging._levelNames.keys() if type(sk) is str]
@staticmethod
def addLevel(levelno, name, color):
""" Adds a custom logging level with color. """
logging._levelNames[levelno] = name
logging._levelColors[levelno] = color
@staticmethod
def testmsgs(logger=None, msg='test message'):
""" Emit test messages for each defined logging level. """
for level in ColorLogger._getLevelNumbers():
if logger is None:
logging.log(level=level, msg=msg)
else:
logger.log(level=level, msg=msg)
if __name__ == '__main__':
""" Example use. """
# Root logger with default configuration. Does not need to be instantiated
# if propagation is disabled on ColorLogger (default behavior).
rootlogger = logging.getLogger()
logging.basicConfig()
# Setup color logger.
colorlogger = ColorLogger('colorlogger')
# Emit some test log entries.
ColorLogger.testmsgs(rootlogger)
ColorLogger.testmsgs(colorlogger)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment