---- Original Message -----
> From: "c buhtz" <c.bu...@posteo.jp>
> To: python-list@python.org
> Sent: Monday, 3 August, 2015 11:13:37 AM
> Subject: Optimal solution for coloring logging output
> 
> I don't want to ask how to do this because there are so many
> "solutions" about it.
> <http://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output>
> 
> There are so much different and part of unpythontic solutions I can
> not
> decide myself. What do you (as real pythontics) think about that.
> Which of the solutions fit to concepts of Python and its logging
> package?
> 
> Coloring means here not only the message itself. The (levelname)
> should
> be included in the coloring.
> For myself coloring the (levelname) would be enough to avoid to much
> color in the output.
> 
> 1.
> The solution itself shouldn't care about plattform differences
> because
> there are still some packages which are able to offer
> plattform-independent console-coloring. Which would you prefere? ;)
> 
> 2.
> Some solutions derive from StreamHandler or much more bad hacking the
> emit() function. I think both of them are not responsible for how the
> output should look or be presented.
> 
> 3.
> How to present the output is IMO the responsibility of a Formater,
> isn't
> it? So I should derive from the Formater.
> 
> What do you as Pythonics think of that? ;)

This is more or less how it could be done:

1/ use the module "curses" to get terminal colors (the doc suggests to use the 
"Console" moduel on windows)
2/ write a logging Formatter that will replace DEBUG/INFO/ERROR message by 
their colored version.


import curses
import logging
import string
import re

curses.setupterm()
class ColorFormat:
        #{ Foregroung colors
        BLACK = curses.tparm(curses.tigetstr('setaf'), curses.COLOR_BLACK)
        RED = curses.tparm(curses.tigetstr('setaf'), curses.COLOR_RED)
        GREEN = curses.tparm(curses.tigetstr('setaf'), curses.COLOR_GREEN)
        YELLOW = curses.tparm(curses.tigetstr('setaf'), curses.COLOR_YELLOW)
        BLUE = curses.tparm(curses.tigetstr('setaf'), curses.COLOR_BLUE)
        MAGENTA = curses.tparm(curses.tigetstr('setaf'), curses.COLOR_MAGENTA)
        CYAN = curses.tparm(curses.tigetstr('setaf'), curses.COLOR_CYAN)
        WHITE = curses.tparm(curses.tigetstr('setaf'), 9) # default white is 7, 
the 9 is a better white
        #{ Backgrounds colors
        BG_BLACK = curses.tparm(curses.tigetstr('setab'), curses.COLOR_BLACK)
        BG_RED = curses.tparm(curses.tigetstr('setab'), curses.COLOR_RED)
        BG_GREEN = curses.tparm(curses.tigetstr('setab'), curses.COLOR_GREEN)
        BG_YELLOW = curses.tparm(curses.tigetstr('setab'), curses.COLOR_YELLOW)
        BG_BLUE = curses.tparm(curses.tigetstr('setab'), curses.COLOR_BLUE)
        BG_MAGENTA = curses.tparm(curses.tigetstr('setab'), 
curses.COLOR_MAGENTA)
        BG_CYAN = curses.tparm(curses.tigetstr('setab'), curses.COLOR_CYAN)
        BG_WHITE = curses.tparm(curses.tigetstr('setab'), curses.COLOR_WHITE) 
        #{ Format codes
        BOLD = curses.tparm(curses.tigetstr('bold'), curses.A_BOLD)
        UNDERLINE = curses.tparm(curses.tigetstr('smul'), curses.A_UNDERLINE)
        BLINK = curses.tparm(curses.tigetstr('blink'), curses.A_BLINK)
        NO_FORMAT = curses.tparm(curses.tigetstr('sgr0'), curses.A_NORMAL)
        NO_COLOR = curses.tigetstr('sgr0')
        #}

def setFormat(attributeList):
        _set = '' # avoid collision with the builtin set type
        for attribute in attributeList:
                _set += getattr(ColorFormat, attribute, '')
        return _set

class ColorFormatter(logging.Formatter):
        def format(self, record):
                parameters = record.__dict__.copy()
                parameters['message'] = record.getMessage()
                                
                # 
------------------------------------------------------------------
                # Log Level Format : %(levelname)
                # 
------------------------------------------------------------------
                fmt = self._fmt
                pattern = r'(%\(levelname\)(?:-?\d+)?s)'
                if record.levelno <= logging.DEBUG:
                        fmt = re.sub(pattern, setFormat(['BLUE']) + r'\1' + 
                                                 setFormat(['NO_COLOR']), fmt)
                elif record.levelno <= logging.INFO:
                        fmt = re.sub(pattern, setFormat(['CYAN']) + r'\1' + 
                                                 setFormat(['NO_COLOR']), fmt)
                elif record.levelno <= logging.WARNING:
                        fmt = re.sub(pattern, setFormat(['MAGENTA']) + r'\1' + 
                                                 setFormat(['NO_COLOR']), fmt)
                elif record.levelno <= logging.ERROR:
                        fmt = re.sub(pattern, setFormat(['RED','BOLD']) + r'\1' 
+ 
                                                 setFormat(['NO_COLOR']), fmt)
                else:
                        fmt = re.sub(pattern, setFormat(['WHITE', 'BOLD', 
'BG_RED']) + 
                                                 r'\1' + 
setFormat(['NO_COLOR']), fmt)
                
                # 
------------------------------------------------------------------
                # following is the classic format method from the default 
formatter
                # 
------------------------------------------------------------------
                if string.find(fmt,"%(asctime)") >= 0:
                        record.asctime = self.formatTime(record, self.datefmt)
                        parameters['asctime'] = record.asctime
                s = fmt % parameters
                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"
                        s = s + record.exc_text
                return s
        
if __name__ == '__main__':
        logger = logging.getLogger('Foo')
        logger.setLevel(logging.DEBUG)
        logger.addHandler(logging.StreamHandler())
        logger.handlers[-1].setFormatter(ColorFormatter('%(levelname)s - 
%(message)s'))
        logger.error('This is an error')
        logger.debug('This is an debug')


-- IMPORTANT NOTICE: 

The contents of this email and any attachments are confidential and may also be 
privileged. If you are not the intended recipient, please notify the sender 
immediately and do not disclose the contents to any other person, use it for 
any purpose, or store or copy the information in any medium. Thank you.
-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to