diff --git a/backend/app/admin/service/login_log_service.py b/backend/app/admin/service/login_log_service.py index c80e92e7..be512b35 100644 --- a/backend/app/admin/service/login_log_service.py +++ b/backend/app/admin/service/login_log_service.py @@ -47,7 +47,7 @@ async def create( ) await login_log_dao.create(db, obj_in) except Exception as e: - log.exception(f'登录日志创建失败: {e}') + log.error(f'登录日志创建失败: {e}') @staticmethod async def delete(*, pk: list[int]) -> int: diff --git a/backend/common/exception/exception_handler.py b/backend/common/exception/exception_handler.py index 0db40994..24c89f46 100644 --- a/backend/common/exception/exception_handler.py +++ b/backend/common/exception/exception_handler.py @@ -9,7 +9,6 @@ from uvicorn.protocols.http.h11_impl import STATUS_PHRASES from backend.common.exception.errors import BaseExceptionMixin -from backend.common.log import log from backend.common.response.response_code import CustomResponseCode, StandardResponseCode from backend.common.response.response_schema import response_base from backend.common.schema import ( @@ -78,9 +77,9 @@ async def _validation_exception_handler(request: Request, e: RequestValidationEr 'code': StandardResponseCode.HTTP_422, 'msg': msg, 'data': data, - 'trace_id': get_request_trace_id(request), } request.state.__request_validation_exception__ = content # 用于在中间件中获取异常信息 + content.update(trace_id=get_request_trace_id(request)) return MsgSpecJSONResponse(status_code=422, content=content) @@ -103,10 +102,11 @@ async def http_exception_handler(request: Request, exc: HTTPException): else: res = response_base.fail(res=CustomResponseCode.HTTP_400) content = res.model_dump() - request.state.__request_http_exception__ = content # 用于在中间件中获取异常信息 + request.state.__request_http_exception__ = content + content.update(trace_id=get_request_trace_id(request)) return MsgSpecJSONResponse( status_code=_get_exception_code(exc.status_code), - content=content.update(trace_id=get_request_trace_id(request)), + content=content, headers=exc.headers, ) @@ -141,14 +141,16 @@ async def pydantic_user_error_handler(request: Request, exc: PydanticUserError): :param exc: :return: """ + content = { + 'code': StandardResponseCode.HTTP_500, + 'msg': CUSTOM_USAGE_ERROR_MESSAGES.get(exc.code), + 'data': None, + } + request.state.__request_pydantic_user_error__ = content + content.update(trace_id=get_request_trace_id(request)) return MsgSpecJSONResponse( status_code=StandardResponseCode.HTTP_500, - content={ - 'code': StandardResponseCode.HTTP_500, - 'msg': CUSTOM_USAGE_ERROR_MESSAGES.get(exc.code), - 'data': None, - 'trace_id': get_request_trace_id(request), - }, + content=content, ) @app.exception_handler(AssertionError) @@ -169,44 +171,44 @@ async def assertion_error_handler(request: Request, exc: AssertionError): else: res = response_base.fail(res=CustomResponseCode.HTTP_500) content = res.model_dump() + request.state.__request_assertion_error__ = content + content.update(trace_id=get_request_trace_id(request)) return MsgSpecJSONResponse( status_code=StandardResponseCode.HTTP_500, - content=content.update(trace_id=get_request_trace_id(request)), + content=content, ) @app.exception_handler(BaseExceptionMixin) async def custom_exception_handler(request: Request, exc: BaseExceptionMixin): """ - 全局异常处理 + 全局自定义异常处理 :param request: :param exc: :return: """ + content = { + 'code': exc.code, + 'msg': str(exc.msg), + 'data': exc.data if exc.data else None, + } + request.state.__request_custom_exception__ = content + content.update(trace_id=get_request_trace_id(request)) return MsgSpecJSONResponse( status_code=_get_exception_code(exc.code), - content={ - 'code': exc.code, - 'msg': str(exc.msg), - 'data': exc.data if exc.data else None, - 'trace_id': get_request_trace_id(request), - }, + content=content, background=exc.background, ) @app.exception_handler(Exception) - async def all_exception_handler(request: Request, exc: Exception): + async def all_unknown_exception_handler(request: Request, exc: Exception): """ - 全局异常处理 + 全局未知异常处理 :param request: :param exc: :return: """ - import traceback - - log.error(f'未知异常: {exc}') - log.error(traceback.format_exc()) if settings.ENVIRONMENT == 'dev': content = { 'code': StandardResponseCode.HTTP_500, @@ -216,9 +218,11 @@ async def all_exception_handler(request: Request, exc: Exception): else: res = response_base.fail(res=CustomResponseCode.HTTP_500) content = res.model_dump() + request.state.__request_all_unknown_exception__ = content + content.update(trace_id=get_request_trace_id(request)) return MsgSpecJSONResponse( status_code=StandardResponseCode.HTTP_500, - content=content.update(trace_id=get_request_trace_id(request)), + content=content, ) if settings.MIDDLEWARE_CORS: @@ -251,9 +255,11 @@ async def cors_custom_code_500_exception_handler(request, exc): else: res = response_base.fail(res=CustomResponseCode.HTTP_500) content = res.model_dump() + request.state.__request_cors_500_exception__ = content + content.update(trace_id=get_request_trace_id(request)) response = MsgSpecJSONResponse( status_code=exc.code if isinstance(exc, BaseExceptionMixin) else StandardResponseCode.HTTP_500, - content=content.update(trace_id=get_request_trace_id(request)), + content=content, background=exc.background if isinstance(exc, BaseExceptionMixin) else None, ) origin = request.headers.get('origin') diff --git a/backend/middleware/opera_log_middleware.py b/backend/middleware/opera_log_middleware.py index d8191449..66bc132b 100644 --- a/backend/middleware/opera_log_middleware.py +++ b/backend/middleware/opera_log_middleware.py @@ -53,7 +53,7 @@ async def dispatch(self, request: Request, call_next) -> Response: # 执行请求 start_time = timezone.now() - res = await self.execute_request(request, call_next) + request_next = await self.execute_request(request, call_next) end_time = timezone.now() cost_time = (end_time - start_time).total_seconds() * 1000.0 @@ -77,20 +77,20 @@ async def dispatch(self, request: Request, call_next) -> Response: browser=request.state.browser, device=request.state.device, args=args, - status=res.status, - code=res.code, - msg=res.msg, + status=request_next.status, + code=request_next.code, + msg=request_next.msg, cost_time=cost_time, opera_time=start_time, ) create_task(OperaLogService.create(obj_in=opera_log_in)) # noqa: ignore # 错误抛出 - err = res.err + err = request_next.err if err: raise err from None - return res.response + return request_next.response async def execute_request(self, request: Request, call_next) -> RequestCallNext: """执行请求""" @@ -101,7 +101,7 @@ async def execute_request(self, request: Request, call_next) -> RequestCallNext: response = None try: response = await call_next(request) - code, msg = self.validation_exception_handler(request, code, msg) + code, msg = self.request_exception_handler(request, code, msg) except Exception as e: log.error(f'请求异常: {e}') # code 处理包含 SQLAlchemy 和 Pydantic @@ -113,22 +113,24 @@ async def execute_request(self, request: Request, call_next) -> RequestCallNext: return RequestCallNext(code=str(code), msg=msg, status=status, err=err, response=response) @staticmethod - def validation_exception_handler(request: Request, code: int, msg: str) -> tuple[str, str]: + def request_exception_handler(request: Request, code: int, msg: str) -> tuple[str, str]: """请求异常处理器""" - try: - http_exception = request.state.__request_http_exception__ - except AttributeError: - pass - else: - code = http_exception.get('code', 500) - msg = http_exception.get('msg', 'Internal Server Error') - try: - validation_exception = request.state.__request_validation_exception__ - except AttributeError: - pass - else: - code = validation_exception.get('code', 400) - msg = validation_exception.get('msg', 'Bad Request') + exception_states = [ + '__request_http_exception__', + '__request_validation_exception__', + '__request_pydantic_user_error__', + '__request_assertion_error__', + '__request_custom_exception__', + '__request_all_unknown_exception__', + '__request_cors_500_exception__', + ] + for state in exception_states: + exception = getattr(request.state, state, None) + if exception: + code = exception.get('code') + msg = exception.get('msg') + break + log.error(f'请求异常: {msg}') return code, msg @staticmethod