[Python] MultiprocessTimedRotatingFileHandler

Python logging模块在多进程下不保证同步,所以 TimedRotating 的情况下可能会导致某些日志文件丢失,下面是一种简单的解决办法,对于日志完整行要求不是很严格的情况下可以使用。

# coding:utf-8
import time
import os
import logging
from logging.handlers import TimedRotatingFileHandler


from .config import config


def init_logger(fname, logger_name):
    log_file = config.get("log", "LOG_PATH") + fname
    logger = logging.getLogger(logger_name)
    # level = config.get('log', 'log_level')
    logger.setLevel(logging.INFO)
    fmt = "%(asctime)s %(filename)s %(lineno)d %(levelname)s %(message)s"
    handler = MultiprocessTimedRotatingFileHandler(log_file, "midnight", 1, 7)
    handler.setFormatter(logging.Formatter(fmt))
    logger.addHandler(handler)
    return logger


class MultiprocessTimedRotatingFileHandler(TimedRotatingFileHandler):

    def __init__(self, filename, when="h", interval=1, backupCount=0,
                 encoding=None, delay=False, utc=False):
        TimedRotatingFileHandler.__init__(self, filename, when=when,
                                          interval=interval,
                                          backupCount=backupCount,
                                          encoding=encoding, delay=delay,
                                          utc=utc)

    def computeRollover(self, currentTime):
        t_str = time.strftime(self.suffix, time.localtime(currentTime))
        t = time.mktime(time.strptime(t_str, self.suffix))
        return TimedRotatingFileHandler.computeRollover(self, t)

    def doRollover(self):
        if self.stream:
            self.stream.close()
            self.stream = None

        currentTime = int(time.time())
        dstNow = time.localtime(currentTime)[-1]
        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
            dstThen = timeTuple[-1]
            if dstNow != dstThen:
                if dstNow:
                    addend = 3600
                else:
                    addend = -3600
                timeTuple = time.localtime(t + addend)

        dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple)

        if not os.path.exists(dfn):
            try:
                os.rename(self.baseFilename, dfn)
            except OSError:
                pass

        if self.backupCount > 0:
            for s in self.getFilesToDelete():
                try:
                    os.remove(s)
                except OSError:
                    pass

        if hasattr(self, 'delay') and not self.delay:
            self.stream = self._open()

        newRolloverAt = self.computeRollover(currentTime)
        while newRolloverAt <= currentTime:
            newRolloverAt = newRolloverAt + self.interval
        # If DST changes and midnight or weekly rollover, adjust for this.
        if (self.when == 'MIDNIGHT' or self.when.startswith(
                'W')) and not self.utc:
            dstAtRollover = time.localtime(newRolloverAt)[-1]
            if dstNow != dstAtRollover:
                if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
                    addend = -3600
                else:  # DST bows out before next rollover, so we need to add an hour
                    addend = 3600
                newRolloverAt += addend
        self.rolloverAt = newRolloverAt

你可能感兴趣的:(如今Python)