276342520f
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 8s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 3m28s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
1. 修复密码重置接口路径不一致 Bug (auth.py) - forgot_password 硬编码 localhost → 使用 APP_BASE_URL 配置 2. 删除 8 处死代码(未使用 import/变量) - 清理多个文件中的未使用导入和变量 3. 删除 8 个空文件/空模块 - 删除无内容的 __init__.py 文件 4. 合并 3 对 100% 完全重复的函数 - 提取 check_project_access/get_user_plan/require_project_and_library - 新建 apps/api/app/api/routes/_helpers.py 作为共享模块 - 6 个路由文件改为从 _helpers 导入 5. 对齐 6 个废弃/异常环境变量 - 修复 DATABASE_POOL_RECYLE 拼写错误 → DATABASE_POOL_RECYCLE - 添加 JWT_ALGORITHM/JWT_ACCESS_TOKEN_EXPIRE_MINUTES/JWT_REFRESH_TOKEN_EXPIRE_DAYS 到 Settings - 修复 jwt_service.py hasattr 字段名匹配 - .env.example: CORS_ORIGINS → CORS_ORIGINS_RAW(逗号分隔格式) - .env.example: 启用 APP_ENV - 修复 OSS_ENDPOINT 默认值拼写错误 (aliiyuncs.com → aliyuncs.com) - 添加 COSYVOICE_* 变量来源注释 修改文件: 52 个(新增 1,删除 8,修改 43)
105 lines
3.1 KiB
Python
105 lines
3.1 KiB
Python
"""
|
||
性能监控中间件
|
||
"""
|
||
|
||
import logging
|
||
import time
|
||
from typing import Callable
|
||
|
||
from fastapi import Request
|
||
from starlette.middleware.base import BaseHTTPMiddleware
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class PerformanceMonitoringMiddleware(BaseHTTPMiddleware):
|
||
"""性能监控中间件"""
|
||
|
||
def __init__(self, app, slow_request_threshold: float = 1.0):
|
||
super().__init__(app)
|
||
self.slow_request_threshold = slow_request_threshold # 慢请求阈值(秒)
|
||
|
||
async def dispatch(self, request: Request, call_next: Callable):
|
||
# 记录请求开始时间
|
||
start_time = time.time()
|
||
|
||
# 生成请求 ID
|
||
request_id = self._generate_request_id()
|
||
request.state.request_id = request_id
|
||
|
||
# 处理请求
|
||
try:
|
||
response = await call_next(request)
|
||
|
||
# 计算处理时间
|
||
process_time = time.time() - start_time
|
||
|
||
# 添加响应头
|
||
response.headers["X-Request-ID"] = request_id
|
||
response.headers["X-Process-Time"] = f"{process_time:.3f}"
|
||
|
||
# 记录慢请求
|
||
if process_time > self.slow_request_threshold:
|
||
logger.warning(
|
||
f"Slow request detected: {request.method} {request.url.path} "
|
||
f"took {process_time:.3f}s (threshold: {self.slow_request_threshold}s) "
|
||
f"[request_id={request_id}]"
|
||
)
|
||
|
||
# 记录请求日志
|
||
logger.info(
|
||
f"{request.method} {request.url.path} "
|
||
f"status={response.status_code} time={process_time:.3f}s "
|
||
f"[request_id={request_id}]"
|
||
)
|
||
|
||
return response
|
||
|
||
except Exception as e:
|
||
process_time = time.time() - start_time
|
||
logger.error(
|
||
f"Request failed: {request.method} {request.url.path} "
|
||
f"error={str(e)} time={process_time:.3f}s "
|
||
f"[request_id={request_id}]",
|
||
exc_info=True,
|
||
)
|
||
raise
|
||
|
||
def _generate_request_id(self) -> str:
|
||
"""生成请求 ID"""
|
||
import uuid
|
||
|
||
return str(uuid.uuid4())
|
||
|
||
|
||
class DatabaseQueryLogger:
|
||
"""数据库查询日志记录器"""
|
||
|
||
def __init__(self):
|
||
self.queries = []
|
||
self.total_time = 0
|
||
|
||
def log_query(self, query: str, params: tuple, duration: float):
|
||
"""记录查询"""
|
||
self.queries.append(
|
||
{
|
||
"query": query,
|
||
"params": params,
|
||
"duration": duration,
|
||
}
|
||
)
|
||
self.total_time += duration
|
||
|
||
# 记录慢查询(超过 100ms)
|
||
if duration > 0.1:
|
||
logger.warning(f"Slow query detected: {query[:100]}... " f"took {duration:.3f}s with params {params}")
|
||
|
||
def get_stats(self):
|
||
"""获取统计信息"""
|
||
return {
|
||
"total_queries": len(self.queries),
|
||
"total_time": self.total_time,
|
||
"avg_time": self.total_time / len(self.queries) if self.queries else 0,
|
||
"slow_queries": len([q for q in self.queries if q["duration"] > 0.1]),
|
||
}
|