result from merge with gerrit

secop subdir only

Change-Id: I65ab7049719b374ae3ec0259483e7e7d16aafcd1
This commit is contained in:
2022-03-07 17:49:08 +01:00
parent dee3514065
commit bd246c5ca7
20 changed files with 760 additions and 583 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program 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 2 of the License, or (at your option) any later
@ -17,24 +17,27 @@
#
# Module authors:
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
import os
from os.path import dirname, join
from logging import DEBUG, INFO, addLevelName
import mlzlog
from secop.lib import getGeneralConfig
from secop.lib import generalConfig
from secop.datatypes import BoolType
from secop.properties import Property
OFF = 99
LOG_LEVELS = dict(mlzlog.LOGLEVELS, off=OFF)
COMLOG = 15
addLevelName(COMLOG, 'COMLOG')
assert DEBUG < COMLOG < INFO
LOG_LEVELS = dict(mlzlog.LOGLEVELS, off=OFF, comlog=COMLOG)
LEVEL_NAMES = {v: k for k, v in LOG_LEVELS.items()}
log = None
rootlogdir = None
def checkLevel(level):
def check_level(level):
try:
if isinstance(level, str):
return LOG_LEVELS[level.lower()]
@ -45,83 +48,120 @@ def checkLevel(level):
raise ValueError('%r is not a valid level' % level)
def initLogging(loglevel='info'):
global log, rootlogdir # pylint: disable-global-statement
class RemoteLogHandler(mlzlog.Handler):
"""handler for remote logging"""
def __init__(self):
super().__init__()
self.subscriptions = {} # dict[modname] of tuple(mobobj, dict [conn] of level)
loglevel = checkLevel(loglevel)
genConfig = getGeneralConfig()
rootname = genConfig.get('rootname', 'secop')
logdir = genConfig.get('logdir')
rootlogdir = join(logdir, rootname)
mlzlog.initLogging(rootname, 'debug', logdir)
for hdl in mlzlog.log.handlers:
hdl.setLevel(loglevel)
return mlzlog.log
def emit(self, record):
"""unused"""
def handle(self, record):
modname = record.name.split('.')[-1]
try:
modobj, subscriptions = self.subscriptions[modname]
except KeyError:
return
for conn, lev in subscriptions.items():
if record.levelno >= lev:
modobj.DISPATCHER.send_log_msg(
conn, modobj.name, LEVEL_NAMES[record.levelno],
record.getMessage())
def set_conn_level(self, modobj, conn, level):
level = check_level(level)
modobj, subscriptions = self.subscriptions.setdefault(modobj.name, (modobj, {}))
if level == OFF:
subscriptions.pop(conn, None)
else:
subscriptions[conn] = level
def __repr__(self):
return 'RemoteLogHandler()'
class ComlogHandler(mlzlog.LogfileHandler):
"""handler for logging communication
class LogfileHandler(mlzlog.LogfileHandler):
communication is
"""
def __init__(self, logdir, rootname, max_days=0):
self.logdir = logdir
self.rootname = rootname
self.max_days = max_days
super().__init__(logdir, rootname)
def emit(self, record):
if record.levelno != COMLOG:
super().emit(record)
def doRollover(self):
super().doRollover()
if self.max_days:
# keep only the last max_days files
with os.scandir(dirname(self.baseFilename)) as it:
files = sorted(entry.path for entry in it if entry.name != 'current')
for filepath in files[-self.max_days:]:
os.remove(filepath)
class ComLogfileHandler(LogfileHandler):
"""handler for logging communication"""
def format(self, record):
return '%s %s' % (self.formatter.formatTime(record), record.getMessage())
def doRollover(self):
super().doRollover()
max_days = getGeneralConfig().get('comlog_days', 31)
# keep only the last max_days files
with os.scandir(dirname(self.baseFilename)) as it:
files = sorted(entry.path for entry in it if entry.name != 'current')
for filepath in files[-max_days:]:
os.remove(filepath)
class HasComlog:
"""mixin for modules with comlog"""
comlog = Property('whether communication is logged ', BoolType(),
default=True, export=False)
_comLog = None
def earlyInit(self):
super().earlyInit()
if self.comlog and generalConfig.initialized and generalConfig.comlog:
self._comLog = mlzlog.Logger('COMLOG.%s' % self.name)
self._comLog.handlers[:] = []
directory = join(logger.logdir, logger.rootname, 'comlog', self.DISPATCHER.name)
self._comLog.addHandler(ComLogfileHandler(
directory, self.name, max_days=generalConfig.getint('comlog_days', 7)))
return
def comLog(self, msg, *args, **kwds):
self.log.log(COMLOG, msg, *args, **kwds)
if self._comLog:
self._comLog.info(msg, *args)
def add_comlog_handler(modobj):
global rootlogdir # pylint: disable-global-statement
comlog = getGeneralConfig().get('comlog')
if comlog:
comlog = join(rootlogdir, comlog)
modobj.log.addHandler(ComlogHandler(comlog, modobj.name))
class MainLogger:
def __init__(self):
self.log = None
self.logdir = None
self.rootname = None
self.console_handler = None
def init(self, console_level='info'):
self.rootname = generalConfig.get('logger_root', 'frappy')
# set log level to minimum on the logger, effective levels on the handlers
# needed also for RemoteLogHandler
# modified from mlzlog.initLogging
mlzlog.setLoggerClass(mlzlog.MLZLogger)
assert self.log is None
self.log = mlzlog.log = mlzlog.MLZLogger(self.rootname)
self.log.setLevel(DEBUG)
self.log.addHandler(mlzlog.ColoredConsoleHandler())
self.logdir = generalConfig.get('logdir', '/tmp/log')
if self.logdir:
logfile_days = generalConfig.getint('logfile_days')
logfile_handler = LogfileHandler(self.logdir, self.rootname, max_days=logfile_days)
if generalConfig.logfile_days:
logfile_handler.max_days = int(generalConfig.logfile_days)
logfile_handler.setLevel(LOG_LEVELS[generalConfig.get('logfile_level', 'info')])
self.log.addHandler(logfile_handler)
self.log.addHandler(RemoteLogHandler())
self.log.handlers[0].setLevel(LOG_LEVELS[console_level])
class RemoteLogHandler(mlzlog.Handler):
"""handler for remote logging"""
def __init__(self, modobj):
super().__init__()
self.subscriptions = {} # dict [conn] of level
self.modobj = modobj
self.modobj.log.addHandler(self)
self.used_by = set()
def handle(self, record, name=None):
result = False
for conn, lev in self.subscriptions.items():
if record.levelno >= lev:
msg = record.getMessage()
if self.modobj.DISPATCHER.send_log_msg(
conn, name or self.modobj.name, LEVEL_NAMES[record.levelno], msg):
result = True
if result:
return True
for master in self.used_by:
# this is an iodev, try to handle by one of our masters
if master.remoteLogHandler.handle(record, self.modobj.name):
return True
return False
def set_conn_level(self, conn, level):
level = checkLevel(level)
if level == mlzlog.DEBUG:
iodev = getattr(self.modobj, '_iodev', None)
if iodev:
# we want also to see debug messages of iodev
if iodev.remoteLogHandler is None:
iodev.remoteLogHandler = RemoteLogHandler(self)
iodev.remoteLogHandler.used_by.add(self.modobj)
level = checkLevel(level)
if level == OFF:
self.subscriptions.pop(conn, None)
else:
self.subscriptions[conn] = level
logger = MainLogger()