3
# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
5
# Permission to use, copy, modify, and distribute this software and its
6
# documentation for any purpose and without fee is hereby granted,
7
# provided that the above copyright notice appear in all copies and that
8
# both that copyright notice and this permission notice appear in
9
# supporting documentation, and that the name of Vinay Sajip
10
# not be used in advertising or publicity pertaining to distribution
11
# of the software without specific, written prior permission.
12
# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14
# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
15
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
16
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
Simple socket-based logging event receiver for use with "logging.py" logging
24
Should work under Python versions >= 1.5.2, except that source line information
25
is not available unless 'inspect' is.
27
Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
30
from select import select
31
import sys, string, struct, types, cPickle, socket
32
import logging, logging.handlers, logging.config
35
if sys.platform == "win32":
38
RESET_ERROR = 0 #FIXME get correct value for Unix...
40
logging.raiseExceptions = 1
46
from SocketServer import ThreadingTCPServer, StreamRequestHandler
48
class LogRecordStreamHandler(StreamRequestHandler):
50
Handler for a streaming logging request. It basically logs the record
51
using whatever logging policy is configured locally.
56
Handle multiple requests - each expected to be a 4-byte length,
57
followed by the LogRecord in pickle format. Logs the record
58
according to whatever policy is configured locally.
62
chunk = self.connection.recv(4)
65
slen = struct.unpack(">L", chunk)[0]
66
chunk = self.connection.recv(slen)
67
while len(chunk) < slen:
68
chunk = chunk + self.connection.recv(slen - len(chunk))
69
obj = self.unPickle(chunk)
70
record = logging.makeLogRecord(obj)
71
self.handleLogRecord(record)
72
except socket.error, e:
73
if type(e.args) != types.TupleType:
77
if errcode != RESET_ERROR:
81
def unPickle(self, data):
82
return cPickle.loads(data)
84
def handleLogRecord(self, record):
85
#if a name is specified, we use the named logger rather than the one
86
#implied by the record. This is so test harnesses don't get into
87
#endless loops (particularly log_test.py, which has this code and the
88
#client code in the same Python instance)
89
if self.server.logname is not None:
90
name = self.server.logname
93
logger = logging.getLogger(name)
96
class LogRecordSocketReceiver(ThreadingTCPServer):
98
A simple-minded TCP socket-based logging receiver suitable for test
102
allow_reuse_address = 1
104
def __init__(self, host='localhost', port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
105
handler=LogRecordStreamHandler):
106
ThreadingTCPServer.__init__(self, (host, port), handler)
111
def serve_until_stopped(self):
115
rd, wr, ex = select.select([self.socket.fileno()],
119
self.handle_request()
126
from SocketServer import ThreadingUDPServer, DatagramRequestHandler
128
class LogRecordDatagramHandler(DatagramRequestHandler):
130
Handler for a datagram logging request. It basically logs the record using
131
whatever logging policy is configured locally.
135
slen = struct.unpack(">L", chunk[:4])[0]
137
assert len(chunk) == slen
138
obj = self.unPickle(chunk)
139
record = logging.LogRecord(None, None, "", 0, "", (), None)
140
record.__dict__.update(obj)
141
self.handleLogRecord(record)
143
def unPickle(self, data):
144
return cPickle.loads(data)
146
def handleLogRecord(self, record):
147
#if a name is specified, we use the named logger rather than the one
148
#implied by the record. This is so test harnesses don't get into
149
#endless loops (particularly log_test.py, which has this code and the
150
#client code in the same Python instance)
151
if self.server.logname is not None:
152
name = self.server.logname
155
logger = logging.getLogger(name)
156
logger.handle(record)
161
class LogRecordDatagramReceiver(ThreadingUDPServer):
163
A simple-minded UDP datagram-based logging receiver suitable for test
167
allow_reuse_address = 1
169
def __init__(self, host='localhost', port=logging.handlers.DEFAULT_UDP_LOGGING_PORT,
170
handler=LogRecordDatagramHandler):
171
ThreadingUDPServer.__init__(self, (host, port), handler)
176
def serve_until_stopped(self):
180
rd, wr, ex = select.select([self.socket.fileno()],
184
self.handle_request()
191
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
195
class LogRecordHTTPHandler(BaseHTTPRequestHandler):
196
def makeDict(self, fs):
199
dict[mfs.name] = mfs.value
200
for key in ["args", "exc_info", "exc_text", "lineno", "msecs", "created",
201
"thread", "levelno", "relativeCreated"]:
202
if dict.has_key(key):
203
dict[key] = eval(dict[key])
207
"""Serve a GET request."""
209
env = { 'REQUEST_METHOD' : 'GET'}
211
i = string.find(self.path, '?')
213
env['QUERY_STRING'] = self.path[i + 1:]
214
fs = cgi.FieldStorage(environ=env)
215
dict = self.makeDict(fs)
216
record = logging.LogRecord(None, None, "", 0, "", (), None)
217
record.__dict__.update(dict)
218
self.handleLogRecord(record)
223
self.wfile.write("GET %s" % sts)
225
def handleLogRecord(self, record):
226
#if a name is specified, we use the named logger rather than the one
227
#implied by the record. This is so test harnesses don't get into
228
#endless loops (particularly log_test.py, which has this code and the
229
#client code in the same Python instance)
230
if self.server.logname is not None:
231
name = self.server.logname
234
logger = logging.getLogger(name)
235
logger.handle(record)
238
"""Serve a HEAD request."""
242
"""Serve a POST request."""
244
env = { 'REQUEST_METHOD' : 'POST'}
246
length = self.headers.getheader('content-length')
248
env['CONTENT_LENGTH'] = length
250
i = string.find(self.path, '?')
252
env['QUERY_STRING'] = self.path[i + 1:]
253
fs = cgi.FieldStorage(fp=self.rfile, environ=env)
254
dict = self.makeDict(fs)
255
record = logging.LogRecord(None, None, "", 0, "", (), None)
256
record.__dict__.update(dict)
257
self.handleLogRecord(record)
264
self.wfile.write("POST %s" % sts)
267
"""Common code for GET and HEAD commands.
269
This sends the response code and MIME headers.
271
Return value is either a file object (which has to be copied
272
to the outputfile by the caller unless the command was HEAD,
273
and must be closed by the caller under all circumstances), or
274
None, in which case the caller has nothing further to do.
277
self.send_response(200)
278
self.send_header("Content-type", "text/plain")
281
def log_message(self, *args):
282
#comment out the following line if you don't want to show requests
283
#apply(BaseHTTPRequestHandler.log_message, (self,) + args)
286
class LogRecordHTTPReceiver(HTTPServer):
287
def __init__(self, host='localhost', port=logging.handlers.DEFAULT_HTTP_LOGGING_PORT,
288
handler=LogRecordHTTPHandler):
289
HTTPServer.__init__(self, (host, port), handler)
294
def serve_until_stopped(self):
298
rd, wr, ex = select.select([self.socket.fileno()],
302
self.handle_request()
311
from ZSI import dispatch
315
def log(args, created, exc_info, exc_text, filename, levelname, levelno, lineno, module, msecs, msg, name, pathname, process, relativeCreated, thread):
316
record = logging.LogRecord(None, None, "", 0, "", (), None)
317
record.args = eval(args)
318
record.exc_info = eval(exc_info)
319
record.exc_text = eval(exc_text)
320
record.created = created
321
record.filename = filename
322
record.module = module
323
record.levelname = levelname
324
record.lineno = lineno
325
record.levelno = levelno
329
record.pathname = pathname
330
record.process = process
331
record.relativeCreated = relativeCreated
332
record.thread = thread
333
#if a name is specified, we use the named logger rather than the one
334
#implied by the record. This is so test harnesses don't get into
335
#endless loops (particularly log_test.py, which has this code and the
336
#client code in the same Python instance)
337
if logname is not None:
341
logger = logging.getLogger(lname)
342
logger.handle(record)
344
class MySOAPRequestHandler(dispatch.SOAPRequestHandler):
345
def log_message(self, *args):
346
#comment out the following line if you don't want to show requests
347
#apply(BaseHTTPRequestHandler.log_message, (self,) + args)
350
class SOAPServer(HTTPServer):
351
def __init__(self, port=logging.handlers.DEFAULT_SOAP_LOGGING_PORT):
353
HTTPServer.__init__(self, address, MySOAPRequestHandler)
359
self.typesmodule = None
361
self.modules = (sys.modules["__main__"],)
363
def serve_until_stopped(self):
367
rd, wr, ex = select.select([self.socket.fileno()],
372
logname = self.logname
373
self.handle_request()
380
def runTCP(tcpserver=None):
382
tcpserver = LogRecordSocketReceiver()
383
print "About to start TCP server..."
384
tcpserver.serve_until_stopped()
386
def runUDP(udpserver=None):
388
udpserver = LogRecordDatagramReceiver()
389
print "About to start UDP server..."
390
udpserver.serve_until_stopped()
392
def runHTTP(httpserver=None):
394
httpserver = LogRecordHTTPReceiver()
395
print "About to start HTTP server..."
396
httpserver.serve_until_stopped()
398
def runSOAP(soapserver=None):
400
print "Sorry, ZSI is not available. Install PyXML-0.6.6 and ZSI first."
401
print "See README.txt and python_logging.html for more information."
404
soapserver = SOAPServer()
405
print "About to start SOAP server..."
406
soapserver.serve_until_stopped()
408
FORMAT_STR = "%(asctime)s %(name)-19s %(levelname)-5s - %(message)s"
410
if __name__ == "__main__":
411
if (len(sys.argv) < 2) or not (string.lower(sys.argv[1]) in \
412
["udp", "tcp", "http", "soap"]):
413
print "usage: logrecv.py [UDP|TCP|HTTP|SOAP]"
415
#logging.basicConfig()
416
logging.config.fileConfig("logrecv.ini")
417
# both = string.lower(sys.argv[1]) == "both"
418
# hdlr = logging.FileHandler("test.log")
419
# hdlr.setFormatter(logging.Formatter(FORMAT_STR))
420
# logging.getLogger("").addHandler(hdlr)
423
# tcpthread = threading.Thread(target=runTCP)
424
# udpthread = threading.Thread(target=runUDP)
430
# tcp = string.lower(sys.argv[1]) == "tcp"
435
arg = string.lower(sys.argv[1])