forked from xiaohei/taiji-AI-PAD
140 lines
5.2 KiB
Python
140 lines
5.2 KiB
Python
"""Monitoring endpoints that expose aggregated stats."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import structlog
|
||
from fastapi import APIRouter, HTTPException, Depends
|
||
from typing import Optional
|
||
|
||
from monitoring import system_monitor
|
||
from app.auth import require_auth
|
||
|
||
logger = structlog.get_logger(__name__)
|
||
|
||
router = APIRouter(prefix="/api/v1/monitoring", tags=["monitoring"])
|
||
|
||
|
||
@router.get("/metrics")
|
||
async def get_system_metrics() -> dict:
|
||
"""Return live system metrics (CPU, memory, etc.)."""
|
||
try:
|
||
return await system_monitor.get_system_metrics()
|
||
except Exception as exc:
|
||
logger.error("获取系统指标失败", error=str(exc))
|
||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||
|
||
|
||
@router.get("/stats")
|
||
async def get_service_stats(service: str = "all") -> dict:
|
||
"""Return aggregate statistics for a specific subsystem."""
|
||
try:
|
||
return await system_monitor.get_service_stats(service)
|
||
except Exception as exc:
|
||
logger.error("获取服务统计失败", error=str(exc))
|
||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||
|
||
|
||
@router.get("/trends")
|
||
async def get_performance_trends(
|
||
metric: str = "executions", period: str = "24h", interval: str = "1h"
|
||
) -> dict:
|
||
"""Return trend data for executions or EU consumption."""
|
||
try:
|
||
return await system_monitor.get_performance_trends(metric, period, interval)
|
||
except Exception as exc:
|
||
logger.error("获取性能趋势失败", error=str(exc))
|
||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||
|
||
|
||
@router.get("/alerts")
|
||
async def get_system_alerts(severity: str | None = None) -> dict:
|
||
"""Return alert summaries with optional severity filtering."""
|
||
try:
|
||
alerts = await system_monitor.get_alerts(severity)
|
||
return {
|
||
"timestamp": await _current_timestamp(),
|
||
"alerts": alerts,
|
||
"count": len(alerts),
|
||
}
|
||
except Exception as exc:
|
||
logger.error("获取系统告警失败", error=str(exc))
|
||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||
|
||
|
||
@router.get("/dashboard")
|
||
async def get_monitoring_dashboard(
|
||
principal: Optional[dict] = Depends(require_auth)
|
||
) -> dict:
|
||
"""
|
||
Aggregate health, metrics, stats, and alerts for dashboards.
|
||
|
||
如果用户已登录,返回租户级别的数据;否则返回全局数据。
|
||
|
||
返回数据包括:
|
||
1. 当前租户EU消耗过去24小时的消耗情况
|
||
2. 使用的模型和模型的使用情况、当前调用次数
|
||
3. 每周API调用的次数,7天的每一天调用多少次,包括成功和失败
|
||
4. 三个微服务的状态(mcp_server, data_ingestion, api_gateway)
|
||
"""
|
||
try:
|
||
# 获取租户ID(如果已登录)
|
||
tenant_id = principal.get("user_id") if principal else None
|
||
|
||
# 获取基础健康状态和告警
|
||
health_task = system_monitor.get_system_health()
|
||
alerts_task = system_monitor.get_alerts()
|
||
|
||
health, alerts = await asyncio.gather(health_task, alerts_task)
|
||
|
||
# 如果有租户ID,获取租户级别的数据
|
||
if tenant_id:
|
||
tenant_data = await system_monitor.get_tenant_dashboard(tenant_id)
|
||
|
||
return {
|
||
"timestamp": await _current_timestamp(),
|
||
"health": health,
|
||
# 租户级别的EU消耗(24小时)
|
||
"euConsumption24h": tenant_data.get("euConsumption24h", {}),
|
||
# 模型使用情况
|
||
"modelUsage": tenant_data.get("modelUsage", {}),
|
||
# 每周API调用统计(7天每天成功/失败)
|
||
"weeklyApiCalls": tenant_data.get("weeklyApiCalls", {}),
|
||
# 告警信息
|
||
"alerts": {
|
||
"items": alerts,
|
||
"count": len(alerts),
|
||
"critical_count": len([a for a in alerts if a.get("severity") == "critical"]),
|
||
"warning_count": len([a for a in alerts if a.get("severity") == "warning"]),
|
||
},
|
||
}
|
||
else:
|
||
# 未登录用户返回全局数据
|
||
metrics_task = system_monitor.get_system_metrics()
|
||
stats_task = system_monitor.get_service_stats("all")
|
||
|
||
metrics, stats = await asyncio.gather(metrics_task, stats_task)
|
||
|
||
return {
|
||
"timestamp": await _current_timestamp(),
|
||
"health": health,
|
||
"metrics": metrics,
|
||
"stats": stats.get("stats", {}),
|
||
"alerts": {
|
||
"items": alerts,
|
||
"count": len(alerts),
|
||
"critical_count": len([a for a in alerts if a.get("severity") == "critical"]),
|
||
"warning_count": len([a for a in alerts if a.get("severity") == "warning"]),
|
||
},
|
||
}
|
||
except Exception as exc:
|
||
logger.error("获取监控仪表板失败", error=str(exc))
|
||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||
|
||
|
||
async def _current_timestamp() -> str:
|
||
"""Helper returning the current UTC timestamp string."""
|
||
from datetime import datetime
|
||
|
||
return datetime.utcnow().isoformat()
|