I've made a time-rotating logger which creates a new logfile at midnight. In my logfile I want to write a header at the top of every file. I'm looking for an efficient way to call a function which writes this header to the logfile upon the moment that the file is created.
import logging
from logging.handlers import TimedRotatingFileHandler
# create time-rotating log handler
logHandler = TimedRotatingFileHandler(logfile, when='midnight')
# create logger
self.log = logging.getLogger('MyTimeRotatingLogger')
self.log.addHandler(logHandler)
I've solved it! Basically all that needs to be done is overriding the doRollover
method of the TimedRotatingFileHandler
, also some code is needed in this new parent class in order to pass the logging instance and set the header content. Hereby an extensive example for people who encounter a similar situation.
from logging.handlers import TimedRotatingFileHandler
class MyTimedRotatingFileHandler(TimedRotatingFileHandler):
def __init__(self, logfile, when, interval):
super(MyTimedRotatingFileHandler, self).__init__(logfile, when, interval)
self._header = ""
self._log = None
def doRollover(self):
super(MyTimedRotatingFileHandler, self).doRollover()
if self._log is not None and self._header != "":
self._log.info(self._header)
def setHeader(self, header):
self._header = header
def configureHeaderWriter(self, header, log):
self._header = header
self._log = log
# create time-rotating log handler
logHandler = MyTimedRotatingFileHandler(logfile, when='midnight')
form = '%(asctime)s %(name)s %(levelname)s: %(message)s'
logFormatter = logging.Formatter(form)
logHandler.setFormatter(logFormatter)
# create logger
log = logging.getLogger('MyLogger')
logHandler.configureHeaderWriter('test-header', log)
log.addHandler(logHandler)
log.setLevel(logging.INFO)
The solutions above cover the majority of use cases, but if you want to still respect the behavior of the FileHandler.delay
attribute, I think the simplest solution is to override the _open()
method:
class MyTimedRotatingFileHandler(TimedRotatingFileHandler):
def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None, header=''):
self.header = header
super().__init__(filename, when, interval, backupCount, encoding, delay, utc, atTime)
def _open(self):
stream = super()._open()
if self.header and stream.tell() == 0:
stream.write(self.header + self.terminator)
stream.flush()
return stream
This way you could avoid ending up with "empty" log files containing only the header, and you don't have to worry about passing specific loggers to the handler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With