You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
6.3 KiB
Python
179 lines
6.3 KiB
Python
13 years ago
|
# -*- coding: utf-8 -*-
|
||
|
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
|
||
|
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
||
|
#
|
||
|
# This file is part of logilab-common.
|
||
|
#
|
||
|
# logilab-common is free software: you can redistribute it and/or modify it under
|
||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||
|
# Software Foundation, either version 2.1 of the License, or (at your option) any
|
||
|
# later version.
|
||
|
#
|
||
|
# logilab-common is distributed in the hope that it will be useful, but WITHOUT
|
||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||
|
# details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU Lesser General Public License along
|
||
|
# with logilab-common. If not, see <http://www.gnu.org/licenses/>.
|
||
|
"""Extends the logging module from the standard library."""
|
||
|
|
||
|
__docformat__ = "restructuredtext en"
|
||
|
|
||
|
import os
|
||
|
import sys
|
||
|
import logging
|
||
|
|
||
|
from logilab.common.textutils import colorize_ansi
|
||
|
|
||
|
|
||
|
def set_log_methods(cls, logger):
|
||
|
"""bind standard logger's methods as methods on the class"""
|
||
|
cls.__logger = logger
|
||
|
for attr in ('debug', 'info', 'warning', 'error', 'critical', 'exception'):
|
||
|
setattr(cls, attr, getattr(logger, attr))
|
||
|
|
||
|
|
||
|
def xxx_cyan(record):
|
||
|
if 'XXX' in record.message:
|
||
|
return 'cyan'
|
||
|
|
||
|
class ColorFormatter(logging.Formatter):
|
||
|
"""
|
||
|
A color Formatter for the logging standard module.
|
||
|
|
||
|
By default, colorize CRITICAL and ERROR in red, WARNING in orange, INFO in
|
||
|
green and DEBUG in yellow.
|
||
|
|
||
|
self.colors is customizable via the 'color' constructor argument (dictionary).
|
||
|
|
||
|
self.colorfilters is a list of functions that get the LogRecord
|
||
|
and return a color name or None.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, fmt=None, datefmt=None, colors=None):
|
||
|
logging.Formatter.__init__(self, fmt, datefmt)
|
||
|
self.colorfilters = []
|
||
|
self.colors = {'CRITICAL': 'red',
|
||
|
'ERROR': 'red',
|
||
|
'WARNING': 'magenta',
|
||
|
'INFO': 'green',
|
||
|
'DEBUG': 'yellow',
|
||
|
}
|
||
|
if colors is not None:
|
||
|
assert isinstance(colors, dict)
|
||
|
self.colors.update(colors)
|
||
|
|
||
|
def format(self, record):
|
||
|
msg = logging.Formatter.format(self, record)
|
||
|
if record.levelname in self.colors:
|
||
|
color = self.colors[record.levelname]
|
||
|
return colorize_ansi(msg, color)
|
||
|
else:
|
||
|
for cf in self.colorfilters:
|
||
|
color = cf(record)
|
||
|
if color:
|
||
|
return colorize_ansi(msg, color)
|
||
|
return msg
|
||
|
|
||
|
def set_color_formatter(logger=None, **kw):
|
||
|
"""
|
||
|
Install a color formatter on the 'logger'. If not given, it will
|
||
|
defaults to the default logger.
|
||
|
|
||
|
Any additional keyword will be passed as-is to the ColorFormatter
|
||
|
constructor.
|
||
|
"""
|
||
|
if logger is None:
|
||
|
logger = logging.getLogger()
|
||
|
if not logger.handlers:
|
||
|
logging.basicConfig()
|
||
|
format_msg = logger.handlers[0].formatter._fmt
|
||
|
fmt = ColorFormatter(format_msg, **kw)
|
||
|
fmt.colorfilters.append(xxx_cyan)
|
||
|
logger.handlers[0].setFormatter(fmt)
|
||
|
|
||
|
|
||
|
LOG_FORMAT = '%(asctime)s - (%(name)s) %(levelname)s: %(message)s'
|
||
|
LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||
|
|
||
|
def get_handler(debug=False, syslog=False, logfile=None, rotation_parameters=None):
|
||
|
"""get an apropriate handler according to given parameters"""
|
||
|
if os.environ.get('APYCOT_ROOT'):
|
||
|
handler = logging.StreamHandler(sys.stdout)
|
||
|
if debug:
|
||
|
handler = logging.StreamHandler()
|
||
|
elif logfile is None:
|
||
|
if syslog:
|
||
|
from logging import handlers
|
||
|
handler = handlers.SysLogHandler()
|
||
|
else:
|
||
|
handler = logging.StreamHandler()
|
||
|
else:
|
||
|
try:
|
||
|
if rotation_parameters is None:
|
||
|
handler = logging.FileHandler(logfile)
|
||
|
else:
|
||
|
from logging.handlers import TimedRotatingFileHandler
|
||
|
handler = TimedRotatingFileHandler(
|
||
|
logfile, **rotation_parameters)
|
||
|
except IOError:
|
||
|
handler = logging.StreamHandler()
|
||
|
return handler
|
||
|
|
||
|
def get_threshold(debug=False, logthreshold=None):
|
||
|
if logthreshold is None:
|
||
|
if debug:
|
||
|
logthreshold = logging.DEBUG
|
||
|
else:
|
||
|
logthreshold = logging.ERROR
|
||
|
elif isinstance(logthreshold, basestring):
|
||
|
logthreshold = getattr(logging, THRESHOLD_MAP.get(logthreshold,
|
||
|
logthreshold))
|
||
|
return logthreshold
|
||
|
|
||
|
def get_formatter(logformat=LOG_FORMAT, logdateformat=LOG_DATE_FORMAT):
|
||
|
isatty = hasattr(sys.__stdout__, 'isatty') and sys.__stdout__.isatty()
|
||
|
if isatty and sys.platform != 'win32':
|
||
|
fmt = ColorFormatter(logformat, logdateformat)
|
||
|
def col_fact(record):
|
||
|
if 'XXX' in record.message:
|
||
|
return 'cyan'
|
||
|
if 'kick' in record.message:
|
||
|
return 'red'
|
||
|
fmt.colorfilters.append(col_fact)
|
||
|
else:
|
||
|
fmt = logging.Formatter(logformat, logdateformat)
|
||
|
return fmt
|
||
|
|
||
|
def init_log(debug=False, syslog=False, logthreshold=None, logfile=None,
|
||
|
logformat=LOG_FORMAT, logdateformat=LOG_DATE_FORMAT, fmt=None,
|
||
|
rotation_parameters=None, handler=None):
|
||
|
"""init the log service"""
|
||
|
logger = logging.getLogger()
|
||
|
if handler is None:
|
||
|
handler = get_handler(debug, syslog, logfile, rotation_parameters)
|
||
|
# only addHandler and removeHandler method while I would like a setHandler
|
||
|
# method, so do it this way :$
|
||
|
logger.handlers = [handler]
|
||
|
logthreshold = get_threshold(debug, logthreshold)
|
||
|
logger.setLevel(logthreshold)
|
||
|
if fmt is None:
|
||
|
if debug:
|
||
|
fmt = get_formatter(logformat=logformat, logdateformat=logdateformat)
|
||
|
else:
|
||
|
fmt = logging.Formatter(logformat, logdateformat)
|
||
|
handler.setFormatter(fmt)
|
||
|
return handler
|
||
|
|
||
|
# map logilab.common.logger thresholds to logging thresholds
|
||
|
THRESHOLD_MAP = {'LOG_DEBUG': 'DEBUG',
|
||
|
'LOG_INFO': 'INFO',
|
||
|
'LOG_NOTICE': 'INFO',
|
||
|
'LOG_WARN': 'WARNING',
|
||
|
'LOG_WARNING': 'WARNING',
|
||
|
'LOG_ERR': 'ERROR',
|
||
|
'LOG_ERROR': 'ERROR',
|
||
|
'LOG_CRIT': 'CRITICAL',
|
||
|
}
|