Add ColoredFormatter. Add setup.py.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Thu Apr 04 20:24:34 2013 +0200
@@ -0,0 +1,4 @@
+__pycache__
+^\.(pydev)?project$
+^\.settings$
+^build/
--- a/README Wed Apr 03 20:37:05 2013 +0200
+++ b/README Thu Apr 04 20:24:34 2013 +0200
@@ -4,6 +4,7 @@
Pycolib is library of small, mostly one-file, modules with little or not (inter)dependencies.
* ansicolor - change color of text in terminal using ANSI escape sequences
+ * coloredformatter - logging.Formatter which adds ANSI colors to output
* makeurl - adjust string for using in URL by replacing symbols and combined unicode chars
* prettysize - print file sizes in human readable form
* soap - minimal SOAP client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/demo/demo_coloredformatter.py Thu Apr 04 20:24:34 2013 +0200
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+
+from pycolib.coloredformatter import ColoredFormatter
+
+import logging
+
+
+def prepare_logger(name, level=logging.DEBUG):
+ logger = logging.getLogger(name)
+ logger.setLevel(level)
+ return logger
+
+
+def prepare_console_handler(level=logging.DEBUG):
+ handler = logging.StreamHandler()
+ formatter = ColoredFormatter('%(asctime)s %(levelname)-5s %(message)s', '%H:%M:%S')
+ formatter.set_color('message', 'RECV', 2)
+ formatter.set_color('message', 'SEND', 6)
+ handler.setFormatter(formatter)
+ handler.setLevel(level)
+ return handler
+
+
+def setup():
+ logging.addLevelName(21, 'RECV')
+ logging.addLevelName(22, 'SEND')
+
+ logger_main = prepare_logger('main')
+
+ handler_console = prepare_console_handler()
+ logger_main.addHandler(handler_console)
+
+
+def finish():
+ logging.shutdown()
+
+
+def main():
+ setup()
+ log = logging.getLogger('main')
+
+ log.info('test')
+
+ try:
+ raise Exception('test exception')
+ except:
+ log.exception('test exc')
+
+ log.log(21, 'recv')
+ log.log(22, 'send')
+
+ log.debug('debug')
+
+ finish()
+
+
+if __name__ == '__main__':
+ main()
+
--- a/pycolib/ansicolor.py Wed Apr 03 20:37:05 2013 +0200
+++ b/pycolib/ansicolor.py Thu Apr 04 20:24:34 2013 +0200
@@ -9,9 +9,9 @@
def color(enable, fg=None, bg=None):
'''
- color(1) -- switch to bold
- color(1,1) -- red foreground
- color(1,3,4) -- red on blue
+ color(1) -- switch to bold, keep previous color
+ color(1, RED) -- red foreground
+ color(1, BOLD + YELLOW, BLUE) -- yellow on blue, bold
color(0) -- reset
'''
@@ -42,7 +42,7 @@
else:
return "\033[0m"
-def setcolor(enable, fg=None, bg=None):
+def set_color(enable, fg=None, bg=None):
print(color(enable, fg, bg), end='')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycolib/coloredformatter.py Thu Apr 04 20:24:34 2013 +0200
@@ -0,0 +1,81 @@
+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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/setup.py Thu Apr 04 20:24:34 2013 +0200
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3.2
+
+from distutils.core import setup
+
+setup(
+ name='pycolib',
+ version='0.0.1',
+ description='Library of small auxiliary modules',
+ author='Radek Brich',
+ author_email='radek.brich@devl.cz',
+ url='http://hg.devl.cz/pycolib',
+ packages=['pycolib'],
+ )
+