feat: 增加全局异常处理、使用route_class记录请求日志
This commit is contained in:
parent
e7cc1e5e18
commit
0ef41c6cde
@ -2,6 +2,8 @@ from fastapi.exceptions import HTTPException
|
|||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
from starlette.responses import JSONResponse
|
from starlette.responses import JSONResponse
|
||||||
|
|
||||||
|
from core.log import logger
|
||||||
|
|
||||||
|
|
||||||
class TokenAuthFailure(HTTPException):
|
class TokenAuthFailure(HTTPException):
|
||||||
pass
|
pass
|
||||||
@ -19,4 +21,18 @@ async def http_exception(request: Request, exc: HTTPException):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
exception_handlers = {HTTPException: http_exception}
|
async def global_exception(request: Request, exc):
|
||||||
|
if hasattr(request.state, "request_id"):
|
||||||
|
request_id = request.state.request_id
|
||||||
|
else:
|
||||||
|
request_id = None
|
||||||
|
logger.info("request_id 获取失败 请确认对应APIRouter使用了route_class=LogRoute ")
|
||||||
|
logger.exception(f"{request_id} Exception Log: {exc}")
|
||||||
|
return JSONResponse({
|
||||||
|
"msg": str(exc),
|
||||||
|
"code": 500,
|
||||||
|
"data": None
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
exception_handlers = {Exception: global_exception, HTTPException: http_exception}
|
||||||
|
@ -2,7 +2,14 @@ import logging
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
handler = logging.StreamHandler()
|
|
||||||
|
# 创建一个 FileHandler,用于写入日志文件
|
||||||
|
handler = logging.FileHandler('log_file.log')
|
||||||
|
handler.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# 设置日志格式
|
||||||
formatter = logging.Formatter("[%(asctime)s] %(levelname)s %(message)s")
|
formatter = logging.Formatter("[%(asctime)s] %(levelname)s %(message)s")
|
||||||
handler.setFormatter(formatter)
|
handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
# 添加 FileHandler 到日志处理器中
|
||||||
logger.addHandler(handler)
|
logger.addHandler(handler)
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
|
import time
|
||||||
|
import uuid
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
from fastapi.middleware import Middleware
|
from fastapi.middleware import Middleware
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from fastapi.routing import APIRoute
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
from starlette.requests import Request
|
||||||
|
from starlette.responses import Response
|
||||||
|
|
||||||
from core.log import logger
|
from core.log import logger
|
||||||
|
|
||||||
|
|
||||||
|
# fix: 中间件没法获取到request 请求体数据 响应体
|
||||||
class CustomRequestLogMiddleware(BaseHTTPMiddleware):
|
class CustomRequestLogMiddleware(BaseHTTPMiddleware):
|
||||||
async def dispatch(self, request, call_next):
|
async def dispatch(self, request, call_next):
|
||||||
logger.info(
|
logger.info(
|
||||||
@ -16,8 +24,28 @@ class CustomRequestLogMiddleware(BaseHTTPMiddleware):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class LogRoute(APIRoute):
|
||||||
|
def get_route_handler(self) -> Callable:
|
||||||
|
original_route_handler = super().get_route_handler()
|
||||||
|
|
||||||
|
async def custom_route_handler(request: Request) -> Response:
|
||||||
|
request_id = str(uuid.uuid4())
|
||||||
|
request.state.request_id = request_id
|
||||||
|
logger.info(f"{request_id} Request Log {request.client} {request.method}"
|
||||||
|
f" {request.url} {request.headers}\n {await request.body()}")
|
||||||
|
before = time.time()
|
||||||
|
response: Response = await original_route_handler(request)
|
||||||
|
duration = time.time() - before
|
||||||
|
response.headers["X-Response-Time"] = str(duration)
|
||||||
|
logger.info(f"{request_id} Response Log {duration}s {response.headers}\n"
|
||||||
|
f" {response.body.decode('utf-8')}")
|
||||||
|
return response
|
||||||
|
|
||||||
|
return custom_route_handler
|
||||||
|
|
||||||
|
|
||||||
middlewares = [
|
middlewares = [
|
||||||
Middleware(CustomRequestLogMiddleware),
|
# Middleware(CustomRequestLogMiddleware),
|
||||||
Middleware(
|
Middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
allow_origins=["*"],
|
allow_origins=["*"],
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
from fastapi import APIRouter, WebSocket
|
from fastapi import APIRouter, WebSocket
|
||||||
|
|
||||||
|
from core.middleware import LogRoute
|
||||||
from schemas import common as BaseSchema
|
from schemas import common as BaseSchema
|
||||||
from service import auth as AuthService
|
from service import auth as AuthService
|
||||||
|
|
||||||
router = APIRouter(tags=["公共"])
|
router = APIRouter(tags=["公共"], route_class=LogRoute)
|
||||||
|
|
||||||
|
|
||||||
LoginResult = BaseSchema.Response[BaseSchema.LoginResult]
|
LoginResult = BaseSchema.Response[BaseSchema.LoginResult]
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from core.middleware import LogRoute
|
||||||
from schemas import common as BaseSchema
|
from schemas import common as BaseSchema
|
||||||
from schemas import menu as MenuSchema
|
from schemas import menu as MenuSchema
|
||||||
from service.menu import service as MenuService
|
from service.menu import service as MenuService
|
||||||
|
|
||||||
router = APIRouter(prefix="/menu", tags=["菜单管理"])
|
router = APIRouter(prefix="/menu", tags=["菜单管理"], route_class=LogRoute)
|
||||||
|
|
||||||
Response = BaseSchema.Response
|
Response = BaseSchema.Response
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from core.middleware import LogRoute
|
||||||
from schemas import common as BaseSchema
|
from schemas import common as BaseSchema
|
||||||
from schemas import role as RoleSchema
|
from schemas import role as RoleSchema
|
||||||
from schemas.common import QueryData
|
from schemas.common import QueryData
|
||||||
from service.role import service as RoleService
|
from service.role import service as RoleService
|
||||||
|
|
||||||
router = APIRouter(prefix="/role", tags=["角色管理"])
|
router = APIRouter(prefix="/role", tags=["角色管理"], route_class=LogRoute)
|
||||||
|
|
||||||
Response = BaseSchema.Response
|
Response = BaseSchema.Response
|
||||||
ListAll = BaseSchema.ListAll
|
ListAll = BaseSchema.ListAll
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from core.middleware import LogRoute
|
||||||
from core.security import check_permissions
|
from core.security import check_permissions
|
||||||
from schemas import common as BaseSchema
|
from schemas import common as BaseSchema
|
||||||
from schemas import user as UserSchema
|
from schemas import user as UserSchema
|
||||||
from schemas.common import QueryData
|
from schemas.common import QueryData
|
||||||
from service.user import service as UserService
|
from service.user import service as UserService
|
||||||
|
|
||||||
router = APIRouter(prefix="/user", tags=["用户管理"])
|
router = APIRouter(prefix="/user", tags=["用户管理"], route_class=LogRoute)
|
||||||
|
|
||||||
Response = BaseSchema.Response
|
Response = BaseSchema.Response
|
||||||
ListAll = BaseSchema.ListAll
|
ListAll = BaseSchema.ListAll
|
||||||
|
Loading…
Reference in New Issue
Block a user