--- __init__.py-orig 2006-11-10 09:16:57.000000000 -0600 +++ __init__.py 2006-11-20 11:04:39.000000000 -0600 @@ -27,6 +27,7 @@ """ import sys, os, types, time, string, cStringIO, traceback +from stat import ST_SIZE try: import codecs @@ -760,21 +761,63 @@ """ A handler class which writes formatted logging records to disk files. """ - def __init__(self, filename, mode='a', encoding=None): + def __init__(self, filename, mode='a', encoding=None, followfile=False): """ Open the specified file and use it as the stream for logging. """ if codecs is None: encoding = None if encoding is None: + self.encoding = None stream = open(filename, mode) else: + self.encoding = encoding stream = codecs.open(filename, mode, encoding) StreamHandler.__init__(self, stream) #keep the absolute path, otherwise derived classes which use this #may come a cropper when the current directory changes self.baseFilename = os.path.abspath(filename) self.mode = mode + self.followfile = followfile + if (self.followfile): + self.size = os.stat(self.baseFilename)[ST_SIZE] + + def update_stream(self): + """Close the old stream and update with the new.""" + + self.stream.flush() + self.stream.close() + if (self.encoding): + self.stream = codecs.open(self.baseFilename, mode, self.encoding) + else: + self.stream = open(self.baseFilename, self.mode) + + def emit(self, record): + """It's possible that the file being written to will be rolled-over + by an external application such as newsyslog on UNIX. By default, the + FileHandler tracks the file descriptor, not the file. If the original + file is renamed, the file associated with the descriptor is updated; + however, it's probably desired that continued updates to the file + associated with the original name take place. + + If the followfile attribute evaluates to True, the code compares the + file size from a previous iteration to that of the current iteration + before the base class emit is called. If a difference in st_size is + found, the current stream is closed and a new one, based on baseFilename, + is created, the file size is updated, and then the base class emit is + called. + """ + + if (self.followfile): + if (not os.path.exists(self.baseFilename)): + self.update_stream() + size = os.stat(self.baseFilename)[ST_SIZE] + if (size < self.size): + self.update_stream() + self.size = size + + # Call the base class emit. + StreamHandler.emit(self, record) def close(self): """ @@ -1224,6 +1267,11 @@ that this argument is incompatible with 'filename' - if both are present, 'stream' is ignored. + followfile Specifies that the FileHandler watch the specified filename + for changes, e.g. renamed by some log rotation mechanism such + as newsyslog. Read FileHandler emit() docstring for more + information. + Note that you could specify a stream created using open(filename, mode) rather than passing the filename and mode in. However, it should be remembered that StreamHandler does not close its stream (since it may be @@ -1234,7 +1282,8 @@ filename = kwargs.get("filename") if filename: mode = kwargs.get("filemode", 'a') - hdlr = FileHandler(filename, mode) + followfile = kwargs.get("followfile", False) + hdlr = FileHandler(filename, mode, followfile=followfile) else: stream = kwargs.get("stream") hdlr = StreamHandler(stream)