Django中间件实现操作日志
本文通过Django中间件的流程,实现操作日志记录的功能,模块化、拿来即用。
功能描述:通过中间件记录 请求时间
、操作用户
、请求URL
、请求方法
、请求IP
、请求参数
和响应数据
、响应耗时
等数据日志,而且可以自定义exclude_urls
列表,访问列表中的url,不会保存操作日志。另外,通过设置的响应时间阈值(可配置化),将超过阈值的操作日志进行单独保存,便于分析。
说明:示例中将是数据记录在MySQL
数据库中,如果你想写入log日志
,只需将数据入库改为log格式写入即可(数据都放在self.data
中,取用方便)。
创建中间件
-
在app01下新建文件夹
middlewares
, 在文件夹下新建中间件文件LogMiddleware.py
-
在中间件文件中新建一个类, 继承MiddlewareMixin:
from django.utils.deprecation import MiddlewareMixin class OpLogs(MiddlewareMixin): def process_request(self, request): pass
-
在settings中注册中间件:
# 自定义中间件 MIDDLEWARE += [ 'app01.middlewares.LogMiddleware.OpLogs' ]
功能实现
-
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
-
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'