1+ import json
2+ import traceback
13from fastapi import HTTPException , Request
24from fastapi .exceptions import RequestValidationError , ResponseValidationError
35from fastapi .responses import JSONResponse
46from starlette .responses import Response
57from tortoise .exceptions import DoesNotExist , IntegrityError
68
9+ from log import logger
710from settings .config import settings
811
912
@@ -12,6 +15,35 @@ class SettingNotFound(Exception):
1215
1316
1417async def DoesNotExistHandle (req : Request , exc : DoesNotExist ) -> JSONResponse :
18+ # 记录详细的错误信息到日志
19+ error_details = {
20+ "method" : req .method ,
21+ "url" : str (req .url ),
22+ "path" : req .url .path ,
23+ "query_params" : dict (req .query_params ),
24+ "client_ip" : req .client .host if req .client else None ,
25+ "user_agent" : req .headers .get ("user-agent" ),
26+ "exception_type" : type (exc ).__name__ ,
27+ "exception_msg" : str (exc ),
28+ "traceback" : traceback .format_exc ()
29+ }
30+
31+ # 构建详细的错误信息
32+ error_message = f"DoesNotExist异常: { req .method } { req .url .path } - { exc } \n "
33+ error_message += f"Exception Type: { type (exc ).__name__ } \n "
34+ error_message += f"Exception Message: { str (exc )} \n "
35+ error_message += f"\n Stack Trace:\n { error_details .get ('traceback' , 'No traceback available' )} \n "
36+ error_message += f"\n Request Context:\n "
37+ for key , value in error_details .items ():
38+ if key != 'traceback' :
39+ if isinstance (value , dict ):
40+ error_message += f" { key } : { json .dumps (value , indent = 2 , ensure_ascii = False )} \n "
41+ else :
42+ error_message += f" { key } : { value } \n "
43+ error_message += "=" * 80
44+
45+ logger .error (error_message )
46+
1547 # 根据环境决定错误信息详细程度
1648 if settings .DEBUG :
1749 msg = f"Object not found: { exc } , query_params: { req .query_params } "
@@ -23,6 +55,30 @@ async def DoesNotExistHandle(req: Request, exc: DoesNotExist) -> JSONResponse:
2355
2456
2557async def HttpExcHandle (request : Request , exc : HTTPException ):
58+ # 记录HTTP异常详情
59+ error_details = {
60+ "method" : request .method ,
61+ "url" : str (request .url ),
62+ "path" : request .url .path ,
63+ "query_params" : dict (request .query_params ),
64+ "client_ip" : request .client .host if request .client else None ,
65+ "user_agent" : request .headers .get ("user-agent" ),
66+ "status_code" : exc .status_code ,
67+ "exception_type" : type (exc ).__name__ ,
68+ "exception_msg" : str (exc .detail ),
69+ "traceback" : traceback .format_exc ()
70+ }
71+
72+ # 根据状态码决定日志级别
73+ if exc .status_code >= 500 :
74+ logger .bind (** error_details ).error (
75+ f"HTTP { exc .status_code } 异常: { request .method } { request .url .path } - { exc .detail } "
76+ )
77+ elif exc .status_code >= 400 :
78+ logger .bind (** error_details ).warning (
79+ f"HTTP { exc .status_code } 异常: { request .method } { request .url .path } - { exc .detail } "
80+ )
81+
2682 if exc .status_code == 401 and exc .headers and "WWW-Authenticate" in exc .headers :
2783 return Response (status_code = exc .status_code , headers = exc .headers )
2884 return JSONResponse (
@@ -32,6 +88,23 @@ async def HttpExcHandle(request: Request, exc: HTTPException):
3288
3389
3490async def IntegrityHandle (request : Request , exc : IntegrityError ):
91+ # 记录数据完整性错误详情
92+ error_details = {
93+ "method" : request .method ,
94+ "url" : str (request .url ),
95+ "path" : request .url .path ,
96+ "query_params" : dict (request .query_params ),
97+ "client_ip" : request .client .host if request .client else None ,
98+ "user_agent" : request .headers .get ("user-agent" ),
99+ "exception_type" : type (exc ).__name__ ,
100+ "exception_msg" : str (exc ),
101+ "traceback" : traceback .format_exc ()
102+ }
103+
104+ logger .bind (** error_details ).error (
105+ f"数据完整性错误: { request .method } { request .url .path } - { exc } "
106+ )
107+
35108 # 根据环境决定错误信息详细程度
36109 if settings .DEBUG :
37110 msg = f"IntegrityError: { exc } "
@@ -43,11 +116,29 @@ async def IntegrityHandle(request: Request, exc: IntegrityError):
43116
44117
45118async def RequestValidationHandle (
46- _ : Request , exc : RequestValidationError
119+ request : Request , exc : RequestValidationError
47120) -> JSONResponse :
121+ # 记录请求验证错误详情
122+ error_details = {
123+ "method" : request .method ,
124+ "url" : str (request .url ),
125+ "path" : request .url .path ,
126+ "query_params" : dict (request .query_params ),
127+ "client_ip" : request .client .host if request .client else None ,
128+ "user_agent" : request .headers .get ("user-agent" ),
129+ "exception_type" : type (exc ).__name__ ,
130+ "exception_msg" : str (exc ),
131+ "validation_errors" : exc .errors (),
132+ "traceback" : traceback .format_exc ()
133+ }
134+
135+ logger .bind (** error_details ).warning (
136+ f"请求参数验证失败: { request .method } { request .url .path } - { len (exc .errors ())} 个错误"
137+ )
138+
48139 # 根据环境决定错误信息详细程度
49140 if settings .DEBUG :
50- msg = f"RequestValidationError: { exc } "
141+ msg = f"RequestValidationError: { exc . errors () } "
51142 else :
52143 msg = "请求参数验证失败,请检查输入格式"
53144
@@ -56,13 +147,68 @@ async def RequestValidationHandle(
56147
57148
58149async def ResponseValidationHandle (
59- _ : Request , exc : ResponseValidationError
150+ request : Request , exc : ResponseValidationError
60151) -> JSONResponse :
152+ # 记录响应验证错误详情
153+ error_details = {
154+ "method" : request .method ,
155+ "url" : str (request .url ),
156+ "path" : request .url .path ,
157+ "query_params" : dict (request .query_params ),
158+ "client_ip" : request .client .host if request .client else None ,
159+ "user_agent" : request .headers .get ("user-agent" ),
160+ "exception_type" : type (exc ).__name__ ,
161+ "exception_msg" : str (exc ),
162+ "validation_errors" : exc .errors (),
163+ "traceback" : traceback .format_exc ()
164+ }
165+
166+ logger .bind (** error_details ).error (
167+ f"响应格式验证错误: { request .method } { request .url .path } - { len (exc .errors ())} 个错误"
168+ )
169+
61170 # 根据环境决定错误信息详细程度
62171 if settings .DEBUG :
63- msg = f"ResponseValidationError: { exc } "
172+ msg = f"ResponseValidationError: { exc . errors () } "
64173 else :
65174 msg = "服务器响应格式错误"
66175
67176 content = dict (code = 500 , msg = msg )
68177 return JSONResponse (content = content , status_code = 500 )
178+
179+
180+ async def UnhandledExceptionHandle (request : Request , exc : Exception ) -> JSONResponse :
181+ """处理所有未捕获的异常"""
182+ # 记录未处理异常的详细信息
183+ error_details = {
184+ "method" : request .method ,
185+ "url" : str (request .url ),
186+ "path" : request .url .path ,
187+ "query_params" : dict (request .query_params ),
188+ "client_ip" : request .client .host if request .client else None ,
189+ "user_agent" : request .headers .get ("user-agent" ),
190+ "exception_type" : type (exc ).__name__ ,
191+ "exception_msg" : str (exc ),
192+ "exception_module" : getattr (exc , "__module__" , "unknown" ),
193+ "traceback" : traceback .format_exc ()
194+ }
195+
196+ # 尝试获取请求体信息(如果可能)
197+ try :
198+ if hasattr (request , "_body" ):
199+ error_details ["request_body_size" ] = len (request ._body ) if request ._body else 0
200+ except Exception :
201+ pass
202+
203+ logger .bind (** error_details ).critical (
204+ f"未处理的异常: { request .method } { request .url .path } - { type (exc ).__name__ } : { exc } "
205+ )
206+
207+ # 根据环境决定错误信息详细程度
208+ if settings .DEBUG :
209+ msg = f"Unhandled exception: { type (exc ).__name__ } : { exc } "
210+ else :
211+ msg = "服务器内部错误,请稍后重试"
212+
213+ content = dict (code = 500 , msg = msg )
214+ return JSONResponse (content = content , status_code = 500 )
0 commit comments