Package logilab :: Package common :: Module logging_ext

[frames] | no frames]

# Source Code for Module logilab.common.logging_ext

      1  # -*- coding: utf-8 -*-
      2  # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
      3  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
      4  #
      5  # This file is part of logilab-common.
      6  #
      7  # logilab-common is free software: you can redistribute it and/or modify it under
      8  # the terms of the GNU Lesser General Public License as published by the Free
      9  # Software Foundation, either version 2.1 of the License, or (at your option) any
     10  # later version.
     11  #
     12  # logilab-common is distributed in the hope that it will be useful, but WITHOUT
     13  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     14  # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
     15  # details.
     16  #
     17  # You should have received a copy of the GNU Lesser General Public License along
     18  # with logilab-common.  If not, see <http://www.gnu.org/licenses/>.
     19  """Extends the logging module from the standard library."""
     20
     21  __docformat__ = "restructuredtext en"
     22
     23  import os
     24  import sys
     25  import logging
     26
     27  from six import string_types
     28
     29  from logilab.common.textutils import colorize_ansi
     30
     31
     32 -def set_log_methods(cls, logger):
     33      """bind standard logger's methods as methods on the class"""
     34      cls.__logger = logger
     35      for attr in ('debug', 'info', 'warning', 'error', 'critical', 'exception'):
     36          setattr(cls, attr, getattr(logger, attr))
     37
     38
     39 -def xxx_cyan(record):
     40      if 'XXX' in record.message:
     41          return 'cyan'
     42
     43 -class ColorFormatter(logging.Formatter):
     44      """
     45      A color Formatter for the logging standard module.
     46
     47      By default, colorize CRITICAL and ERROR in red, WARNING in orange, INFO in
     48      green and DEBUG in yellow.
     49
     50      self.colors is customizable via the 'color' constructor argument (dictionary).
     51
     52      self.colorfilters is a list of functions that get the LogRecord
     53      and return a color name or None.
     54      """
     55
     56 -    def __init__(self, fmt=None, datefmt=None, colors=None):
     57          logging.Formatter.__init__(self, fmt, datefmt)
     58          self.colorfilters = []
     59          self.colors = {'CRITICAL': 'red',
     60                         'ERROR': 'red',
     61                         'WARNING': 'magenta',
     62                         'INFO': 'green',
     63                         'DEBUG': 'yellow',
     64                         }
     65          if colors is not None:
     66              assert isinstance(colors, dict)
     67              self.colors.update(colors)
     68
     69 -    def format(self, record):
     70          msg = logging.Formatter.format(self, record)
     71          if record.levelname in self.colors:
     72              color = self.colors[record.levelname]
     73              return colorize_ansi(msg, color)
     74          else:
     75              for cf in self.colorfilters:
     76                  color = cf(record)
     77                  if color:
     78                      return colorize_ansi(msg, color)
     79          return msg
     80
     81 -def set_color_formatter(logger=None, **kw):
     82      """
     83      Install a color formatter on the 'logger'. If not given, it will
     84      defaults to the default logger.
     85
     86      Any additional keyword will be passed as-is to the ColorFormatter
     87      constructor.
     88      """
     89      if logger is None:
     90          logger = logging.getLogger()
     91          if not logger.handlers:
     92              logging.basicConfig()
     93      format_msg = logger.handlers[0].formatter._fmt
     94      fmt = ColorFormatter(format_msg, **kw)
     95      fmt.colorfilters.append(xxx_cyan)
     96      logger.handlers[0].setFormatter(fmt)
     97
     98
     99  LOG_FORMAT = '%(asctime)s - (%(name)s) %(levelname)s: %(message)s'
    100  LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
    101
    102 -def get_handler(debug=False, syslog=False, logfile=None, rotation_parameters=None):
    103      """get an apropriate handler according to given parameters"""
    104      if os.environ.get('APYCOT_ROOT'):
    105          handler = logging.StreamHandler(sys.stdout)
    106      if debug:
    107          handler = logging.StreamHandler()
    108      elif logfile is None:
    109          if syslog:
    110              from logging import handlers
    111              handler = handlers.SysLogHandler()
    112          else:
    113              handler = logging.StreamHandler()
    114      else:
    115          try:
    116              if rotation_parameters is None:
    117                  if os.name == 'posix' and sys.version_info >= (2, 6):
    118                      from logging.handlers import WatchedFileHandler
    119                      handler = WatchedFileHandler(logfile)
    120                  else:
    121                      handler = logging.FileHandler(logfile)
    122              else:
    123                  from logging.handlers import TimedRotatingFileHandler
    124                  handler = TimedRotatingFileHandler(
    125                      logfile, **rotation_parameters)
    126          except IOError:
    127              handler = logging.StreamHandler()
    128      return handler
    129
    130 -def get_threshold(debug=False, logthreshold=None):
    131      if logthreshold is None:
    132          if debug:
    133              logthreshold = logging.DEBUG
    134          else:
    135              logthreshold = logging.ERROR
    136      elif isinstance(logthreshold, string_types):
    137          logthreshold = getattr(logging, THRESHOLD_MAP.get(logthreshold,
    138                                                            logthreshold))
    139      return logthreshold
    140
    141 -def _colorable_terminal():
    142      isatty = hasattr(sys.__stdout__, 'isatty') and sys.__stdout__.isatty()
    143      if not isatty:
    144          return False
    145      if os.name == 'nt':
    146          try:
    147              from colorama import init as init_win32_colors
    148          except ImportError:
    149              return False
    150          init_win32_colors()
    151      return True
    152
    153 -def get_formatter(logformat=LOG_FORMAT, logdateformat=LOG_DATE_FORMAT):
    154      if _colorable_terminal():
    155          fmt = ColorFormatter(logformat, logdateformat)
    156          def col_fact(record):
    157              if 'XXX' in record.message:
    158                  return 'cyan'
    159              if 'kick' in record.message:
    160                  return 'red'
    161          fmt.colorfilters.append(col_fact)
    162      else:
    163          fmt = logging.Formatter(logformat, logdateformat)
    164      return fmt
    165
    166 -def init_log(debug=False, syslog=False, logthreshold=None, logfile=None,
    167               logformat=LOG_FORMAT, logdateformat=LOG_DATE_FORMAT, fmt=None,
    168               rotation_parameters=None, handler=None):
    169      """init the log service"""
    170      logger = logging.getLogger()
    171      if handler is None:
    172          handler = get_handler(debug, syslog, logfile, rotation_parameters)
    173      # only addHandler and removeHandler method while I would like a setHandler
    174      # method, so do it this way :$
    175      logger.handlers = [handler]
    176      logthreshold = get_threshold(debug, logthreshold)
    177      logger.setLevel(logthreshold)
    178      if fmt is None:
    179          if debug:
    180              fmt = get_formatter(logformat=logformat, logdateformat=logdateformat)
    181          else:
    182              fmt = logging.Formatter(logformat, logdateformat)
    183      handler.setFormatter(fmt)
    184      return handler
    185
    186  # map logilab.common.logger thresholds to logging thresholds
    187  THRESHOLD_MAP = {'LOG_DEBUG':   'DEBUG',
    188                   'LOG_INFO':    'INFO',
    189                   'LOG_NOTICE':  'INFO',
    190                   'LOG_WARN':    'WARNING',
    191                   'LOG_WARNING': 'WARNING',
    192                   'LOG_ERR':     'ERROR',
    193                   'LOG_ERROR':   'ERROR',
    194                   'LOG_CRIT':    'CRITICAL',
    195                   }
    196