Last active
April 13, 2023 06:22
-
-
Save nfarrar/f2f484a7a2e21bdef81e to your computer and use it in GitHub Desktop.
Python Colored Logging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
__author__ = "Nathan Farrar" | |
__website__ = "http://crunk.io" | |
__email__ = "[email protected]" | |
__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