feat: 增加全局异常处理、使用route_class记录请求日志

This commit is contained in:
zy7y 2023-06-14 19:52:28 +08:00
parent e7cc1e5e18
commit 0ef41c6cde
7 changed files with 62 additions and 7 deletions

View File

@ -2,6 +2,8 @@ from fastapi.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse
from core.log import logger
class TokenAuthFailure(HTTPException):
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}

View File

@ -2,7 +2,14 @@ import logging
logger = logging.getLogger(__name__)
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")
handler.setFormatter(formatter)
# 添加 FileHandler 到日志处理器中
logger.addHandler(handler)

View File

@ -1,10 +1,18 @@
import time
import uuid
from typing import Callable
from fastapi.middleware import Middleware
from fastapi.middleware.cors import CORSMiddleware
from fastapi.routing import APIRoute
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response
from core.log import logger
# fix 中间件没法获取到request 请求体数据 响应体
class CustomRequestLogMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
logger.info(
@ -16,8 +24,28 @@ class CustomRequestLogMiddleware(BaseHTTPMiddleware):
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 = [
Middleware(CustomRequestLogMiddleware),
# Middleware(CustomRequestLogMiddleware),
Middleware(
CORSMiddleware,
allow_origins=["*"],

View File

@ -1,9 +1,10 @@
from fastapi import APIRouter, WebSocket
from core.middleware import LogRoute
from schemas import common as BaseSchema
from service import auth as AuthService
router = APIRouter(tags=["公共"])
router = APIRouter(tags=["公共"], route_class=LogRoute)
LoginResult = BaseSchema.Response[BaseSchema.LoginResult]

View File

@ -1,10 +1,11 @@
from fastapi import APIRouter
from core.middleware import LogRoute
from schemas import common as BaseSchema
from schemas import menu as MenuSchema
from service.menu import service as MenuService
router = APIRouter(prefix="/menu", tags=["菜单管理"])
router = APIRouter(prefix="/menu", tags=["菜单管理"], route_class=LogRoute)
Response = BaseSchema.Response

View File

@ -1,12 +1,13 @@
from fastapi import APIRouter, Depends
from typing import List
from core.middleware import LogRoute
from schemas import common as BaseSchema
from schemas import role as RoleSchema
from schemas.common import QueryData
from service.role import service as RoleService
router = APIRouter(prefix="/role", tags=["角色管理"])
router = APIRouter(prefix="/role", tags=["角色管理"], route_class=LogRoute)
Response = BaseSchema.Response
ListAll = BaseSchema.ListAll

View File

@ -1,13 +1,14 @@
from fastapi import APIRouter, Depends
from typing import List
from core.middleware import LogRoute
from core.security import check_permissions
from schemas import common as BaseSchema
from schemas import user as UserSchema
from schemas.common import QueryData
from service.user import service as UserService
router = APIRouter(prefix="/user", tags=["用户管理"])
router = APIRouter(prefix="/user", tags=["用户管理"], route_class=LogRoute)
Response = BaseSchema.Response
ListAll = BaseSchema.ListAll