Skip to content

Instantly share code, notes, and snippets.

@natedub
Created July 23, 2011 21:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save natedub/1101888 to your computer and use it in GitHub Desktop.
Save natedub/1101888 to your computer and use it in GitHub Desktop.
Colorizing and formatting Python logging console output for better readability
"""
This colorizing :class:`logging.Formatter` implementation adds ANSI color
sequences to make logging output more readable.
SQLAlchemy queryies are treated specially: Pygments formats the query
string and the bind params. Python tracebacks are also formatted by
Pygments. Package names vary their colors as well, see the MY_APP_NAME
setting.
If you're configuring logging via a INI file, add this formatter like so:
[formatters]
keys = ..., colorized
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = colorized
[formatter_colorized]
class = colorformatter.AnsiColorFormatter
NOTE: Requires Pygments and Fabric, both available on PyPi.
Enjoy!
.. author:: Nathan Wright <wright.nathan@gmail.com>
"""
#
# Copyright 2011 Nathan Wright <wright.nathan@gmail.com>
#
import logging
import re
import sys
from fabric.colors import blue
from fabric.colors import cyan
from fabric.colors import green
from fabric.colors import magenta
from fabric.colors import red
from fabric.colors import yellow
from pygments import highlight
from pygments.formatters import TerminalFormatter
from pygments.lexers import MySqlLexer
from pygments.lexers import PythonLexer
from pygments.lexers import PythonTracebackLexer
mysql_lexer = MySqlLexer()
python_lexer = PythonLexer()
python_traceback_lexer = PythonTracebackLexer()
terminal_formatter = TerminalFormatter()
re_color_codes = re.compile(r'\033\[(\d;)?\d+m')
MY_APP_NAME = 'myapp.'
LEVELS = {
'WARNING': red(' WARN', bold=True),
'INFO': blue(' INFO'),
'DEBUG': blue('DEBUG'),
'CRITICAL': magenta(' CRIT'),
'ERROR': red('ERROR'),
}
class AnsiColorFormatter(logging.Formatter):
def __init__(self, msgfmt=None, datefmt=None):
logging.Formatter.__init__(self, None, '%H:%M:%S')
def format(self, record):
"""
Format the specified record as text.
The record's attribute dictionary is used as the operand to a
string formatting operation which yields the returned string.
Before formatting the dictionary, a couple of preparatory steps
are carried out. The message attribute of the record is computed
using LogRecord.getMessage(). If the formatting string contains
"%(asctime)", formatTime() is called to format the event time.
If there is exception information, it is formatted using
formatException() and appended to the message.
"""
message = record.getMessage()
asctime = self.formatTime(record, self.datefmt)
name = record.name
if name == 'sqlalchemy.engine.base.Engine':
name = green('sqlalchemy')
if record.levelname == 'INFO':
if message.startswith('('):
lexer = python_lexer
else:
lexer = mysql_lexer
message = highlight(message, lexer, terminal_formatter).rstrip()
elif name.startswith(MY_APP_NAME):
name = yellow(name)
else:
name = cyan(name)
s = '%(timestamp)s %(threadName)s %(levelname)s %(name)s ' % {
'timestamp': green('%s,%03d' % (asctime, record.msecs), bold=True),
'levelname': LEVELS[record.levelname],
'name': name,
'threadName': yellow(record.threadName, bold=True)
}
if "\n" in message:
indent_length = len(re_color_codes.sub('', s))
message = message.replace("\n", "\n" + ' ' * indent_length)
s += message
if record.exc_info:
# Cache the traceback text to avoid converting it multiple times
# (it's constant anyway)
if not record.exc_text:
record.exc_text = self.formatException(record.exc_info)
if record.exc_text:
if s[-1:] != "\n":
s = s + "\n"
try:
exc_text = record.exc_text
except UnicodeError:
# Sometimes filenames have non-ASCII chars, which can lead
# to errors when s is Unicode and record.exc_text is str
# See issue 8924
exc_text = record.exc_text.decode(sys.getfilesystemencoding())
s += highlight(exc_text, python_traceback_lexer, terminal_formatter)
return s
@dbrgn
Copy link

dbrgn commented May 16, 2012

Instead of relying on fabric for colors (why using a deployment library for coloring?) you could use fabulous instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment