• 使用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一个错误看看是否能记录到日志.

    如果本地启动项目报错 PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。

    django的启动参数改为: python manage.py runserver --noreload 就正常了. 

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

  • 相关阅读:
    为什么和什么是 DevOps?
    使用jmeter 上传文件
    jmeter 获取执行脚本的路径
    随笔(九)
    随笔(八)
    随笔(七)
    随笔(六)
    随笔(五)
    随笔(四)
    随笔(三)
  • 原文地址:https://www.cnblogs.com/banbosuiyue/p/15030647.html
Copyright © 2020-2023  润新知