You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django错误日志中添加额外信息增强调试能力?

问题场景

我有一个会抛出除零异常的Django视图:

# views.py
def view1(request):
    val = 5 / 0
    return JsonResponse({"val": val})

同时我的Django配置中DEBUG=False,日志配置如下:

# settings.py
DEBUG = False
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': f'{BASE_DIR}/logs/debug.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

调用该视图时,日志仅输出异常栈信息,但缺少请求URL、查询参数、请求载荷、请求头等调试关键信息,请问如何把这些信息添加到错误日志中?

解决方案

方法一:自定义日志过滤器

通过Django日志过滤器,在日志输出时自动注入请求上下文信息:

  1. 在项目中创建filters.py,编写自定义过滤器:
# filters.py
import logging

class RequestLogFilter(logging.Filter):
    def filter(self, record):
        # 检查日志记录是否携带request对象
        if hasattr(record, 'request'):
            request = record.request
            # 注入请求URL
            record.url = request.get_full_path()
            # 注入查询参数
            record.query_params = request.GET.dict()
            # 注入请求载荷(区分JSON和表单数据)
            if request.content_type == 'application/json':
                record.payload = request.body.decode('utf-8')
            else:
                record.payload = request.POST.dict()
            # 注入关键请求头
            record.user_agent = request.META.get('HTTP_USER_AGENT', '')
            record.auth_header = request.META.get('HTTP_AUTHORIZATION', '')
        else:
            # 无request时填充默认值
            record.url = 'N/A'
            record.query_params = 'N/A'
            record.payload = 'N/A'
            record.user_agent = 'N/A'
            record.auth_header = 'N/A'
        return True
  1. 修改settings.py中的日志配置,添加过滤器并更新日志格式:
# settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'request_log': {
            '()': 'your_project_name.filters.RequestLogFilter',  # 替换为你的项目路径
        },
    },
    'formatters': {
        'detailed_error': {
            'format': '''
Internal Server Error: %(url)s
Query Params: %(query_params)s
Request Payload: %(payload)s
User-Agent: %(user_agent)s
Authorization: %(auth_header)s
%(message)s
            ''',
        },
    },
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': f'{BASE_DIR}/logs/debug.log',
            'filters': ['request_log'],
            'formatter': 'detailed_error',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

Django默认的异常处理器会自动把request对象附加到日志记录中,无需额外修改即可生效。

方法二:自定义异常处理器

直接重写Django的异常处理函数,主动记录包含请求信息的错误日志:

  1. 创建exception_handlers.py编写自定义处理器:
# exception_handlers.py
import logging
from django.core.handlers.exception import response_for_exception

logger = logging.getLogger('django')

def custom_exception_handler(request, exception):
    # 拼接包含请求信息的日志内容
    log_content = f'''
Internal Server Error: {request.get_full_path()}
Query Params: {request.GET.dict()}
Request Payload: {request.body.decode('utf-8') if request.content_type == 'application/json' else request.POST.dict()}
User-Agent: {request.META.get('HTTP_USER_AGENT', '')}
    '''
    # 输出日志并附带异常栈
    logger.error(log_content, exc_info=True)
    
    # 调用默认处理器生成响应
    response = response_for_exception(request, exception)
    return response
  1. 在settings.py中配置使用该处理器:
# settings.py
EXCEPTION_HANDLER = 'your_project_name.exception_handlers.custom_exception_handler'

方法三:中间件+线程局部变量

通过中间件把请求存入线程局部变量,确保日志过滤器能获取到当前请求上下文:

  1. 创建middleware.py:
# middleware.py
import threading
from django.utils.deprecation import MiddlewareMixin

_thread_locals = threading.local()

def get_current_request():
    return getattr(_thread_locals, 'request', None)

class RequestMiddleware(MiddlewareMixin):
    def process_request(self, request):
        _thread_locals.request = request

    def process_response(self, request, response):
        _thread_locals.request = None
        return response
  1. 在settings.py中注册中间件(放在靠前位置):
# settings.py
MIDDLEWARE = [
    'your_project_name.middleware.RequestMiddleware',
    # 原有中间件...
]
  1. 修改RequestLogFilter,从线程局部变量获取请求:
# filters.py
from .middleware import get_current_request

class RequestLogFilter(logging.Filter):
    def filter(self, record):
        request = get_current_request()
        if request:
            record.url = request.get_full_path()
            record.query_params = request.GET.dict()
            record.payload = request.body.decode('utf-8') if request.content_type == 'application/json' else request.POST.dict()
            record.user_agent = request.META.get('HTTP_USER_AGENT', '')
            record.auth_header = request.META.get('HTTP_AUTHORIZATION', '')
        else:
            record.url = 'N/A'
            record.query_params = 'N/A'
            record.payload = 'N/A'
            record.user_agent = 'N/A'
            record.auth_header = 'N/A'
        return True

这种方式适用于无法直接传递request对象的日志场景,确保所有错误日志都能携带请求上下文。

内容的提问来源于stack exchange,提问作者ONMNZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 23:42:30