mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Switch to rich logging
This commit is contained in:
parent
ee8fb6998c
commit
80f44c494a
2 changed files with 17 additions and 106 deletions
|
|
@ -43,7 +43,7 @@ console = Console()
|
|||
class Pelican:
|
||||
|
||||
def __init__(self, settings):
|
||||
"""Pelican initialisation
|
||||
"""Pelican initialization
|
||||
|
||||
Performs some checks on the environment before doing anything else.
|
||||
"""
|
||||
|
|
@ -500,7 +500,7 @@ def listen(server, port, output, excqueue=None):
|
|||
def main(argv=None):
|
||||
args = parse_arguments(argv)
|
||||
logs_dedup_min_level = getattr(logging, args.logs_dedup_min_level)
|
||||
init_logging(args.verbosity, args.fatal,
|
||||
init_logging(level=args.verbosity, fatal=args.fatal, name=__name__,
|
||||
logs_dedup_min_level=logs_dedup_min_level)
|
||||
|
||||
logger.debug('Pelican version: %s', __version__)
|
||||
|
|
@ -538,9 +538,9 @@ def main(argv=None):
|
|||
except KeyboardInterrupt:
|
||||
logger.warning('Keyboard interrupt received. Exiting.')
|
||||
except Exception as e:
|
||||
logger.critical('%s', e)
|
||||
logger.critical("%s: %s" % (e.__class__.__name__, e))
|
||||
|
||||
if args.verbosity == logging.DEBUG:
|
||||
raise
|
||||
console.print_exception()
|
||||
else:
|
||||
sys.exit(getattr(e, 'exitcode', 1))
|
||||
|
|
|
|||
115
pelican/log.py
115
pelican/log.py
|
|
@ -1,82 +1,13 @@
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from collections.abc import Mapping
|
||||
|
||||
from rich.logging import RichHandler
|
||||
|
||||
__all__ = [
|
||||
'init'
|
||||
]
|
||||
|
||||
|
||||
class BaseFormatter(logging.Formatter):
|
||||
def __init__(self, fmt=None, datefmt=None):
|
||||
FORMAT = '%(customlevelname)s %(message)s'
|
||||
super().__init__(fmt=FORMAT, datefmt=datefmt)
|
||||
|
||||
def format(self, record):
|
||||
customlevel = self._get_levelname(record.levelname)
|
||||
record.__dict__['customlevelname'] = customlevel
|
||||
# format multiline messages 'nicely' to make it clear they are together
|
||||
record.msg = record.msg.replace('\n', '\n | ')
|
||||
if not isinstance(record.args, Mapping):
|
||||
record.args = tuple(arg.replace('\n', '\n | ') if
|
||||
isinstance(arg, str) else
|
||||
arg for arg in record.args)
|
||||
return super().format(record)
|
||||
|
||||
def formatException(self, ei):
|
||||
''' prefix traceback info for better representation '''
|
||||
s = super().formatException(ei)
|
||||
# fancy format traceback
|
||||
s = '\n'.join(' | ' + line for line in s.splitlines())
|
||||
# separate the traceback from the preceding lines
|
||||
s = ' |___\n{}'.format(s)
|
||||
return s
|
||||
|
||||
def _get_levelname(self, name):
|
||||
''' NOOP: overridden by subclasses '''
|
||||
return name
|
||||
|
||||
|
||||
class ANSIFormatter(BaseFormatter):
|
||||
ANSI_CODES = {
|
||||
'red': '\033[1;31m',
|
||||
'yellow': '\033[1;33m',
|
||||
'cyan': '\033[1;36m',
|
||||
'white': '\033[1;37m',
|
||||
'bgred': '\033[1;41m',
|
||||
'bggrey': '\033[1;100m',
|
||||
'reset': '\033[0;m'}
|
||||
|
||||
LEVEL_COLORS = {
|
||||
'INFO': 'cyan',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'bgred',
|
||||
'DEBUG': 'bggrey'}
|
||||
|
||||
def _get_levelname(self, name):
|
||||
color = self.ANSI_CODES[self.LEVEL_COLORS.get(name, 'white')]
|
||||
if name == 'INFO':
|
||||
fmt = '{0}->{2}'
|
||||
else:
|
||||
fmt = '{0}{1}{2}:'
|
||||
return fmt.format(color, name, self.ANSI_CODES['reset'])
|
||||
|
||||
|
||||
class TextFormatter(BaseFormatter):
|
||||
"""
|
||||
Convert a `logging.LogRecord' object into text.
|
||||
"""
|
||||
|
||||
def _get_levelname(self, name):
|
||||
if name == 'INFO':
|
||||
return '->'
|
||||
else:
|
||||
return name + ':'
|
||||
|
||||
|
||||
class LimitFilter(logging.Filter):
|
||||
"""
|
||||
Remove duplicates records, and limit the number of records in the same
|
||||
|
|
@ -169,40 +100,20 @@ logging.setLoggerClass(FatalLogger)
|
|||
logging.getLogger().__class__ = FatalLogger
|
||||
|
||||
|
||||
def supports_color():
|
||||
"""
|
||||
Returns True if the running system's terminal supports color,
|
||||
and False otherwise.
|
||||
|
||||
from django.core.management.color
|
||||
"""
|
||||
plat = sys.platform
|
||||
supported_platform = plat != 'Pocket PC' and \
|
||||
(plat != 'win32' or 'ANSICON' in os.environ)
|
||||
|
||||
# isatty is not always implemented, #6223.
|
||||
is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
|
||||
if not supported_platform or not is_a_tty:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_formatter():
|
||||
if supports_color():
|
||||
return ANSIFormatter()
|
||||
else:
|
||||
return TextFormatter()
|
||||
|
||||
|
||||
def init(level=None, fatal='', handler=logging.StreamHandler(), name=None,
|
||||
def init(level=None, fatal='', handler=RichHandler(), name=None,
|
||||
logs_dedup_min_level=None):
|
||||
FatalLogger.warnings_fatal = fatal.startswith('warning')
|
||||
FatalLogger.errors_fatal = bool(fatal)
|
||||
|
||||
logger = logging.getLogger(name)
|
||||
LOG_FORMAT = "%(message)s"
|
||||
logging.basicConfig(
|
||||
level=level,
|
||||
format=LOG_FORMAT,
|
||||
datefmt="[%H:%M:%S]",
|
||||
handlers=[handler]
|
||||
)
|
||||
|
||||
handler.setFormatter(get_formatter())
|
||||
logger.addHandler(handler)
|
||||
logger = logging.getLogger(name)
|
||||
|
||||
if level:
|
||||
logger.setLevel(level)
|
||||
|
|
@ -218,9 +129,9 @@ def log_warnings():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
init(level=logging.DEBUG)
|
||||
init(level=logging.DEBUG, name=__name__)
|
||||
|
||||
root_logger = logging.getLogger()
|
||||
root_logger = logging.getLogger(__name__)
|
||||
root_logger.debug('debug')
|
||||
root_logger.info('info')
|
||||
root_logger.warning('warning')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue