geo/backend/app/monitoring/middleware.py

87 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""监控中间件"""
import time
from typing import Callable
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from app.monitoring.metrics import (
API_REQUESTS_TOTAL,
API_REQUEST_DURATION_SECONDS,
API_REQUESTS_IN_PROGRESS,
)
# 需要排除的路径(不记录指标)
EXCLUDED_PATHS = {"/health", "/ready", "/metrics", "/docs", "/openapi.json"}
class MonitoringMiddleware(BaseHTTPMiddleware):
"""API监控中间件"""
async def dispatch(self, request: Request, call_next: Callable) -> Response:
# 跳过排除路径
if request.url.path in EXCLUDED_PATHS:
return await call_next(request)
# 提取端点标识(用于指标标签)
endpoint = self._get_endpoint_label(request)
# 增加活跃请求计数
API_REQUESTS_IN_PROGRESS.labels(
method=request.method,
endpoint=endpoint
).inc()
# 记录开始时间
start_time = time.perf_counter()
try:
# 执行请求
response = await call_next(request)
status_code = response.status_code
except Exception as e:
status_code = 500
raise
finally:
# 计算耗时
duration = time.perf_counter() - start_time
# 记录指标
API_REQUESTS_TOTAL.labels(
method=request.method,
endpoint=endpoint,
status=str(status_code)
).inc()
API_REQUEST_DURATION_SECONDS.labels(
method=request.method,
endpoint=endpoint
).observe(duration)
# 减少活跃请求计数
API_REQUESTS_IN_PROGRESS.labels(
method=request.method,
endpoint=endpoint
).dec()
return response
def _get_endpoint_label(self, request: Request) -> str:
"""提取端点标签"""
path = request.url.path
# 规范化路径替换ID等参数
parts = path.strip("/").split("/")
# 处理常见模式:/api/v1/resources/{id}
if len(parts) >= 4 and parts[0] == "api":
resource = parts[2] if len(parts) > 2 else "unknown"
action = parts[3] if len(parts) > 3 else "list"
# 映射到规范标签
if action.isdigit():
return f"{resource}_detail"
return f"{resource}_{action}"
return "other"