compressed_sized_timed_rotating_handler.py 2.48 KiB
import time
import os
import logging.handlers as handlers
import zipfile


class CompressedSizedTimedRotatingFileHandler(handlers.TimedRotatingFileHandler):
    """Handler for logging to a set of files, which switches from one file
    to the next when the current file reaches a certain size, or at certain
    timed intervals"""

    def __init__(self, filename, max_bytes=0, backup_count=0, encoding=None,
                 delay=0, when='h', interval=1, utc=False, zip_mode=zipfile.ZIP_DEFLATED):
        handlers.TimedRotatingFileHandler.__init__(self, filename=filename, when=when, interval=interval, utc=utc,
                                                   backupCount=backup_count, encoding=encoding, delay=delay)
        self.maxBytes = max_bytes
        self.zip_mode = zip_mode

    def shouldRollover(self, record):
        """Determines if rollover should occur.
        Basically, sees if the supplied record would cause the file to exceed
        the size limit we have."""

        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 True
        t = int(time.time())
        if t >= self.rolloverAt:
            return True
        return False

    def find_last_rotated_file(self):
        """Looks for the last rotated file and returns it"""

        dir_name, base_name = os.path.split(self.baseFilename)
        file_names = os.listdir(dir_name)
        result = []
        prefix = f'{base_name}.2'  # we want to find a rotated file with e.g. filename.2017-12-12... name
        for file_name in file_names:
            if file_name.startswith(prefix) and not file_name.endswith('.zip'):
                result.append(file_name)
        result.sort()
        return os.path.join(dir_name, result[0])

    def doRollover(self):
        """Does the roll-over by compressing the current file then deleting the uncompressed file"""

        super(CompressedSizedTimedRotatingFileHandler, self).doRollover()

        dfn = self.find_last_rotated_file()
        dfn_zipped = f'{dfn}.zip'
        if os.path.exists(dfn_zipped):
            os.remove(dfn_zipped)
        with zipfile.ZipFile(dfn_zipped, 'w', self.zip_mode) as f:
            f.write(dfn)
        os.remove(dfn)