django 日志默认打印 request 请求信息

4,481 阅读2分钟

django 日志默认打印 request 请求信息

需求

请求view中手动打印日志时中插入request的如下信息(每个request请求都记录可以使用中间件进行解决,但这里仅仅是在需要的地方手动打印):

 #统一附加日志内容

ADD_LOG = r'''{"username": request.user, "path": request.path, "request_id": request.id, "login_id": request.login_id}'''

旧的解决办法

在每次需要打印日志时,通过 logging extra 进行额外的打印信息添加:
每次手动添加同样的extra非常的不优雅。

image.png

新的解决方案

django 自带log系统官方文档

1、熟悉python的logging模块结构。

  1. Loggers
  2. Handlers
  3. Filters
  4. Formatters

2、django中间件存储request信息。


class RequestLogMiddleware(MiddlewareMixin):
    """
    将request的信息记录在当前的请求线程上
    """
    def process_request(self, request):
        # 统一附加日志内容
        # ADD_LOG = r'''{"username": request.user, "path": request.path, "request_id": request.id, "login_id": request.login_id}'''
        local.path = request.path
        local.request_id = request.id
        local.login_id = request.login_id
        local.username = request.user.username

3、logging的filters模块添加request信息。

import logging

class RequestLogFilter(logging.Filter):
    """
    日志过滤器,将当前请求线程的request信息保存到日志的record上下文
    """
    def filter(self, record):
        record.request_id = getattr(local, 'request_id', "none")
        record.path = getattr(local, 'path', "none")
        record.login_id = getattr(local, 'login_id', "none")
        record.username = getattr(local, 'username', "none")
        record.appName = getattr(local, "appName", "none")
        return True

4、实现原理及代码

通过 local = threading.local()

middleware-waiwen文件代码:

import threading
import logging
try:
    from django.utils.deprecation import MiddlewareMixin  # Django 1.10.x
except ImportError:
    MiddlewareMixin = object  # Django 1.4.x - Django 1.9.x

local = threading.local()
class RequestLogFilter(logging.Filter):
    """
    日志过滤器,将当前请求线程的request信息保存到日志的record上下文
    record带有formater需要的信息。
    """
    def filter(self, record):
        record.request_id = getattr(local, 'request_id', "none")
        record.path = getattr(local, 'path', "none")
        record.login_id = getattr(local, 'login_id', "none")
        record.username = getattr(local, 'username', "none")
        return True

class RequestLogMiddleware(MiddlewareMixin):
    """
    将request的信息记录在当前的请求线程上。
    """
    def process_request(self, request):
        # 统一附加日志内容
        # ADD_LOG = r'''{"username": request.user, "path": request.path, "request_id": request.id, "login_id": request.login_id}'''
        local.path = request.path
        local.request_id = request.id
        local.login_id = request.login_id
        local.username = request.user.username

settings 文件配置

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
  
    'wcloud.middleware-waiwen.RequestLogMiddleware'  
     #使用该中间件
     #将当前的request信息保存到当前线程供日志打印使用
]


LOGGING = {
        # 日志相关
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': '{"date": "%(created)f", "level": "%(levelname)s", "funcName": "%(module)s.%(funcName)s:%(lineno)d", "msg": "%(message)s"}'},  # 日志格式
            'custom': {
              #该格式化中包含有过滤器record新增的字段
                'format': '{"date": "%(created)f", "level": "%(levelname)s", "funcName": "%(module)s.%(funcName)s:%(lineno)d", "request_id": "%(request_id)s","login_id": "%(login_id)s", "username": "%(username)s", "path": "%(path)s","msg": "%(message)s"}'
            },
        },
        'filters': {
            #注册该过滤器
            'request_info': {'()': 'wcloud.middleware-waiwen.RequestLogFilter'}
        },
        'handlers': {
            'log': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
                'formatter': 'custom',
              #在该过handler中使用该过滤器
                'filters': ['request_info'], 
            },
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
                'formatter': 'standard',
            },
        },
        'loggers': {
            'django': {
                'handlers': ['console'],
                'level': 'ERROR',
                'propagate': False
            },
            'django.request': {
                'handlers': ['console'],
                'level': 'ERROR',
                'propagate': False
            },
            'django.db.backens': {
                'handlers': ['console'],
                'level': 'DEBUG',
                'propagate': False
            },
            'log': {
                'handlers': ['log'],
                'level': 'INFO',
                'propagate': True
            },
           
        }
    }

5、效果

image.png

参考:

给Django日志加上request_id