luffy后台配置之二次封装

封装logger

项目都要记录日志

  • 日志都可以打印到控制台
  • 日志可以写到日志文件中
  • 日志存到某个库中
  • 所有项目日志统一管理 sentry:django写的服务,收集日志的,可以展示 开源的

项目中print都调整为logger.info()

以后项目上线,只需要调整日志级别,低级别的日志就不打印了,于是日志输出不用删掉

操作步骤

  • django中集成日志步骤,django使用的就是python内置的日志模块

第一步:在配置文件中加入日志配置 ---大字典

# dev.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
        },
    },
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            # 实际开发建议使用WARNING
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            # 实际开发建议使用ERROR
            'level': 'WARNING',
            'class': 'logging.handlers.RotatingFileHandler',
            # 日志位置,日志文件名,日志保存目录必须手动创建,注:这里的文件路径要注意BASE_DIR代表的是小luffyapi
            'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "luffy.log"),
            # 日志文件的最大值,这里我们设置300M
            'maxBytes': 300 * 1024 * 1024,
            # 日志文件的数量,设置最大日志数量为10
            'backupCount': 10,
            # 日志格式:详细格式
            'formatter': 'verbose',
            # 文件内容编码
            'encoding': 'utf-8'
        },
    },
    # 日志对象
    'loggers': {
        'django': {
            'handlers': ['console', 'file'],
            'propagate': True,  # 是否让日志信息继续冒泡给其他的日志处理系统
        },
    }
}

第二步:在utils新建 common_logger.py ,得到日志对象

import logging
logger = logging.getLogger('django')

第三步:在任意想用日志的地方,导入使用即可

from utils.common_logger import logger

logger.info('info级别的日志')
logger.error('error级别的日志')

示例:

# home下的view.py

from django.http import JsonResponse
from utils.common_logger import logger

def test_logger(request):
    logger.info('info级别的日志')
    logger.error('error级别的日志')
    return JsonResponse({'info':'日志测试'},json_dumps_params={'ensure_ascii': False})

# urls.py

from home import views

urlpatterns = [
    path('test_logger/',views.test_logger),
]

全局异常处理封装

 无论后端是否出错,前端接收的格式都要统一,所以需要进行全局异常处理

回顾三大认证

  • 视图类的方法中只要出了异常,就会执行一个函数,但是这个函数只能处理drf的异常---》我们需要自己写个函数,既能处理drf异常,又能处理django异常,这样统一返回格式,前端看到格式都统一了

使用步骤:

第一步:在utils中新建 common_exceptions.py,写个异常处理函数

from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from utils.common_logger import logger


# 只要走到这个函数中,一定是出异常了,所以要记录日志
def exception_handler(exc, context):
    # 1 记录日志 : 哪个ip地址,用户id是多少,访问哪个路径,执行哪个视图函数,出了什么错
    request = context.get('request')
    view = context.get('view')
    ip = request.META.get('REMOTE_ADDR')
    user_id = request.user.pk
    path = request.get_full_path()
    response = drf_exception_handler(exc, context)
    if response:
        logger.warning('drf出了异常,异常是:%s' % str(exc))
        # drf的异常已经处理了--->直接取detail 会有点小小的问题,碰到再解决
        res = Response({'code': 999, 'msg': response.data.get('detail', '服务器异常,请联系系统管理员')})
    else:
        # djagno的异常,咱们要处理
        logger.error('用户【%s】,ip地址为【%s】,访问地址为【%s】,执行视图函数为【%s】,出错是【%s】' % (user_id, ip, path, str(view), str(exc)))
        res = Response({'code': 888, 'msg': '服务器异常,请联系系统管理员'})

    return res

第二步:配置配置文件

  • 以后只要出了异常,都会走咱们的函数
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'utils.exception.exception_handler',
}

第三步:视图类中直接使用

使用示例:

# home.views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import APIException

class TestException(APIView):
    def get(self,request):

        raise APIException('drf抛出异常')

        return Response('ok')

# urls.py

from home import views

urlpatterns = [
    path('test_exception/',views.TestException.as_view())
]

封装Response

本身drf有Response,但是公司都会规定,前端收到的格式都是固定的,如

# return APIResponse()----------前端收到-->{code:100,msg:成功}

# return APIResponse(token=xsdse,username=lqz)----------前端收到-->{code:100,msg:成功,token:xsdse,username:lqz}

# return APIResponse(data=[{},{},{}])----------前端收到-->{code:100,msg:成功,data:[{},{},{}]}

# return APIResponse(code=101,msg=失败)----------前端收到-->{code:101,msg:失败}

# return APIResponse(headers={'xx':'xx'})----------前端收到-->{code:100,msg:成功},但是响应头中有xx=xx

# return APIResponse(status=201)----------前端收到-->{code:100,msg:成功},但是响应状态码是201

对Response进行封装,封装后,code,msg可以不传,不传就用默认的

使用步骤

第一步:在utils下新建common_response.py,封装APIResponse

from rest_framework.response import Response

class APIResponse(Response):
    def __init__(self, code=100, msg='成功', status=None, headers=None, **kwargs):
        data = {'code': code, 'msg': msg}
        if kwargs:  # 有值,说明,传了 除了code msg   status headers 以外的,咱们都要返回给前端,放到这个data中
            data.update(kwargs)
        # Response(data=data,status=status,headers=headers)
        super().__init__(data=data, status=status, headers=headers)

        # 不要return,可以这样做  self.data=data  self.status=status

第二步:导入使用

  • 视图函数的方法,返回时,都使用咱们自己的

示例

from rest_framework.response import Response
from utils.common_response import APIResponse

class TestAPIResponse(APIView):
    def get(self,request):
        return APIResponse(token='asdsadfsaf',username='xxx',addr='cfsafsaf')

 

posted @ 2023-02-27 20:06  莫~慌  阅读(30)  评论(0编辑  收藏  举报