Search code examples
pythonloggingpython-3.xcolorsconsole

How to decorate console logger messages in Python?


I am using a logger in Python, and I want it to show some messages (not all) with colors in console.

Now I do this:

print('\033[0;41;97m')
logger.info('Colored message')
print('\033[0m')

It works well, but the problem is that there are blank lines above and below the message. I can't do this:

print('\033[0;41;97m', end='')
logger.info('Colored message')
print('\033[0m')

Because this way there is a blank line below the message. And I can't do this neither:

logger.info('\033[0;41;97m' + 'Colored message' + '\033[0m')

Because then, when I open the log file I see weird symbols. Any solution, please?

EDIT

ch = logging.StreamHandler()
fh = logging.handlers.RotatingFileHandler(log_file, 'a', max_bytes, 10)

ch_formatter = logging.Formatter('%(asctime)s - %(levelname)-4s - '
                                 '%(message)s',
                                 datefmt='%Y.%m.%d_%H:%M:%S_%Z')
fh_formatter = logging.Formatter('%(asctime)s - %(levelname)-4s - '
                                 '%(message)s',
                                 datefmt='%Y.%m.%d_%H:%M:%S_%Z')
ch.setFormatter(ch_formatter)
fh.setFormatter(fh_formatter)

logger.addHandler(ch)
logger.addHandler(fh)

Solution

  • UPDATE

    OP says I am using a RotatingFileHandler. :)

    Define a new FileHandler which escapes ansi color

    # file handler for **ansi_escape**
    class MyFileHandler(logging.handlers.RotatingFileHandler):
        import re
        ansi_escape = re.compile(r'\x1b[^m]*m')
        def emit(self, record):
            record.msg = self.ansi_escape.sub('', record.msg)
            logging.handlers.RotatingFileHandler.emit(self, record)
    

    Then add this and StreamHandler to logger

    ch = logging.StreamHandler()
    fh = MyFileHandler('file.log')
    
    ch_formatter = logging.Formatter('%(asctime)s - %(levelname)-4s - '
                                     '%(message)s',
                                     datefmt='%Y.%m.%d_%H:%M:%S_%Z')
    fh_formatter = logging.Formatter('%(asctime)s - %(levelname)-4s - '
                                     '%(message)s',
                                     datefmt='%Y.%m.%d_%H:%M:%S_%Z')
    
    
    ch.setFormatter(ch_formatter)
    fh.setFormatter(fh_formatter)
    logger.addHandler(ch)
    logger.addHandler(fh)
    

    Define infoc... see below:

    logger.infoc = lambda msg: logger.info('\033[0;41;97m' + msg + '\033[0m')
    

    Finally you can archive...

    # for colored console but not file
    logger.infoc('Colored message')
    # for normal
    logger.info('Normal message')
    

    EDIT

    How about using wrapper for the colored messages.

    logger.infoc = lambda msg: logger.info('\033[0;41;97m' + msg + '\033[0m')
    logger.infoc('Colored message')
    

    Use basicConfig as

    fmt = '\033[0;41;97m %(message)s \033[0m'
    logging.basicConfig(level=logging.DEBUG, format=fmt)
    logger = logging.getLogger(__file__)
    logger.info('hello')
    

    Or

    console = logging.StreamHandler()
    console.setFormatter(logging.Formatter(fmt))
    logger.addHandler(console)
    
    logger.error('hello')
    

    UPDATE

    The color code should be in StreamHandler only. Modify FileHandler like this:

    fileh = logging.FileHandler('file.log')
    fileh.setFormatter(logging.Formatter('%(message)s')) # remove the color code.
    logger.addHandler(fileh)
    

    No more weird symbols in your logfile.