]> granicus.if.org Git - python/commitdiff
Added WatchedFileHandler (based on SF patch #1598415)
authorVinay Sajip <vinay_sajip@yahoo.co.uk>
Sun, 14 Jan 2007 21:49:59 +0000 (21:49 +0000)
committerVinay Sajip <vinay_sajip@yahoo.co.uk>
Sun, 14 Jan 2007 21:49:59 +0000 (21:49 +0000)
Lib/logging/handlers.py

index cd8d5d2f7467262fde13ed06c1f2607bccdd5874..1a82d9e743334bd4b8eae1204b4fa3f6aee0afe5 100644 (file)
@@ -28,6 +28,7 @@ To use, simply 'import logging' and log away!
 """
 
 import sys, logging, socket, types, os, string, cPickle, struct, time, glob
+from stat import ST_DEV, ST_INO
 
 try:
     import codecs
@@ -282,6 +283,54 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
             self.stream = open(self.baseFilename, 'w')
         self.rolloverAt = self.rolloverAt + self.interval
 
+class WatchedFileHandler(logging.FileHandler):
+    """
+    A handler for logging to a file, which watches the file
+    to see if it has changed while in use. This can happen because of
+    usage of programs such as newsyslog and logrotate which perform
+    log file rotation. This handler, intended for use under Unix,
+    watches the file to see if it has changed since the last emit.
+    (A file has changed if its device or inode have changed.)
+    If it has changed, the old file stream is closed, and the file
+    opened to get a new stream.
+
+    This handler is not appropriate for use under Windows, because
+    under Windows open files cannot be moved or renamed - logging
+    opens the files with exclusive locks - and so there is no need
+    for such a handler. Furthermore, ST_INO is not supported under
+    Windows; stat always returns zero for this value.
+
+    This handler is based on a suggestion and patch by Chad J.
+    Schroeder.
+    """
+    def __init__(self, filename, mode='a', encoding=None):
+        logging.FileHandler.__init__(self, filename, mode, encoding)
+        stat = os.stat(self.baseFilename)
+        self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
+
+    def emit(self, record):
+        """
+        Emit a record.
+
+        First check if the underlying file has changed, and if it
+        has, close the old stream and reopen the file to get the
+        current stream.
+        """
+        if not os.path.exists(self.baseFilename):
+            stat = None
+            changed = 1
+        else:
+            stat = os.stat(self.baseFilename)
+            changed = (stat[ST_DEV] != self.dev) or (stat[ST_INO] != self.ino)
+        if changed:
+            self.stream.flush()
+            self.stream.close()
+            self.stream = self._open()
+            if stat is None:
+                stat = os.stat(self.baseFilename)
+            self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
+        logging.FileHandler.emit(self, record)
+
 class SocketHandler(logging.Handler):
     """
     A handler class which writes logging records, in pickle format, to