cdist/cdist/log.py
Evil Ham ba77ea9edc [UX] Add option to enable LogLevel-based coloured output.
This makes it easier for new and experienced users to run cdist with higher
verbosity levels, both to know that things are working as expected and to debug
issues.

Documentation has been modified accordingly and default behaviour is not
changed.
2020-06-01 19:11:58 +02:00

165 lines
4.2 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org)
#
# This file is part of cdist.
#
# cdist is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cdist 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
import logging
import sys
import datetime
# Define additional cdist logging levels.
logging.OFF = logging.CRITICAL + 10 # disable logging
logging.addLevelName(logging.OFF, 'OFF')
logging.VERBOSE = logging.INFO - 5
logging.addLevelName(logging.VERBOSE, 'VERBOSE')
def _verbose(msg, *args, **kwargs):
logging.log(logging.VERBOSE, msg, *args, **kwargs)
logging.verbose = _verbose
logging.TRACE = logging.DEBUG - 5
logging.addLevelName(logging.TRACE, 'TRACE')
def _trace(msg, *args, **kwargs):
logging.log(logging.TRACE, msg, *args, **kwargs)
logging.trace = _trace
class ColorFormatter(logging.Formatter):
USE_COLORS = False
RESET = '\033[0m'
COLOR_MAP = {
'ERROR': '\033[0;31m',
'WARNING': '\033[0;33m',
'INFO': '\033[0;94m',
'VERBOSE': '\033[0;34m',
'DEBUG': '\033[0;90m',
'TRACE': '\033[0;37m',
}
def __init__(self, msg):
super().__init__(msg)
def format(self, record):
msg = super().format(record)
if self.USE_COLORS:
color = self.COLOR_MAP.get(record.levelname)
if color:
msg = color + msg + self.RESET
return msg
class DefaultLog(logging.Logger):
FORMAT = '%(levelname)s: %(message)s'
class StdoutFilter(logging.Filter):
def filter(self, rec):
return rec.levelno != logging.ERROR
class StderrFilter(logging.Filter):
def filter(self, rec):
return rec.levelno == logging.ERROR
def __init__(self, name):
super().__init__(name)
self.propagate = False
formatter = ColorFormatter(self.FORMAT)
self.addFilter(self)
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.addFilter(self.StdoutFilter())
stdout_handler.setLevel(logging.TRACE)
stdout_handler.setFormatter(formatter)
stderr_handler = logging.StreamHandler(sys.stderr)
stderr_handler.addFilter(self.StderrFilter())
stderr_handler.setLevel(logging.ERROR)
stderr_handler.setFormatter(formatter)
self.addHandler(stdout_handler)
self.addHandler(stderr_handler)
def filter(self, record):
"""Prefix messages with logger name"""
record.msg = self.name + ": " + str(record.msg)
return True
def verbose(self, msg, *args, **kwargs):
self.log(logging.VERBOSE, msg, *args, **kwargs)
def trace(self, msg, *args, **kwargs):
self.log(logging.TRACE, msg, *args, **kwargs)
class TimestampingLog(DefaultLog):
def filter(self, record):
"""Add timestamp to messages"""
super().filter(record)
now = datetime.datetime.now()
timestamp = now.strftime("%Y%m%d%H%M%S.%f")
record.msg = "[" + timestamp + "] " + str(record.msg)
return True
class ParallelLog(DefaultLog):
FORMAT = '%(levelname)s: [%(process)d]: %(message)s'
class TimestampingParallelLog(TimestampingLog, ParallelLog):
pass
def setupDefaultLogging():
del logging.getLogger().handlers[:]
logging.setLoggerClass(DefaultLog)
def setupTimestampingLogging():
del logging.getLogger().handlers[:]
logging.setLoggerClass(TimestampingLog)
def setupTimestampingParallelLogging():
del logging.getLogger().handlers[:]
logging.setLoggerClass(TimestampingParallelLog)
def setupParallelLogging():
del logging.getLogger().handlers[:]
logging.setLoggerClass(ParallelLog)
setupDefaultLogging()