Poodletooth-iLand/panda/direct/directnotify/RotatingLog.py

144 lines
4.5 KiB
Python
Raw Normal View History

2015-03-03 16:10:12 -06:00
import os
import time
class RotatingLog:
"""
A file() (or open()) replacement that will automatically open and write
to a new file if the prior file is too large or after a time interval.
"""
def __init__(self, path="./log_file", hourInterval=24, megabyteLimit=1024):
"""
path is a full or partial path with file name.
hourInterval is the number of hours at which to rotate the file.
megabyteLimit is the number of megabytes of file size the log
may grow to, after which the log is rotated. Note: The log
file may get a bit larger than limit do to writing out whole
lines (last line may exceed megabyteLimit or "megabyteGuidline").
"""
self.path=path
self.timeInterval=None
self.timeLimit=None
self.sizeLimit=None
if hourInterval is not None:
self.timeInterval=hourInterval*60*60
self.timeLimit=time.time()+self.timeInterval
if megabyteLimit is not None:
self.sizeLimit=megabyteLimit*1024*1024
def __del__(self):
self.close()
def close(self):
if hasattr(self, "file"):
self.file.flush()
self.file.close()
self.closed = self.file.closed
del self.file
else:
self.closed = 1
def shouldRotate(self):
"""
Returns a bool about whether a new log file should
be created and written to (while at the same time
stopping output to the old log file and closing it).
"""
if not hasattr(self, "file"):
return 1
if self.timeLimit is not None and time.time() > self.timeLimit:
return 1
if self.sizeLimit is not None and self.file.tell() > self.sizeLimit:
return 1
return 0
def filePath(self):
dateString=time.strftime("%Y_%m_%d_%H", time.localtime())
for i in range(26):
path="%s_%s_%s.log"%(self.path, dateString, chr(i+97))
if not os.path.exists(path) or os.stat(path)[6] < self.sizeLimit:
return path
# Hmm, 26 files are full? throw the rest in z:
# Maybe we should clear the self.sizeLimit here... maybe.
return path
def rotate(self):
"""
Rotate the log now. You normally shouldn't need to call this.
See write().
"""
path=self.filePath()
file=open(path, "a")
if file:
self.close()
# This should be redundant with "a" open() mode,
# but on some platforms tell() will return 0
# until the first write:
file.seek(0, 2)
self.file=file
# Some of these data members may be expected by some of our clients:
self.closed = self.file.closed
self.mode = self.file.mode
self.name = self.file.name
self.softspace = self.file.softspace
#self.encoding = self.file.encoding # Python 2.3
#self.newlines = self.file.newlines # Python 2.3, maybe
if self.timeLimit is not None and time.time() > self.timeLimit:
self.timeLimit=time.time()+self.timeInterval
else:
# We'll keep writing to the old file, if available.
print "RotatingLog error: Unable to open new log file \"%s\"."%(path,)
def write(self, data):
"""
Write the data to either the current log or a new one,
depending on the return of shouldRotate() and whether
the new file can be opened.
"""
if self.shouldRotate():
self.rotate()
if hasattr(self, "file"):
r = self.file.write(data)
self.file.flush()
return r
def flush(self):
return self.file.flush()
def fileno(self):
return self.file.fileno()
def isatty(self):
return self.file.isatty()
def next(self):
return self.file.next()
def read(self, size):
return self.file.read(size)
def readline(self, size):
return self.file.readline(size)
def readlines(self, sizehint):
return self.file.readlines(sizehint)
def xreadlines(self):
return self.file.xreadlines()
def seek(self, offset, whence=0):
return self.file.seek(offset, whence)
def tell(self):
return self.file.tell()
def truncate(self, size):
return self.file.truncate(size)
def writelines(self, sequence):
return self.file.writelines(sequence)