DRF:配置全局异常处理和日志结合

项目目录结构

---study_drf

        ---study_drf

                ---settings.py

        ---utils

                ---log.py

                ---exception.py

项目依赖

Django==3.2
django-cors-headers==3.5.0
djangorestframework==3.12.2
djangorestframework-jwt==1.11.0
mysqlclient==2.1.1
pinyin==0.4.0 #拼音处理
PyJWT==1.7.1
fpdf==1.7.2 #生成pdf文件
APScheduler==3.10.1 #轻量级定时任务
redis==4.6.0  #操作redis数据库的

要使用drf的Response做为响应对象,需要先注册app

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',#使用rest_framework的Response需要注册
]

一、utils/log.py

1、setting.py配置日志

#######--配置日志,
#1、配置日志要保存的文件夹,创建文件夹
import time
BASE_LOG_DIR = os.path.join(BASE_DIR, 'logs')
ERROR_PATH_DIR = os.path.join(BASE_LOG_DIR,'error')
if not os.path.exists(ERROR_PATH_DIR):
    #如果logs/error/不存在,递归创建目录
    os.makedirs(ERROR_PATH_DIR)

ALL_PATH_DIR = os.path.join(BASE_LOG_DIR,'all')
if not os.path.exists(ALL_PATH_DIR):
    #如果logs/all/目录不存在,就递归创建(如果logs目录不存在,也会创建)
    os.makedirs(ALL_PATH_DIR)

#2、相关的日志配置
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,  # 设置已存在的logger不失效
    'filters': {
    },
    'formatters': {
        'standard': {
            'format': '[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d:%(funcName)s]:%(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
        'simple': {
            'format': '[%(asctime)s][%(levelname)s]:%(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        }
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': { #按照文件大小分割日志,将所有的日志信息都保存在这里
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(BASE_LOG_DIR,'all', 'debug.log'),
            'maxBytes': 1024 * 1024 * 50,  # 日志大小50M
            'backupCount': 5,
            'formatter': 'standard',
            'encoding': 'utf-8',
        },
        #os.path.join(BASE_LOG_DIR,'error',f"{time.strftime('%Y-%m-%d')}.log")
        'time_file':{#按照时间分割日志,每周一新增一个日志文件,存error等级以上的日志
              'level': 'INFO',#日志的等级
              'class': 'logging.handlers.TimedRotatingFileHandler',
              'filename':os.path.join(BASE_LOG_DIR,'error',f"{time.strftime('%Y-%m-%d')}.log") ,#日志的文件名
              'when': 'D', #时间单位,S,M,H,D,'W0'(星期1),'W6'(星期天)
              'interval': 1,
              'backupCount': 5, #备份数量
              'formatter': 'standard', #使用的日志格式
              'encoding': 'utf-8',
        }

    },
    'loggers': {
        #INFO以上日志,打印在console,也写到以文件大小分割的日志中
        'django': {
            'handlers': ['console','file'],#handlers中存在的配置
            'level': 'INFO',
            'propagate': True
        },
        #error以上的日志写到按时间分割的日志文件中,同时打印在控制台
        'django.request': {
            'handlers': ['time_file'],#handlers中存在的配置
            'level': 'ERROR',
            'propagate': True
        },

    },
}

2、utils/log.py,拿到配置的日志处理对象,实现手动记录日志

#手动写日志
import logging

info_logger = logging.getLogger('django') #根据loggers配置handlers,将日志写到指定的地方
error_logger = logging.getLogger('django.request') #根据loggers配置handlers,将日志写到指定的地方

if __name__ == '__main__':
    #简单的使用例子,使用这个方法记录日志,可以记录详细的日志信息(在视图中使用)
    error_logger.exception(f'{__file__}/Test_log,method=post,error,django.request')

二、utils/exception.py

1.1、重写自己的drf全局异常模块

from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status
from utils.log import error_logger #写日志

#配置drf的全局异常处理,需要在settings中配置
def _exception_handler(exc,context):
    #exc是报错的异常对象,context是哪个模块的函数出现报错
    response = exception_handler(exc,context)
    # print(exc.detail.get('error'),exc.detail.get('code'))
    # print(exc,'异常对象')
    # print(context,'报错函数')
    # print(response,'返回对象')
    #response有两个结果:一个是None(系统处理),一个django处理后(但格式不符合要求)
    if not response:
        #当然可以在这里进行精细的捕获

        #将错误信息写到日志文件中,使用这个方法,可以把更多信息记录起来(不要使用error方法,记录的信息不详细)
        error_logger.exception(exc)
        return Response(data={'error':'系统内部错误,请稍后再重试','code':500},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    else:
        #djang处理的
        if type(response.data) == dict:
            detail = response.data.get('detail')
        elif type(response.data) == list:
            #特殊情况处理
            detail = response.data
            if len(detail) <=1:
                return Response(data={'error':detail[0], 'code': 400},
                                status=response.status_code)
            else:
                return Response(data={'error': detail, 'code': 416},
                                status=response.status_code)
        else:
            detail = response.data
        if detail:
            if '未找到。' == detail:
                detail = '查询不到该数据信息'
            if '无效页面。' == detail:
                detail = '该页面的数据查询不到,请确定要查询的页面数据是否存在'
            return Response(data={'error':detail,'code':400},status=response.status_code)
        else:
            #我在写认证时,raise AuthenticationFailed({'code': 410, 'msg': msg,'type':'报错'})
            #拿到这里抛出异常的信息和code
            return Response(data={'error':exc.detail.get('error'),'code':exc.detail.get('code')},status=response.status_code)

1.2、settings.py 在配置文件中使用全局异常处理

#### drf的配置,全局配置
REST_FRAMEWORK = {

    #2、配置全局异常处理
    'EXCEPTION_HANDLER': 'utils.exception._exception_handler',


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值