pycolib/coloredformatter.py
author Radek Brich <radek.brich@devl.cz>
Thu, 04 Apr 2013 20:24:34 +0200
changeset 2 d3ffa15f5886
child 5 055f7dfb3e4f
permissions -rw-r--r--
Add ColoredFormatter. Add setup.py.

import logging
from copy import copy

from pycolib.ansicolor import color, BOLD, WHITE, YELLOW, RED


class ColoredFormatter(logging.Formatter):

    def __init__(self, fmt, datefmt):
        logging.Formatter.__init__(self, fmt, datefmt)
        self._colors = {
            'message': {
                'default': (None, None),
                'exception': (BOLD + YELLOW, RED),
                },
            'levelname': {
                'default': (BOLD + WHITE, None),
                'debug': (None, None),
                },
            'time': {
                'default': (BOLD + WHITE, None),
                'debug': (None, None),
                },
            }


    def formatTime(self, record, datefmt=None):
        """Override, add color as specified."""
        formatted = logging.Formatter.formatTime(self, record, datefmt)
        fg, bg = self.get_color('time', record)
        if fg or bg:
            formatted = color(1, fg, bg) + formatted + color(0)
        return formatted


    def format(self, record):
        """Override, add color as specified."""
        original_record = copy(record)

        ### message color
        fg, bg = self.get_color('message', record)
        if fg or bg:
            record.msg = color(1, fg, bg) + record.msg + color(0)

        ### levelname color
        fg, bg = self.get_color('levelname', record)
        if fg or bg:
            record.levelname = color(1, fg, bg) + record.levelname + color(0)

        res = logging.Formatter.format(self, record)

        record = original_record
        return res


    def set_color(self, fieldname, levelname, fg=None, bg=None):
        """Specify color for parts of log message.

        Args:
            fieldname: Which field to apply: 'message' | 'levelname' | 'time'
            levelname: Log level to apply, case insensitive: 'debug' | 'info' etc.
                Custom levels are supported too.
                Special name 'default' is used for unspecified levels.

        """
        self._colors[fieldname][levelname.lower()] = (fg, bg)


    def get_color(self, fieldname, record):
        """Get specified color for field levelname (from record)."""
        colormap = self._colors[fieldname]
        levelname = record.levelname.lower()
        fg, bg = colormap['default']
        if levelname in colormap:
            fg, bg = colormap[levelname]
        # exception is not real level, detect it using exc_info
        if record.levelno == logging.ERROR and record.exc_info is not None \
        and 'exception' in colormap:
            fg, bg = colormap['exception']
        return fg, bg