Source code for lclib.logs
"""
Logging manager
This file is part of lab-control-lib
(c) 2023-2024 Pierre Thibault (pthibault@units.it)
"""
import logging
import logging.config
import logging.handlers
import zmq
import json
import threading
import time
import datetime
from .util import Future
# This adds another debug level but it is not well managed by
# zmq.logs.PubHandler so for now not used.
"""
VERBOSE_NUM = 5
logging.addLevelName(VERBOSE_NUM, "VERBOSE")
def verbose(self, message, *args, **kws):
if self.isEnabledFor(VERBOSE_NUM):
# Yes, logger takes its '*args' as 'args'.
self._log(VERBOSE_NUM, message, args, **kws)
logging.Logger.verbose = verbose
"""
# Basic config
DEFAULT_LOGGING = {
'version': 1,
'disable_existing_loggers': False
}
# This is overwritten by init()
log_dir = None
logging.config.dictConfig(DEFAULT_LOGGING)
# Create root logger
logger = logging.getLogger(__package__.split('.')[0])
# Do not reach root handler
logger.propagate = False
# Custom formatter
[docs]
class DualFormatter(logging.Formatter):
"""
Use "extented format" if logger level is DEBUG or below.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.default_formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s",
"%d/%m/%Y %H:%M:%S")
self.extended_formatter = logging.Formatter(
"[%(asctime)s.%(msecs)03d] [%(levelname)s] [%(name)s] [%(funcName)s():%(lineno)s] [PID:%(process)d TID:%(thread)d] %(message)s",
"%d/%m/%Y %H:%M:%S")
[docs]
def format(self, record):
level = logging.getLogger(record.name).getEffectiveLevel()
if level <= logging.DEBUG:
return self.extended_formatter.format(record)
else:
return self.default_formatter.format(record)
[docs]
class JsonFormatter(logging.Formatter):
"""
Format a record as JSON encoded.
"""
[docs]
def format(self, record):
keys = ['created',
'exc_text',
'filename',
'funcName',
'levelname',
'levelno',
'lineno',
'message',
'module',
'msecs',
'name',
'pathname',
'process',
'processName',
'relativeCreated',
'thread',
'threadName',
'msg']
d = {k: getattr(record, k, None) for k in keys}
return json.dumps(d)
dual_formatter = DualFormatter()
json_formatter = JsonFormatter()
# Console logging
console_handler = logging.StreamHandler()
console_handler.setFormatter(dual_formatter)
logger.addHandler(console_handler)
[docs]
def log_to_file(log_file_name):
# File logging
file_handler = logging.handlers.RotatingFileHandler(log_file_name, maxBytes=1024 * 1024 * 10, backupCount=300,
encoding='utf-8')
file_handler.setFormatter(dual_formatter)
file_handler.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
# Tell matplotlib to shut up even on debug mode
matplotlib_logger = logging.getLogger('matplotlib')
matplotlib_logger.setLevel(logging.INFO)
[docs]
class logging_muted:
def __enter__(self):
logging.disable(logging.CRITICAL)
def __exit__(self, exit_type, exit_value, exit_traceback):
logging.disable(logging.NOTSET)