• 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'
      
  • 相关阅读:
    【vue开发问题-解决方法】(十一)数据双向绑定导致修改数据格式原数据绑定出错
    【JavaScript】使用url下载文件,解决chrome浏览器自动识别图片打开问题。
    我的转行之路(电气转IT)------2018阿里校招面经
    关于Class.getResource和ClassLoader.getResource的路径问题
    protected修饰符详解
    为什么i=i++后,i的值不变(深入解析)
    Java中的初始化详细解析
    再谈抽象类(感觉理解的更深了)
    数据类型总结(干货)
    Java的接口和抽象类深入理解
  • 原文地址:https://www.cnblogs.com/yzm1017/p/15049914.html
Copyright © 2020-2023  润新知