128 lines
4.2 KiB
Python
128 lines
4.2 KiB
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
|
|
# 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 <markus.zolliker@psi.ch>
|
|
#
|
|
# *****************************************************************************
|
|
|
|
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
|