Django中间件实现操作日志记录

Django中间件实现操作日志

本文通过Django中间件的流程,实现操作日志记录的功能,模块化、拿来即用。

功能描述:通过中间件记录 请求时间操作用户请求URL请求方法请求IP请求参数响应数据响应耗时等数据日志,而且可以自定义exclude_urls列表,访问列表中的url,不会保存操作日志。另外,通过设置的响应时间阈值(可配置化),将超过阈值的操作日志进行单独保存,便于分析。

说明:示例中将是数据记录在MySQL数据库中,如果你想写入log日志,只需将数据入库改为log格式写入即可(数据都放在self.data中,取用方便)。

创建中间件

  1. 在app01下新建文件夹middlewares, 在文件夹下新建中间件文件LogMiddleware.py

  2. 在中间件文件中新建一个类, 继承MiddlewareMixin:

    from django.utils.deprecation import MiddlewareMixin
    
    class OpLogs(MiddlewareMixin):
    	
    	def process_request(self, request):
            pass
    
  3. 在settings中注册中间件:

    # 自定义中间件
    MIDDLEWARE += [
        'app01.middlewares.LogMiddleware.OpLogs'
    ]
    

功能实现

  1. LogModdleware.py中间件

    # -*- coding:utf-8 -*-
    """
    @file   : LogMiddleware.py
    @Author : Python
    @Date   : 2021/7/20 14:00
    """
    import time
    import json
    
    from django.utils.deprecation import MiddlewareMixin
    
    from app.models import OpLogs, AccessTimeOutLogs
    
    
    class OpLogs(MiddlewareMixin):
    
        __exclude_urls = ['index/']   # 定义不需要记录日志的url名单
    
        def __init__(self, *args):
            super(OpLog, self).__init__(*args)
    
            self.start_time = None	# 开始时间
            self.end_time = None	# 响应时间
            self.data = {}		# dict数据
    
        def process_request(self, request):
            """
            请求进入
            :param request: 请求对象
            :return:
            """
            
            self.start_time = time.time()   # 开始时间
            re_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())  # 请求时间(北京)
    
            # 请求IP
            x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
            if x_forwarded_for:
                # 如果有代理,获取真实IP
                re_ip = x_forwarded_for.split(",")[0]
            else:
                re_ip = request.META.get('REMOTE_ADDR')
    
            # 请求方法
            re_method = request.method
    
            # 请求参数
            re_content = request.GET if re_method == 'GET' else request.POST
            if re_content:
                # 筛选空参数
                re_content = json.dumps(re_content)
            else:
                re_content = None
                
            self.data.update(
                {
                    're_time': re_time,     # 请求时间
                    're_url': request.path,     # 请求url
                    're_method': re_method,     # 请求方法
                    're_ip': re_ip,     # 请求IP
                    're_content': re_content,    # 请求参数
                    # 're_user': request.user.username    # 操作人(需修改),网站登录用户
                    're_user': 'AnonymousUser'    # 匿名操作用户测试
                }
            )
    
    
        def process_response(self, request, response):
            """
            响应返回
            :param request: 请求对象
            :param response: 响应对象
            :return: response
            """
            # 请求url在 exclude_urls中,直接return,不保存操作日志记录
            for url in self.__exclude_urls:
                if url in self.data.get('re_url'):
                    return response
    
            # 获取响应数据字符串(多用于API, 返回JSON字符串)
            rp_content = response.content.decode()
            self.data['rp_content'] = rp_content
    
            # 耗时
            self.end_time = time.time()  # 响应时间
            access_time = self.end_time - self.start_time
            self.data['access_time'] = round(access_time * 1000)  # 耗时毫秒/ms
    
            # 耗时大于3s的请求,单独记录 (可将时间阈值设置在settings中,实现可配置化)
            if self.data.get('access_time') > 3 * 1000:
                AccessTimeOutLogs.objects.create(**self.data)   # 超时操作日志入库db
    
            OpLogs.objects.create(**self.data)  # 操作日志入库db
    
            return response
    
    
  2. app01.models 模型

    from django.db import models
    
    
    class OpLogs(models.Model):
        """操作日志表"""
    
        id = models.AutoField(primary_key=True)
        re_time = models.CharField(max_length=32, verbose_name='请求时间')
        re_user = models.CharField(max_length=32, verbose_name='操作人')
        re_ip = models.CharField(max_length=32, verbose_name='请求IP')
        re_url = models.CharField(max_length=255, verbose_name='请求url')
        re_method = models.CharField(max_length=11, verbose_name='请求方法')
        re_content = models.TextField(null=True, verbose_name='请求参数')
        rp_content = models.TextField(null=True, verbose_name='响应参数')
        access_time = models.IntegerField(verbose_name='响应耗时/ms')
    
        class Meta:
            db_table = 'op_logs'
    
    
    class AccessTimeOutLogs(models.Model):
        """超时操作日志表"""
    
        id = models.AutoField(primary_key=True)
        re_time = models.CharField(max_length=32, verbose_name='请求时间')
        re_user = models.CharField(max_length=32, verbose_name='操作人')
        re_ip = models.CharField(max_length=32, verbose_name='请求IP')
        re_url = models.CharField(max_length=255, verbose_name='请求url')
        re_method = models.CharField(max_length=11, verbose_name='请求方法')
        re_content = models.TextField(null=True, verbose_name='请求参数')
        rp_content = models.TextField(null=True, verbose_name='响应参数')
        access_time = models.IntegerField(verbose_name='响应耗时/ms')
    
        class Meta:
            db_table = 'access_timeout_logs'
    
posted @ 2021-07-23 17:40  SensorError  阅读(1370)  评论(0编辑  收藏  举报