使用Django日志模块记录全局报错日志

Django提供了日志模块可以在settings.py中定义LOGGING直接使用

示例 :

LOGGING = {
    version: 1,
    disable_existing_loggers: False,  # 是否禁用已经存在的日志模块
    handlers: {
        file: {  # 定义日志文件记录
            level: ERROR,  # 只记录报错
            # ‘class‘: ‘logging.FileHandler‘,  # 普通的日志记录类,不实用
            # ‘class‘: ‘logging.handlers.TimedRotatingFileHandler‘,  # 原本的按时间分割的日志记录类
            class: utils.tools.MyTimedRotating,  # 使用django日志记录全局报错. 重写父类方法,自定义文件命名和删除
            filename: os.path.join(BASE_DIR, logs, err.log),  # 定义日志文件目录,logs文件夹没有就创建,err.log自动生成
            formatter: verbose,
            when: D,  # 每天切割一次日志
            interval: 1,  # 时间间隔: 一天
            backupCount: 10,  # 保留?份日志
            encoding: utf-8
        },
        console: {  # 定义终端打印记录
            level: INFO,  # 打印所有信息
            class: logging.StreamHandler,
            formatter: verbose,
        },
    },
    formatters: {
        verbose: {  # 定义详细的日志信息
            format: {levelname} {asctime} {module} {process:d} {thread:d} {message},
            style: {,
        },
        simple: {  # 定义简单的日志信息
            format: {levelname} {message},
            style: {,
        },
    },
    loggers: {
        django: {  # 使用django日志,指定使用上述定义的各个配置
            handlers: [file, console],  # 同时记录到日志文件和在终端打印
            level: INFO,
            propagate: True,  # 是否向上传播
            formatter: verbose
        },
    },
}

 

由于Django提供的这个按时间分割的 TimedRotatingFileHandler 日志类命名很奇怪, 所以我把它的文件命名和删除文件方法重写了, 在自己的 utils/tools.py文件中定义

其中原本的类通过 from logging.handlers import TimedRotatingFileHandler 导入

class MyTimedRotating(TimedRotatingFileHandler):
    """
    重写父类的日志命名及过量日志删除
    """
    def doRollover(self):
        """
        自定义日志命名
        """
        if self.stream:
            self.stream.close()
            self.stream = None
        # get the time that this sequence started at and make it a TimeTuple
        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.rotation_filename(self.baseFilename + "." +
        #                              time.strftime(self.suffix, timeTuple))
        dfn = self.rotation_filename(self.baseFilename.rstrip(".log") + "_" +
                                     time.strftime(self.suffix, timeTuple) + ".log")
        if os.path.exists(dfn):
            os.remove(dfn)
        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()
        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

    def getFilesToDelete(self):
        """
        超出规定数量日志的删除
        """
        dirName, baseName = os.path.split(self.baseFilename)
        fileNames = os.listdir(dirName)
        result = []
        # prefix = baseName + "."  # err.
        prefix = baseName.rstrip(".log") + "_"  # err_
        tail = ".log"
        plen_head = len(prefix)
        plen_tail = len(tail)
        for fileName in fileNames:
            if fileName[:plen_head] == prefix and fileName[-plen_tail:] == tail:
                suffix = fileName[plen_head: -plen_tail]
                if self.extMatch.match(suffix):
                    result.append(os.path.join(dirName, fileName))
        if len(result) < self.backupCount:
            result = []
        else:
            result.sort()
            result = result[:len(result) - self.backupCount]
        return result

 

如果懒的话直接使用原本的 logging.handlers.TimedRotatingFileHandler 类, 就不需要重写父类方法了. 写完之后可以使用raise一个错误看看是否能记录到日志.

这样就能自动按时间分割日志文件, 记录全局报错日志了, 大家觉得好用可以帮忙点个赞

 

使用Django日志模块记录全局报错日志

上一篇:Bootstrap使用父子表


下一篇:Split string via delimiter and print the split string and delimiter's index