如何为django.server日志追加用户ID等请求元数据?
解决Django.server日志添加用户ID的问题
问题根源
django.server的日志由Django内置WSGI服务器(如runserver使用的WSGIRequestHandler)生成,这类日志的record对象仅包含socket层面信息,不携带Django的HttpRequest对象,因此你自定义的UserIdFilter无法通过record.request获取用户ID。
可行方案
方案一:自定义WSGIRequestHandler,注入用户ID到日志
通过替换runserver的请求处理器,在日志记录时主动获取用户ID并拼接格式:
- 创建自定义处理器类
# 项目/utils.py(或其他合适路径) from django.core.servers.basehttp import WSGIRequestHandler from django.contrib.auth.models import AnonymousUser class CustomRequestHandler(WSGIRequestHandler): def log_message(self, format, *args): # 从WSGI环境中提取Django请求对象 request = self.request.environ.get('django.request') user_id = "unknown" if request: if isinstance(request.user, AnonymousUser): user_id = "anon" else: user_id = request.user.id or "anon" # 拼接原日志格式与用户ID new_format = f"{format} user-id:{user_id}" super().log_message(new_format, *args)
- 修改
manage.py指定自定义处理器
# manage.py import os import sys from django.core.management.commands.runserver import Command as RunserverCommand from myproject.utils import CustomRequestHandler # 替换为你的实际路径 RunserverCommand.default_request_handler = CustomRequestHandler def main(): os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line(sys.argv) if __name__ == '__main__': main()
- 简化日志配置(无需额外过滤器)
# settings.py LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'loggers': { 'django.server': { 'handlers': ['console'], 'level': 'INFO', 'propagate': False, }, }, }
方案二:通过中间件自定义请求日志(替代django.server)
如果不需要严格依赖django.server的日志来源,用中间件实现更灵活的日志记录,直接获取HttpRequest对象:
- 创建日志中间件
# middleware.py import logging from datetime import datetime request_logger = logging.getLogger('custom.request') class RequestLogMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) # 获取用户ID user_id = request.user.id if request.user.is_authenticated else "anon" # 构造匹配原django.server格式的日志内容 asctime = datetime.now().strftime('%d/%b/%Y %H:%M:%S') log_msg = f'[{asctime}] "{request.method} {request.path} {request.META["SERVER_PROTOCOL"]}" {response.status_code} {response.content_length or 0} user-id:{user_id}' request_logger.info(log_msg) return response
- 注册中间件
# settings.py MIDDLEWARE = [ # 建议放在靠前位置,确保所有请求都被记录 'myproject.middleware.RequestLogMiddleware', # 替换为实际路径 # ... 其他中间件 ]
- 配置自定义日志记录器
# settings.py LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, 'null': { 'class': 'logging.NullHandler', }, }, 'loggers': { 'custom.request': { 'handlers': ['console'], 'level': 'INFO', 'propagate': False, }, # 关闭django.server日志避免重复输出 'django.server': { 'handlers': ['null'], 'level': 'INFO', 'propagate': False, }, }, }
方案对比
- 方案一:严格保留
django.server日志来源,适合需要维持原有日志体系的场景,但仅对runserver生效(生产环境使用Gunicorn/uWSGI需单独调整)。 - 方案二:通用性更强,生产环境可直接使用,日志格式完全可控,但需要替换原
django.server的日志输出。
内容的提问来源于stack exchange,提问作者sajith.vim
相关产品推荐
相关产品推荐

