-
Notifications
You must be signed in to change notification settings - Fork 1
/
loggingprotocol.py
172 lines (149 loc) · 6.81 KB
/
loggingprotocol.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
'''
This module defines the logging protocol the server receives network messages
from the logging client. Where logging.handlers.SocketHandler
is the client side of a network based Python logging solution, this
provides the server side interface for what the SocketHandler module
produces.
'''
# python system modules
import logging
import logging.config
import cPickle # use cPickle for speed
import struct
from ConfigParser import ConfigParser
# third party system modules
import twisted
from twisted.application import service, internet
from twisted.internet import protocol
from twisted.web import resource, server as webserver
# local modules
from loggingwebpage import htmlpage
from loggingmodel import model
class LoggingProtocol(twisted.internet.protocol.Protocol):
'''This class encapsulates the actual handling of the data
received by the protocol. It builds up the message till it can
peel off a log message, and then calls the defined
logger.handle() so the Python logging system can then handle
the message.
'''
LONG_INT_LENGTH = 4
def __init__(self):
'''Constructor for our derived Protocol class. This configures
the logging system for the server and sets up some instance
variables.
'''
# configure the logging system
logging.config.fileConfig('loggingserver.conf',
{"processlog" : "process.log"})
self._logger = logging.getLogger("logging server")
self._buffer = ""
def dataReceived(self, data):
'''This method accumulates the data received till
we have a complete log message. Then it pulls the log message
out and to logger.handle as a logrecord. This
method is called by the Protocol parent class when data is
received from the socket attached to this protocol. This
method has to handle possible multiple messages per buffer
and partial messages per buffer.
Parameters:
data string of data received by the socket this
server is attached to contains the data sent
by logging.handlers.SocketHandler
'''
logRecord = None
# get an alias to the LONG_INT_LENGTH
long_int_length = LoggingProtocol.LONG_INT_LENGTH
# paste the recieved data onto what we have
self._buffer += data
# keep processing the buffer till we need more data
done = False
while not done:
# do we have enough data to pull off the leading big
# endian long integer?
if len(self._buffer) >= long_int_length:
length = struct.unpack(">L", \
self._buffer[:long_int_length])[0]
# do we have the complete logging message?
if len(self._buffer) >= long_int_length + length:
# get the pickled log message
logPickle = self._buffer[long_int_length : long_int_length + length]
logRecord = logging.makeLogRecord(cPickle.loads(logPickle))
# do we have a logrecord?, then handle it
if logRecord:
self._logger.handle(logRecord)
model.logRecordHandler(logRecord)
# update the class buffer with what we have left
self._buffer = self._buffer[long_int_length + length:]
# otherwise, we don't have a complete message
else:
done = True
# otherwise, don't have enough data for length value
else:
done = True
def connectionLost(self, reason):
self._buffer = ""
def handle_quit(self):
self.transport.loseConnection()
class LoggingFactory(twisted.internet.protocol.Factory):
'''This factory creates the loggingProtocol when built'''
protocol = LoggingProtocol
class LoggingService(twisted.application.internet.TCPServer):
'''This class encapsulates our TCP service, tying it to a
port number and to the protocol that will handle the received
messages, in this case an instance of LoggingProtocol
'''
def __init__(self):
twisted.application.internet.TCPServer.__init__(self,
logging.handlers.DEFAULT_TCP_LOGGING_PORT,
LoggingFactory())
self.setName("Logging Server")
class LoggingServerWebResource(twisted.web.resource.Resource):
'''This class defines the entry point for the logging server
status home page. This page provides a view of what's going
on inside the logging server.
'''
def render_GET(self, request):
formatter = logging.Formatter(
fmt="%(asctime)s %(name)-12s %(levelname)-8s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S")
data = {}
data["starttime"] = model.starttime
data["uptime"] = model.uptime
data["logrecordstotal"] = model.logRecordsTotal
# create list of all log records
html = '''<tr class="%s"><td>%s</td></tr>'''
rows = []
for logrecord in model:
if logrecord.levelno == logging.CRITICAL:
rows.append(html % ("critical",
formatter.format(
logrecord).replace(' ', ' ')))
if logrecord.levelno == logging.ERROR:
rows.append(html % ("error",
formatter.format(
logrecord).replace(' ', ' ')))
if logrecord.levelno == logging.WARN:
rows.append(html % ("warn",
formatter.format(
logrecord).replace(' ', ' ')))
if logrecord.levelno == logging.INFO:
rows.append(html % ("info",
formatter.format(
logrecord).replace(' ', ' ')))
if logrecord.levelno == logging.DEBUG:
rows.append(html % ("debug",
formatter.format(
logrecord).replace(' ', ' ')))
data["all"] = ''.join(rows)
return (htmlpage % data).encode('utf-8')
class LoggingServerWebService(twisted.application.internet.TCPServer):
'''This class encapsulates the createion of the TCP service that
provides the HTTP webserver for the logging servers status page.
'''
def __init__(self):
webRoot = twisted.web.resource.Resource()
webRoot.putChild('', LoggingServerWebResource())
site = twisted.web.server.Site(webRoot)
internet.TCPServer.__init__(self,
logging.handlers.DEFAULT_TCP_LOGGING_PORT + 1, site)
self.setName("Logging Server Web Server")