loggering学习文档,包括RotatingFileHandler 和 TimedRotatingFileHandl源码

logger.setLevel(level) 解释

在 Python 的 logging 模块中,logger.setLevel(level) 方法用于设置日志记录器的级别。日志级别决定了哪些日志消息会被记录,哪些会被忽略。以下是各个日志级别的详细说明:
logging.DEBUG: 最详细的日志信息,用于调试目的。
logging.INFO: 确认程序按预期运行的信息。
logging.WARNING: 表明有意外,或者在不久的将来可能的问题。
logging.ERROR: 由于严重问题,程序部分功能无法执行。
logging.CRITICAL: 严重的错误,表明程序本身可能无法继续运行。
当你设置 logger.setLevel(logging.DEBUG) 时,所有级别的日志消息(包括 DEBUG、INFO、WARNING、ERROR 和 CRITICAL)都会被记录。
当你设置 logger.setLevel(logging.INFO) 时,只有 INFO 级别及其以上的日志消息(INFO、WARNING、ERROR 和 CRITICAL)会被记录。DEBUG 级别的日志消息会被忽略。
简单来说,logging.DEBUG 会记录所有级别的日志,而 logging.INFO 只会记录 INFO 级别及其以上的日志。

logging使用流程
创建日志记录器
logger = logging.getLogger(‘task_logger’)
logger.setLevel(logging.INFO)
创建一个控制台处理器,将日志输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
创建一个文件处理器,将日志输出到文件,并设置滚动策略
file_handler = RotatingFileHandler(‘task.log’,mode=‘a’,maxBytes=10241024100,backupCount=5) # 100M 5个文件
file_handler.setLevel(logging.INFO)
创建日志格式器,并添加到控制台处理器,和文件处理器
formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’, ‘[%Y-%m-%d %H:%M:%S]’)
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
将控制台处理器和文件处理器添加到日志记录器中
logger.addHandler(console_handler)
logger.addHandler(file_handler)
整体logger配置代码
import logging
from logging.handlers import RotatingFileHandler
#-------------------------------------- #配置日志文件# --------------------------------------#

创建日志记录器

logger = logging.getLogger(‘task_logger’)
logger.setLevel(logging.INFO)

创建一个控制台处理器,将日志输出到控制台

console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

创建一个文件处理器,将日志输出到文件,并设置滚动策略

file_handler = RotatingFileHandler(‘task.log’,mode=‘a’,maxBytes=10241024100,backupCount=5) # 100M 5个文件
file_handler.setLevel(logging.INFO)

创建日志格式器,并添加到控制台处理器,和文件处理器

formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’, ‘[%Y-%m-%d %H:%M:%S]’)
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)

将控制台处理器和文件处理器添加到日志记录器中

logger.addHandler(console_handler)
logger.addHandler(file_handler)

整体logger配置代码

import logging
from logging.handlers import RotatingFileHandler
#--------------------------------------        #配置日志文件#        --------------------------------------#
## 创建日志记录器
logger = logging.getLogger('task_logger')
logger.setLevel(logging.INFO)
## 创建一个控制台处理器,将日志输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

## 创建一个文件处理器,将日志输出到文件,并设置滚动策略
file_handler = RotatingFileHandler('task.log',mode='a',maxBytes=1024*1024*100,backupCount=5) # 100M 5个文件
file_handler.setLevel(logging.INFO)

## 创建日志格式器,并添加到控制台处理器,和文件处理器
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s', '[%Y-%m-%d %H:%M:%S]')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
## 将控制台处理器和文件处理器添加到日志记录器中
logger.addHandler(console_handler)
logger.addHandler(file_handler)

# 测试日志记录
# logger.debug('This is a debug message')
# logger.info('This is an info message')
# logger.warning('This is a warning message')
# logger.error('This is an error message')
# logger.critical('This is a critical message')

RotatingFileHandler 和 TimedRotatingFileHandl源码

支持文件大小 以及文件轮转

