# -*- 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 # version. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Module authors: # Markus Zolliker # # ***************************************************************************** import os from os.path import dirname, join import mlzlog from secop.lib import getGeneralConfig OFF = 99 LOG_LEVELS = dict(mlzlog.LOGLEVELS, off=OFF) LEVEL_NAMES = {v: k for k, v in LOG_LEVELS.items()} log = None rootlogdir = None def checkLevel(level): try: if isinstance(level, str): return LOG_LEVELS[level.lower()] if level in LEVEL_NAMES: return level except KeyError: pass raise ValueError('%r is not a valid level' % level) def initLogging(loglevel='info'): global log, rootlogdir # pylint: disable-global-statement 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 class ComlogHandler(mlzlog.LogfileHandler): """handler for logging communication communication is """ 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) 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 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