Source code for taurus.core.util.remotelogmonitor

#!/usr/bin/env python

# ###########################################################################
#
# This file is part of Taurus
#
# http://taurus-scada.org
#
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
#
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Taurus 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
#
# ###########################################################################

"""Useful module for remote logging
"""

import time
import socket
import pickle
import logging
import logging.handlers
import struct
import weakref
import click

import socketserver

import taurus.cli.common


__all__ = ["LogRecordStreamHandler", "LogRecordSocketReceiver", "log"]


[docs]class LogRecordStreamHandler(socketserver.StreamRequestHandler):
[docs] def handle(self): try: return self._handle() except Exception: pass
def _handle(self): self._stop = stop = 0 self.hostName = self.server.hostName self.server.registerHandler(self) while not stop: chunk = self.connection.recv(4) if len(chunk) < 4: break slen = struct.unpack(">L", chunk)[0] chunk = self.connection.recv(slen) while len(chunk) < slen: chunk = chunk + self.connection.recv(slen - len(chunk)) obj = self.unPickle(chunk) record = self.makeLogRecord(obj) self.handleLogRecord(record) stop = self._stop
[docs] def unPickle(self, data): return pickle.loads(data)
[docs] def makeLogRecord(self, obj): record = logging.makeLogRecord(obj) if not hasattr(record, "hostName"): record.hostName = self.hostName return record
[docs] def handleLogRecord(self, record): logger = self.server.data.get("logger") if logger is None: logger = logging.getLogger(record.name) if not logger.isEnabledFor(record.levelno): return logger.handle(record)
[docs] def stop(self): self._stop = 1
[docs]class LogRecordSocketReceiver(socketserver.ThreadingTCPServer): """ Simple TCP socket-based logging receiver suitable for testing. """ allow_reuse_address = 1 daemon_threads = True def __init__( self, host="localhost", port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, handler=LogRecordStreamHandler, **kwargs ): socketserver.ThreadingTCPServer.__init__(self, (host, port), handler) self.hostName = socket.gethostbyaddr(host)[0] self.port = port self._stop = 0 self._stopped = 0 self.timeout = 1 self.data = kwargs self.__handlers = []
[docs] def registerHandler(self, handler): if handler is not None: self.__handlers.append(weakref.ref(handler))
[docs] def unregisterHandler(self, handler): try: self.__handlers.remove(handler) except ValueError: pass
[docs] def serve_until_stopped(self): import select stop = 0 while not stop: rd, wr, ex = select.select( [self.socket.fileno()], [], [], self.timeout ) if rd: self.handle_request() stop = self._stop self._stopped = 1
[docs] def stop(self): self._stop = True while not self._stopped: time.sleep(0.1) for handler in self.__handlers: h = handler() if h is not None: h.stop() h.finish() self.close_request(h.connection) self.socket.close()
class LogNameFilter(logging.Filter): def __init__(self, name=None): self.name = name def filter(self, record): name = self.name if name is None: return True return record.name == name
[docs]def log(host, port, name=None, level=None): local_logger_name = "RemoteLogger.%s.%d" % (host, port) local_logger = logging.getLogger(local_logger_name) if name is not None: local_logger.addFilter(LogNameFilter(name=name)) if level is not None: local_logger.setLevel(level) tcpserver = LogRecordSocketReceiver( host=host, port=port, logger=local_logger ) msg = "logging for '%s' on port %d" % (host, port) if name is not None: msg += " for " + name print("Start", msg) try: tcpserver.serve_until_stopped() except KeyboardInterrupt: print("\nCancelled", msg)
@click.command("logmon") @click.option( "--port", "port", type=int, default=logging.handlers.DEFAULT_TCP_LOGGING_PORT, show_default=True, help="Port where log server is running", ) @click.option( "--log-name", "log_name", default=None, help="Filter specific log object", ) @taurus.cli.common.log_level def logmon_cmd(port, log_name, log_level): """Show the console-based Taurus Remote Log Monitor""" import taurus host = socket.gethostname() level = getattr(taurus, log_level.capitalize(), taurus.Trace) log(host=host, port=port, name=log_name, level=level) if __name__ == "__main__": logmon_cmd()