commit eb14765ab34352cabcd51387403c0863b72c126e
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Tue Oct 2 13:42:10 2012 +0200
logging: add new file LoggingHandler
This file defines a new class ServerHandler. This class is a logging
handler and therefore is a decendant of the class logging.Handler.
This new class contains a TCP server socket listening on a specified
port. Until an incoming connection is recieved emitted messages are
stored in a buffer. After recieving a connection the stored messages are
all sent to the client and the buffer is flushed.
To avoid using threads or a new process for this server, the server
socket is created as nonblocking and we check for incoming connections
only when a new log message is emitted.
This handler was created because there is no suitable alternative for
this functionality in the python standard library. However this handler
is inspired by the SocketHandler and uses some of it's code.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Common/LoggingHandler.py | 108 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 108 insertions(+), 0 deletions(-)
---
diff --git a/Common/LoggingHandler.py b/Common/LoggingHandler.py
new file mode 100644
index 0000000..9b08f9d
--- /dev/null
+++ b/Common/LoggingHandler.py
@@ -0,0 +1,108 @@
+"""
+Server-like logging handler.
+Stores logged messages in a buffer. Every time a new message is emitted it
+checks for incoming connections. If a connection is established it flushes the
+messages stored in the buffer to the connecting client.
+
+Copyright 2012 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__autor__ = """
+olichtne(a)redhat.com (Ondrej Lichtner)
+"""
+
+import socket, struct, pickle
+import logging
+
+DEFAULT_LOG_PORT = 9998
+
+class ServerHandler(logging.Handler):
+ def __init__(self, port=DEFAULT_LOG_PORT):
+ logging.Handler.__init__(self)
+ self.port = port
+
+ self.sock = None
+ self.buf = []
+
+ self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.server_socket.setblocking(0)
+ self.server_socket.bind(('0.0.0.0', self.port))
+ self.server_socket.listen(1)
+
+ def makePickle(self, record):
+ """
+ Pickles the record in binary format with a length prefix, and
+ returns it ready for transmission across the socket.
+
+ Function taken from class SocketHandler from standard python
+ library logging.handlers
+ """
+ d = dict(record.__dict__)
+ d['msg'] = record.getMessage()
+ d['args'] = None
+ d['exc_info'] = None
+ s = pickle.dumps(d, 1)
+ slen = struct.pack(">L", len(s))
+ return slen + s
+
+ def emit(self, record):
+ try:
+ s = self.makePickle(record)
+ self.buf.append(s)
+ self.send_all()
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ logging.Handler.handleError(self, record)
+
+ def client_connection(self):
+ if self.sock == None:
+ try:
+ self.sock = self.server_socket.accept()[0]
+ return True
+ except:
+ self.sock = None
+ return False
+ else:
+ return True
+
+ def send_all(self):
+ if self.client_connection():
+ sent = len(self.buf)
+ for record in self.buf:
+ if not self.send(record):
+ sent = self.buf.index(record)
+ break
+
+ self.buf = self.buf[sent:]
+
+ def send(self, record):
+ try:
+ if hasattr(self.sock, "sendall"):
+ self.sock.sendall(record)
+ else:
+ sentsofar = 0
+ left = len(record)
+ while left > 0:
+ sent = self.sock.send(record[sentsofar:])
+ sentsofar = sentsofar + sent
+ left = left - sent
+ return True
+ except socket.error:
+ self.sock.close()
+ self.sock = None
+ return False
+
+ def close(self):
+ if self.sock:
+ self.sock.close()
+ self.sock = None
+
+ self.server_socket.close()
+ self.server_socket = None
+
+ self.buf = []
+
+ logging.Handler.close(self)
Show replies by date