diff --git a/a_long_dianjing/settings.py b/a_long_dianjing/settings.py index 8b04410..38898a6 100644 --- a/a_long_dianjing/settings.py +++ b/a_long_dianjing/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = [ ] MIDDLEWARE = [ + 'utils.debug_middleware.DebugExceptionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -51,6 +52,34 @@ MIDDLEWARE = [ 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] +# 测试阶段日志配置 — 确保 500 错误堆栈输出到 console +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format': '[%(asctime)s] %(levelname)s %(name)s: %(message)s' + }, + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'formatter': 'verbose', + }, + }, + 'loggers': { + 'django': { + 'handlers': ['console'], + 'level': 'INFO', + }, + 'utils.debug_middleware': { + 'handlers': ['console'], + 'level': 'DEBUG', + 'propagate': False, + }, + }, +} + ROOT_URLCONF = 'a_long_dianjing.urls' TEMPLATES = [ diff --git a/utils/debug_middleware.py b/utils/debug_middleware.py new file mode 100644 index 0000000..5e9bc69 --- /dev/null +++ b/utils/debug_middleware.py @@ -0,0 +1,39 @@ +""" +调试中间件 — 捕获所有 500 错误并打印完整堆栈到日志 +仅在测试阶段使用,上线前移除 +""" +import logging +import traceback + +logger = logging.getLogger('django') + + +class DebugExceptionMiddleware: + """捕获所有未处理异常,打印完整堆栈到 gunicorn 日志""" + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + response = self.get_response(request) + if response.status_code == 500: + logger.error( + f"[500] {request.method} {request.path} " + f"user={getattr(request.user, 'UserName', 'anon')}" + ) + return response + + def process_exception(self, request, exception): + """未处理异常 — 打印完整堆栈""" + tb = traceback.format_exc() + user_info = getattr(request.user, 'UserName', 'anon') + logger.error( + f"\n{'='*60}\n" + f"[EXCEPTION] {request.method} {request.path}\n" + f"User: {user_info}\n" + f"Type: {type(exception).__name__}: {exception}\n" + f"{'='*60}\n" + f"{tb}\n" + f"{'='*60}" + ) + return None # 返回 None 让 Django 继续正常异常处理流程