41c6100ceb4a17f25dce2533088a439d04525a9e
   1"""
   2This file sets up logging for the entire logparse package. Custom log formatter
   3and handler classes are specified below and the logger is supplied to all
   4subsequent modules, including parsers.
   5"""
   6
   7__version__ = '2.0'
   8__name__ = 'logparse'
   9
  10
  11from copy import copy
  12import logging
  13import logging.handlers
  14
  15
  16# Standard shell escape codes
  17ESC = {
  18        "reset": "\033[0m",
  19        "color": "\033[1;%dm",
  20        "bold": "\033[1m",
  21        "underlined": "\033[4m"
  22    }
  23
  24# Standard shell colour codes (30..39 are the foreground colors)
  25DEFAULT = 39
  26BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN = range(30, 37)
  27
  28# Map colours to log levels (used for level text only)
  29COLORS = {
  30        10: BLUE,       # debug
  31        20: DEFAULT,    # info
  32        30: YELLOW,     # warning
  33        40: RED,        # error
  34        50: RED         # critical
  35    }
  36
  37# Template for formatting log messages
  38FORMAT = ("{bold}%(name)-15s{reset}  %(levelname)-18s  %(message)s "
  39        "({bold}%(filename)s{reset}:%(lineno)d)")
  40
  41
  42class ColoredFormatter(logging.Formatter):
  43    """
  44    Custom implementation of a log formatter to apply standard shell colour
  45    escape sequences depending on the log level. The original record is copied
  46    so as to not interfere with subsequent handlings (i.e. the syslog handler).
  47    """
  48
  49    def __init__(self, msg):
  50        logging.Formatter.__init__(self, msg)
  51
  52    def format(self, record):
  53        temprecord = copy(record)
  54        levelname = temprecord.levelname
  55        if temprecord.levelno in COLORS:
  56            levelname_color = ESC["color"] % (COLORS[temprecord.levelno]) \
  57                + levelname + ESC["reset"]
  58            temprecord.levelname = levelname_color
  59        temprecord.name = record.name.replace(__name__ + ".", "")
  60        return logging.Formatter.format(self, temprecord)
  61
  62
  63class ColoredLogger(logging.Logger):
  64    """
  65    Custom implementation of a logger object using the `ColoredFormatter` class
  66    above. This class also includes a syslog handler to direct a minimal amount
  67    of output to /dev/log.
  68    """
  69
  70    message = FORMAT.format(**ESC)
  71
  72    def __init__(self, name):
  73        """
  74        Initialise the logger for the entire package. This is done here so that
  75        the configuration is applied to all child modules. A syslog handler
  76        is also initialised, with a min level of INFO so that journald doesn't
  77        get spammed with debug messages..
  78        """
  79
  80        logging.Logger.__init__(self, name)
  81
  82        color_formatter = ColoredFormatter(self.message)
  83
  84        syslog_handler = logging.handlers.SysLogHandler(address = '/dev/log')
  85        syslog_handler.setLevel(logging.INFO)
  86        syslog_handler.setFormatter(logging.Formatter(
  87            fmt='{}[%(process)d]: (%(module)s) %(message)s'.format(__name__)))
  88
  89        console = logging.StreamHandler()
  90        console.setFormatter(color_formatter)
  91
  92        self.addHandler(console)
  93        self.addHandler(syslog_handler)
  94        return
  95
  96
  97# Initialise logger object
  98logging.setLoggerClass(ColoredLogger)
  99logger = logging.getLogger()