---- 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