OLD | NEW |
(Empty) | |
| 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 unde
r |
| 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) an
y |
| 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 logilab.common.textutils import colorize_ansi |
| 28 |
| 29 |
| 30 def set_log_methods(cls, logger): |
| 31 """bind standard logger's methods as methods on the class""" |
| 32 cls.__logger = logger |
| 33 for attr in ('debug', 'info', 'warning', 'error', 'critical', 'exception'): |
| 34 setattr(cls, attr, getattr(logger, attr)) |
| 35 |
| 36 |
| 37 def xxx_cyan(record): |
| 38 if 'XXX' in record.message: |
| 39 return 'cyan' |
| 40 |
| 41 class ColorFormatter(logging.Formatter): |
| 42 """ |
| 43 A color Formatter for the logging standard module. |
| 44 |
| 45 By default, colorize CRITICAL and ERROR in red, WARNING in orange, INFO in |
| 46 green and DEBUG in yellow. |
| 47 |
| 48 self.colors is customizable via the 'color' constructor argument (dictionary
). |
| 49 |
| 50 self.colorfilters is a list of functions that get the LogRecord |
| 51 and return a color name or None. |
| 52 """ |
| 53 |
| 54 def __init__(self, fmt=None, datefmt=None, colors=None): |
| 55 logging.Formatter.__init__(self, fmt, datefmt) |
| 56 self.colorfilters = [] |
| 57 self.colors = {'CRITICAL': 'red', |
| 58 'ERROR': 'red', |
| 59 'WARNING': 'magenta', |
| 60 'INFO': 'green', |
| 61 'DEBUG': 'yellow', |
| 62 } |
| 63 if colors is not None: |
| 64 assert isinstance(colors, dict) |
| 65 self.colors.update(colors) |
| 66 |
| 67 def format(self, record): |
| 68 msg = logging.Formatter.format(self, record) |
| 69 if record.levelname in self.colors: |
| 70 color = self.colors[record.levelname] |
| 71 return colorize_ansi(msg, color) |
| 72 else: |
| 73 for cf in self.colorfilters: |
| 74 color = cf(record) |
| 75 if color: |
| 76 return colorize_ansi(msg, color) |
| 77 return msg |
| 78 |
| 79 def set_color_formatter(logger=None, **kw): |
| 80 """ |
| 81 Install a color formatter on the 'logger'. If not given, it will |
| 82 defaults to the default logger. |
| 83 |
| 84 Any additional keyword will be passed as-is to the ColorFormatter |
| 85 constructor. |
| 86 """ |
| 87 if logger is None: |
| 88 logger = logging.getLogger() |
| 89 if not logger.handlers: |
| 90 logging.basicConfig() |
| 91 format_msg = logger.handlers[0].formatter._fmt |
| 92 fmt = ColorFormatter(format_msg, **kw) |
| 93 fmt.colorfilters.append(xxx_cyan) |
| 94 logger.handlers[0].setFormatter(fmt) |
| 95 |
| 96 |
| 97 LOG_FORMAT = '%(asctime)s - (%(name)s) %(levelname)s: %(message)s' |
| 98 LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S' |
| 99 |
| 100 def get_handler(debug=False, syslog=False, logfile=None, rotation_parameters=Non
e): |
| 101 """get an apropriate handler according to given parameters""" |
| 102 if os.environ.get('APYCOT_ROOT'): |
| 103 handler = logging.StreamHandler(sys.stdout) |
| 104 if debug: |
| 105 handler = logging.StreamHandler() |
| 106 elif logfile is None: |
| 107 if syslog: |
| 108 from logging import handlers |
| 109 handler = handlers.SysLogHandler() |
| 110 else: |
| 111 handler = logging.StreamHandler() |
| 112 else: |
| 113 try: |
| 114 if rotation_parameters is None: |
| 115 handler = logging.FileHandler(logfile) |
| 116 else: |
| 117 from logging.handlers import TimedRotatingFileHandler |
| 118 handler = TimedRotatingFileHandler( |
| 119 logfile, **rotation_parameters) |
| 120 except IOError: |
| 121 handler = logging.StreamHandler() |
| 122 return handler |
| 123 |
| 124 def get_threshold(debug=False, logthreshold=None): |
| 125 if logthreshold is None: |
| 126 if debug: |
| 127 logthreshold = logging.DEBUG |
| 128 else: |
| 129 logthreshold = logging.ERROR |
| 130 elif isinstance(logthreshold, basestring): |
| 131 logthreshold = getattr(logging, THRESHOLD_MAP.get(logthreshold, |
| 132 logthreshold)) |
| 133 return logthreshold |
| 134 |
| 135 def get_formatter(logformat=LOG_FORMAT, logdateformat=LOG_DATE_FORMAT): |
| 136 isatty = hasattr(sys.__stdout__, 'isatty') and sys.__stdout__.isatty() |
| 137 if isatty and sys.platform != 'win32': |
| 138 fmt = ColorFormatter(logformat, logdateformat) |
| 139 def col_fact(record): |
| 140 if 'XXX' in record.message: |
| 141 return 'cyan' |
| 142 if 'kick' in record.message: |
| 143 return 'red' |
| 144 fmt.colorfilters.append(col_fact) |
| 145 else: |
| 146 fmt = logging.Formatter(logformat, logdateformat) |
| 147 return fmt |
| 148 |
| 149 def init_log(debug=False, syslog=False, logthreshold=None, logfile=None, |
| 150 logformat=LOG_FORMAT, logdateformat=LOG_DATE_FORMAT, fmt=None, |
| 151 rotation_parameters=None, handler=None): |
| 152 """init the log service""" |
| 153 logger = logging.getLogger() |
| 154 if handler is None: |
| 155 handler = get_handler(debug, syslog, logfile, rotation_parameters) |
| 156 # only addHandler and removeHandler method while I would like a setHandler |
| 157 # method, so do it this way :$ |
| 158 logger.handlers = [handler] |
| 159 logthreshold = get_threshold(debug, logthreshold) |
| 160 logger.setLevel(logthreshold) |
| 161 if fmt is None: |
| 162 if debug: |
| 163 fmt = get_formatter(logformat=logformat, logdateformat=logdateformat
) |
| 164 else: |
| 165 fmt = logging.Formatter(logformat, logdateformat) |
| 166 handler.setFormatter(fmt) |
| 167 return handler |
| 168 |
| 169 # map logilab.common.logger thresholds to logging thresholds |
| 170 THRESHOLD_MAP = {'LOG_DEBUG': 'DEBUG', |
| 171 'LOG_INFO': 'INFO', |
| 172 'LOG_NOTICE': 'INFO', |
| 173 'LOG_WARN': 'WARNING', |
| 174 'LOG_WARNING': 'WARNING', |
| 175 'LOG_ERR': 'ERROR', |
| 176 'LOG_ERROR': 'ERROR', |
| 177 'LOG_CRIT': 'CRITICAL', |
| 178 } |
OLD | NEW |