summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVinay Sajip <vinay_sajip@yahoo.co.uk>2004-02-20 13:17:27 (GMT)
committerVinay Sajip <vinay_sajip@yahoo.co.uk>2004-02-20 13:17:27 (GMT)
commit48cfe38e799394e2fdf81d95af3bdbfaf8e01360 (patch)
treeb538798d0360cc3a58c00ef6743005132de31ff4
parent326441e72eb9dfb621b31e3705fccd3651347e20 (diff)
downloadcpython-48cfe38e799394e2fdf81d95af3bdbfaf8e01360.zip
cpython-48cfe38e799394e2fdf81d95af3bdbfaf8e01360.tar.gz
cpython-48cfe38e799394e2fdf81d95af3bdbfaf8e01360.tar.bz2
Copyright year change.
Corrections to comments. Tracebacks can now be sent via SocketHandler. SocketHandler now uses exponential backoff strategy. Handlers now chain to Handler.close() from their close() methods.
-rw-r--r--Lib/logging/handlers.py84
1 files changed, 67 insertions, 17 deletions
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 26ca8ad..c556f1a 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -19,9 +19,9 @@ Logging package for Python. Based on PEP 282 and comments thereto in
comp.lang.python, and influenced by Apache's log4j system.
Should work under Python versions >= 1.5.2, except that source line
-information is not available unless 'inspect' is.
+information is not available unless 'sys._getframe()' is.
-Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging' and log away!
"""
@@ -132,6 +132,13 @@ class SocketHandler(logging.Handler):
self.port = port
self.sock = None
self.closeOnError = 0
+ self.retryTime = None
+ #
+ # Exponential backoff parameters.
+ #
+ self.retryStart = 1.0
+ self.retryMax = 30.0
+ self.retryFactor = 2.0
def makeSocket(self):
"""
@@ -142,6 +149,34 @@ class SocketHandler(logging.Handler):
s.connect((self.host, self.port))
return s
+ def createSocket(self):
+ """
+ Try to create a socket, using an exponential backoff with
+ a max retry time. Thanks to Robert Olson for the original patch
+ (SF #815911) which has been slightly refactored.
+ """
+ now = time.time()
+ # Either retryTime is None, in which case this
+ # is the first time back after a disconnect, or
+ # we've waited long enough.
+ if self.retryTime is None:
+ attempt = 1
+ else:
+ attempt = (now >= self.retryTime)
+ if attempt:
+ try:
+ self.sock = self.makeSocket()
+ self.retryTime = None # next time, no delay before trying
+ except:
+ #Creation failed, so set the retry time and return.
+ if self.retryTime is None:
+ self.retryPeriod = self.retryStart
+ else:
+ self.retryPeriod = self.retryPeriod * self.retryFactor
+ if self.retryPeriod > self.retryMax:
+ self.retryPeriod = self.retryMax
+ self.retryTime = now + self.retryPeriod
+
def send(self, s):
"""
Send a pickled string to the socket.
@@ -149,24 +184,38 @@ class SocketHandler(logging.Handler):
This function allows for partial sends which can happen when the
network is busy.
"""
- if hasattr(self.sock, "sendall"):
- self.sock.sendall(s)
- else:
- sentsofar = 0
- left = len(s)
- while left > 0:
- sent = self.sock.send(s[sentsofar:])
- sentsofar = sentsofar + sent
- left = left - sent
+ if self.sock is None:
+ self.createSocket()
+ #self.sock can be None either because we haven't reached the retry
+ #time yet, or because we have reached the retry time and retried,
+ #but are still unable to connect.
+ if self.sock:
+ try:
+ if hasattr(self.sock, "sendall"):
+ self.sock.sendall(s)
+ else:
+ sentsofar = 0
+ left = len(s)
+ while left > 0:
+ sent = self.sock.send(s[sentsofar:])
+ sentsofar = sentsofar + sent
+ left = left - sent
+ except socket.error:
+ self.sock.close()
+ self.sock = None # so we can call createSocket next time
def makePickle(self, record):
"""
Pickles the record in binary format with a length prefix, and
returns it ready for transmission across the socket.
"""
+ ei = record.exc_info
+ if ei:
+ dummy = self.format(record) # just to get traceback text into record.exc_text
+ record.exc_info = None # to avoid Unpickleable error
s = cPickle.dumps(record.__dict__, 1)
- #n = len(s)
- #slen = "%c%c" % ((n >> 8) & 0xFF, n & 0xFF)
+ if ei:
+ record.exc_info = ei # for next handler
slen = struct.pack(">L", len(s))
return slen + s
@@ -195,8 +244,6 @@ class SocketHandler(logging.Handler):
"""
try:
s = self.makePickle(record)
- if not self.sock:
- self.sock = self.makeSocket()
self.send(s)
except:
self.handleError(record)
@@ -208,6 +255,7 @@ class SocketHandler(logging.Handler):
if self.sock:
self.sock.close()
self.sock = None
+ logging.Handler.close(self)
class DatagramHandler(SocketHandler):
"""
@@ -386,6 +434,7 @@ class SysLogHandler(logging.Handler):
"""
if self.unixsocket:
self.socket.close()
+ logging.Handler.close(self)
def emit(self, record):
"""
@@ -580,7 +629,7 @@ class NTEventLogHandler(logging.Handler):
DLL name.
"""
#self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
- pass
+ logging.Handler.close(self)
class HTTPHandler(logging.Handler):
"""
@@ -603,7 +652,7 @@ class HTTPHandler(logging.Handler):
def mapLogRecord(self, record):
"""
Default implementation of mapping the log record into a dict
- that is send as the CGI data. Overwrite in your class.
+ that is sent as the CGI data. Overwrite in your class.
Contributed by Franz Glasner.
"""
return record.__dict__
@@ -726,3 +775,4 @@ class MemoryHandler(BufferingHandler):
self.flush()
self.target = None
self.buffer = []
+ BufferingHandler.close(self)