class RotatingFileHandler(BaseRotatingHandler):
    """
    Handler for logging to a set of files, which switches from one file
    to the next when the current file reaches a certain size.
    """
    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0,
                 encoding=None, delay=False, errors=None):
        """
        Open the specified file and use it as the stream for logging.

        By default, the file grows indefinitely. You can specify particular
        values of maxBytes and backupCount to allow the file to rollover at
        a predetermined size.

        Rollover occurs whenever the current log file is nearly maxBytes in
        length. If backupCount is >= 1, the system will successively create
        new files with the same pathname as the base file, but with extensions
        ".1", ".2" etc. appended to it. For example, with a backupCount of 5
        and a base file name of "app.log", you would get "app.log",
        "app.log.1", "app.log.2", ... through to "app.log.5". The file being
        written to is always "app.log" - when it gets filled up, it is closed
        and renamed to "app.log.1", and if files "app.log.1", "app.log.2" etc.
        exist, then they are renamed to "app.log.2", "app.log.3" etc.
        respectively.

        If maxBytes is zero, rollover never occurs.
        """
        # If rotation/rollover is wanted, it doesn't make sense to use another
        # mode. If for example 'w' were specified, then if there were multiple
        # runs of the calling application, the logs from previous runs would be
        # lost if the 'w' is respected, because the log file would be truncated
        # on each run.
        if maxBytes > 0:
            mode = 'a'
        if "b" not in mode:
            encoding = io.text_encoding(encoding)
        BaseRotatingHandler.__init__(self, filename, mode, encoding=encoding,
                                     delay=delay, errors=errors)
        self.maxBytes = maxBytes
        self.backupCount = backupCount

    def doRollover(self):
        """
        Do a rollover, as described in __init__().
        """
        if self.stream:
            self.stream.close()
            self.stream = None
        if self.backupCount > 0:
            for i in range(self.backupCount - 1, 0, -1):
                sfn = self.rotation_filename("%s.%d" % (self.baseFilename, i))
                dfn = self.rotation_filename("%s.%d" % (self.baseFilename,
                                                        i + 1))
                if os.path.exists(sfn):
                    if os.path.exists(dfn):
                        os.remove(dfn)
                    os.rename(sfn, dfn)
            dfn = self.rotation_filename(self.baseFilename + ".1")
            if os.path.exists(dfn):
                os.remove(dfn)
            self.rotate(self.baseFilename, dfn)
        if not self.delay:
            self.stream = self._open()

    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.
        """
        # See bpo-45401: Never rollover anything other than regular files
        if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename):
            return False
        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
        return False

class TimedRotatingFileHandler(BaseRotatingHandler):
    """
    Handler for logging to a file, rotating the log file at certain timed
    intervals.

    If backupCount is > 0, when rollover is done, no more than backupCount
    files are kept - the oldest ones are deleted.
    """
    def __init__(self, filename, when='h', interval=1, backupCount=0,
                 encoding=None, delay=False, utc=False, atTime=None,
                 errors=None):
        encoding = io.text_encoding(encoding)
        BaseRotatingHandler.__init__(self, filename, 'a', encoding=encoding,
                                     delay=delay, errors=errors)
        self.when = when.upper()
        self.backupCount = backupCount
        self.utc = utc
        self.atTime = atTime
        # Calculate the real rollover interval, which is just the number of
        # seconds between rollovers.  Also set the filename suffix used when
        # a rollover occurs.  Current 'when' events supported:
        # S - Seconds
        # M - Minutes
        # H - Hours
        # D - Days
        # midnight - roll over at midnight
        # W{0-6} - roll over on a certain day; 0 - Monday
        #
        # Case of the 'when' specifier is not important; lower or upper case
        # will work.
        if self.when == 'S':
            self.interval = 1 # one second
            self.suffix = "%Y-%m-%d_%H-%M-%S"
            extMatch = r"(?<!\d)\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(?!\d)"
        elif self.when == 'M':
            self.interval = 60 # one minute
            self.suffix = "%Y-%m-%d_%H-%M"
            extMatch = r"(?<!\d)\d{4}-\d{2}-\d{2}_\d{2}-\d{2}(?!\d)"
        elif self.when == 'H':
            self.interval = 60 * 60 # one hour
            self.suffix = "%Y-%m-%d_%H"
            extMatch = r"(?<!\d)\d{4}-\d{2}-\d{2}_\d{2}(?!\d)"
        elif self.when == 'D' or self.when == 'MIDNIGHT':
            self.interval = 60 * 60 * 24 # one day
            self.suffix = "%Y-%m-%d"
            extMatch = r"(?<!\d)\d{4}-\d{2}-\d{2}(?!\d)"
        elif self.when.startswith('W'):
            self.interval = 60 * 60 * 24 * 7 # one week
            if len(self.when) != 2:
                raise ValueError("You must specify a day for weekly rollover from 0 to 6 (0 is Monday): %s" % self.when)
            if self.when[1] < '0' or self.when[1] > '6':
                raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
            self.dayOfWeek = int(self.when[1])
            self.suffix = "%Y-%m-%d"
            extMatch = r"(?<!\d)\d{4}-\d{2}-\d{2}(?!\d)"
        else:
            raise ValueError("Invalid rollover interval specified: %s" % self.when)

        # extMatch is a pattern for matching a datetime suffix in a file name.
        # After custom naming, it is no longer guaranteed to be separated by
        # periods from other parts of the filename.  The lookup statements
        # (?<!\d) and (?!\d) ensure that the datetime suffix (which itself
        # starts and ends with digits) is not preceded or followed by digits.
        # This reduces the number of false matches and improves performance.
        self.extMatch = re.compile(extMatch, re.ASCII)
        self.interval = self.interval * interval # multiply by units requested
        # The following line added because the filename passed in could be a
        # path object (see Issue #27493), but self.baseFilename will be a string
        filename = self.baseFilename
        if os.path.exists(filename):
            t = os.stat(filename)[ST_MTIME]
        else:
            t = int(time.time())
        self.rolloverAt = self.computeRollover(t)

    def computeRollover(self, currentTime):
        """
        Work out the rollover time based on the specified time.
        """
        result = currentTime + self.interval
        # If we are rolling over at midnight or weekly, then the interval is already known.
        # What we need to figure out is WHEN the next interval is.  In other words,
        # if you are rolling over at midnight, then your base interval is 1 day,
        # but you want to start that one day clock at midnight, not now.  So, we
        # have to fudge the rolloverAt value in order to trigger the first rollover
        # at the right time.  After that, the regular interval will take care of
        # the rest.  Note that this code doesn't care about leap seconds. :)
        if self.when == 'MIDNIGHT' or self.when.startswith('W'):
            # This could be done with less code, but I wanted it to be clear
            if self.utc:
                t = time.gmtime(currentTime)
            else:
                t = time.localtime(currentTime)
            currentHour = t[3]
            currentMinute = t[4]
            currentSecond = t[5]
            currentDay = t[6]
            # r is the number of seconds left between now and the next rotation
            if self.atTime is None:
                rotate_ts = _MIDNIGHT
            else:
                rotate_ts = ((self.atTime.hour * 60 + self.atTime.minute)*60 +
                    self.atTime.second)

            r = rotate_ts - ((currentHour * 60 + currentMinute) * 60 +
                currentSecond)
            if r <= 0:
                # Rotate time is before the current time (for example when
                # self.rotateAt is 13:45 and it now 14:15), rotation is
                # tomorrow.
                r += _MIDNIGHT
                currentDay = (currentDay + 1) % 7
            result = currentTime + r
            # If we are rolling over on a certain day, add in the number of days until
            # the next rollover, but offset by 1 since we just calculated the time
            # until the next day starts.  There are three cases:
            # Case 1) The day to rollover is today; in this case, do nothing
            # Case 2) The day to rollover is further in the interval (i.e., today is
            #         day 2 (Wednesday) and rollover is on day 6 (Sunday).  Days to
            #         next rollover is simply 6 - 2 - 1, or 3.
            # Case 3) The day to rollover is behind us in the interval (i.e., today
            #         is day 5 (Saturday) and rollover is on day 3 (Thursday).
            #         Days to rollover is 6 - 5 + 3, or 4.  In this case, it's the
            #         number of days left in the current week (1) plus the number
            #         of days in the next week until the rollover day (3).
            # The calculations described in 2) and 3) above need to have a day added.
            # This is because the above time calculation takes us to midnight on this
            # day, i.e. the start of the next day.
            if self.when.startswith('W'):
                day = currentDay # 0 is Monday
                if day != self.dayOfWeek:
                    if day < self.dayOfWeek:
                        daysToWait = self.dayOfWeek - day
                    else:
                        daysToWait = 6 - day + self.dayOfWeek + 1
                    result += daysToWait * _MIDNIGHT
                result += self.interval - _MIDNIGHT * 7
            else:
                result += self.interval - _MIDNIGHT
            if not self.utc:
                dstNow = t[-1]
                dstAtRollover = time.localtime(result)[-1]
                if dstNow != dstAtRollover:
                    if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
                        addend = -3600
                        if not time.localtime(result-3600)[-1]:
                            addend = 0
                    else:           # DST bows out before next rollover, so we need to add an hour
                        addend = 3600
                    result += addend
        return result

    def shouldRollover(self, record):
        """
        Determine if rollover should occur.

        record is not used, as we are just comparing times, but it is needed so
        the method signatures are the same
        """
        t = int(time.time())
        if t >= self.rolloverAt:
            # See #89564: Never rollover anything other than regular files
            if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename):
                # The file is not a regular file, so do not rollover, but do
                # set the next rollover time to avoid repeated checks.
                self.rolloverAt = self.computeRollover(t)
                return False

            return True
        return False

    def getFilesToDelete(self):
        """
        Determine the files to delete when rolling over.

        More specific than the earlier method, which just used glob.glob().
        """
        dirName, baseName = os.path.split(self.baseFilename)
        fileNames = os.listdir(dirName)
        result = []
        if self.namer is None:
            prefix = baseName + '.'
            plen = len(prefix)
            for fileName in fileNames:
                if fileName[:plen] == prefix:
                    suffix = fileName[plen:]
                    if self.extMatch.fullmatch(suffix):
                        result.append(os.path.join(dirName, fileName))
        else:
            for fileName in fileNames:
                # Our files could be just about anything after custom naming,
                # but they should contain the datetime suffix.
                # Try to find the datetime suffix in the file name and verify
                # that the file name can be generated by this handler.
                m = self.extMatch.search(fileName)
                while m:
                    dfn = self.namer(self.baseFilename + "." + m[0])
                    if os.path.basename(dfn) == fileName:
                        result.append(os.path.join(dirName, fileName))
                        break
                    m = self.extMatch.search(fileName, m.start() + 1)

        if len(result) < self.backupCount:
            result = []
        else:
            result.sort()
            result = result[:len(result) - self.backupCount]
        return result

    def doRollover(self):
        """
        do a rollover; in this case, a date/time stamp is appended to the filename
        when the rollover happens.  However, you want the file to be named for the
        start of the interval, not the current time.  If there is a backup count,
        then we have to get a list of matching filenames, sort them and remove
        the one with the oldest suffix.
        """
        # get the time that this sequence started at and make it a TimeTuple
        currentTime = int(time.time())
        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
            dstNow = time.localtime(currentTime)[-1]
            dstThen = timeTuple[-1]
            if dstNow != dstThen:
                if dstNow:
                    addend = 3600
                else:
                    addend = -3600
                timeTuple = time.localtime(t + addend)
        dfn = self.rotation_filename(self.baseFilename + "." +
                                     time.strftime(self.suffix, timeTuple))
        if os.path.exists(dfn):
            # Already rolled over.
            return

        if self.stream:
            self.stream.close()
            self.stream = None
        self.rotate(self.baseFilename, dfn)
        if self.backupCount > 0:
            for s in self.getFilesToDelete():
                os.remove(s)
        if not self.delay:
            self.stream = self._open()
        self.rolloverAt = self.computeRollover(currentTime)

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值