如何在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日志过滤器,在日志输出时自动注入请求上下文信息:
- 在项目中创建
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
- 修改
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的异常处理函数,主动记录包含请求信息的错误日志:
- 创建
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
- 在
settings.py中配置使用该处理器:
# settings.py EXCEPTION_HANDLER = 'your_project_name.exception_handlers.custom_exception_handler'
方法三:中间件+线程局部变量
通过中间件把请求存入线程局部变量,确保日志过滤器能获取到当前请求上下文:
- 创建
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
- 在
settings.py中注册中间件(放在靠前位置):
# settings.py MIDDLEWARE = [ 'your_project_name.middleware.RequestMiddleware', # 原有中间件... ]
- 修改
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
相关产品推荐
相关产品推荐

