I do struggle with the logging a bit. I'd like to roll over the logs after certain period of time and also after reaching certain size.
Rollover after a period of time is made by TimedRotatingFileHandler
,
and rollover after reaching certain log size is made by RotatingFileHandler
.
But the TimedRotatingFileHandler
doesn't have the attribute maxBytes
and the RotatingFileHandler
can not rotate after a certain period of time.
I also tried to add both handlers to logger, but the result was doubled logging.
Do I miss something?
I also looked into source code of logging.handlers
. I tried to subclass TimedRotatingFileHandler
and override the method shouldRollover()
to create a class with capabilities of both:
class EnhancedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=0, utc=0, maxBytes=0):
""" This is just a combination of TimedRotatingFileHandler and RotatingFileHandler (adds maxBytes to TimedRotatingFileHandler) """
# super(self). #It's old style class, so super doesn't work.
logging.handlers.TimedRotatingFileHandler.__init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=0, utc=0)
self.maxBytes=maxBytes
def shouldRollover(self, record):
"""
Determine if rollover should occur.
Basically, see if the supplied record would cause the file to exceed
the size limit we have.
we are also comparing times
"""
if self.stream is None: # delay was set...
self.stream = self._open()
if self.maxBytes > 0: # are we rolling over?
msg = "%s\n" % self.format(record)
self.stream.seek(0, 2) #due to non-posix-compliant Windows feature
if self.stream.tell() + len(msg) >= self.maxBytes:
return 1
t = int(time.time())
if t >= self.rolloverAt:
return 1
#print "No need to rollover: %d, %d" % (t, self.rolloverAt)
return 0
But like this the log creates one backup and the gets overwritten. Seems like I have to override also method doRollover()
which is not so easy.
Any other idea how to create a logger which rolls the file over after certain time and also after certain size reached?
I adapted Julien's code for my usage. Now it rollover after reaching certain log size or after a period of time.
So I made a small hack to
TimedRotatingFileHandler
to be able to do rollover after both, time and size. I had to modify__init__
,shouldRollover
,doRollover
andgetFilesToDelete
(see below). This is the result, when I set up when='M', interval=2, backupCount=20, maxBytes=1048576:You can see that first four logs were rolled over after reaching size of 1MB, while the last rollover occurred after two minutes. So far I didn't test deleting of old log files, so it probably doesn't work. The code certainly will not work for backupCount>=1000. I append just three digits at the end of the file name.
This is the modified code:
Here is what I use:
If you really need this functionality, write your own handler based on TimedRotatingFileHandler to primarily use time for rolling over, but incorporate sized-based rollover into the existing logic. You've tried this, but you need to (at a minimum) override both
shouldRollover()
anddoRollover()
methods. The first method determines when to roll over, the second does the closing of the current log file, renaming existing files and deleting obsolete files, then opening the new file.The
doRollover()
logic may be a little tricky, but certainly doable.