You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.8 KiB
147 lines
4.8 KiB
import time
|
|
import uuid
|
|
import psutil
|
|
import os
|
|
from datetime import datetime
|
|
from fastapi import APIRouter, Depends, Request
|
|
from sqlalchemy import select, func
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from database import get_db
|
|
from models import User, ChatSession, ChatMessage, Task, FlowDefinition, FlowExecution, SystemMetric
|
|
from schemas import SystemHealthOut, UsageStatsOut
|
|
from dependencies import get_current_user
|
|
from middleware.cache_manager import cache_manager
|
|
from middleware.rate_limiter import rate_limiter
|
|
|
|
router = APIRouter(prefix="/api/system", tags=["system"])
|
|
|
|
_start_time = time.time()
|
|
|
|
|
|
@router.get("/health", response_model=SystemHealthOut)
|
|
async def health_check(request: Request, db: AsyncSession = Depends(get_db)):
|
|
db_ok = False
|
|
try:
|
|
await db.execute(select(func.count()).select_from(User))
|
|
db_ok = True
|
|
except Exception:
|
|
pass
|
|
|
|
mem = psutil.Process(os.getpid()).memory_info()
|
|
cpu = psutil.cpu_percent(interval=0.1)
|
|
uptime = time.time() - _start_time
|
|
|
|
try:
|
|
user_count = await db.execute(select(func.count(User.id)))
|
|
active_users = user_count.scalar() or 0
|
|
except Exception:
|
|
active_users = 0
|
|
|
|
return SystemHealthOut(
|
|
status="healthy" if db_ok and cache_manager.available else "degraded",
|
|
service="enterprise-ai-platform",
|
|
uptime_seconds=round(uptime, 1),
|
|
db_connected=db_ok,
|
|
redis_connected=cache_manager.available,
|
|
active_users=active_users,
|
|
memory_mb=round(mem.rss / 1024 / 1024, 1),
|
|
cpu_percent=round(cpu, 1),
|
|
)
|
|
|
|
|
|
@router.get("/stats", response_model=UsageStatsOut)
|
|
async def usage_stats(request: Request, db: AsyncSession = Depends(get_db)):
|
|
today = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
|
|
total_users = (await db.execute(select(func.count(User.id)))).scalar() or 0
|
|
active_today = (await db.execute(
|
|
select(func.count(func.distinct(User.id)))
|
|
.join(ChatSession, ChatSession.user_id == User.id)
|
|
.where(ChatSession.created_at >= today)
|
|
)).scalar() or 0
|
|
total_sessions = (await db.execute(select(func.count(ChatSession.id)))).scalar() or 0
|
|
total_messages = (await db.execute(select(func.count(ChatMessage.id)))).scalar() or 0
|
|
total_tasks = (await db.execute(select(func.count(Task.id)))).scalar() or 0
|
|
total_flows = (await db.execute(select(func.count(FlowDefinition.id)))).scalar() or 0
|
|
published = (await db.execute(
|
|
select(func.count(FlowDefinition.id)).where(FlowDefinition.status == "published")
|
|
)).scalar() or 0
|
|
api_calls = (await db.execute(
|
|
select(func.count(FlowExecution.id)).where(FlowExecution.started_at >= today)
|
|
)).scalar() or 0
|
|
|
|
return UsageStatsOut(
|
|
total_users=total_users,
|
|
active_users_today=active_today,
|
|
total_sessions=total_sessions,
|
|
total_messages=total_messages,
|
|
total_tasks=total_tasks,
|
|
total_flows=total_flows,
|
|
published_flows=published,
|
|
api_calls_today=api_calls,
|
|
avg_response_time_ms=0.0,
|
|
)
|
|
|
|
|
|
@router.post("/metrics")
|
|
async def collect_metrics(payload: dict, request: Request, db: AsyncSession = Depends(get_db)):
|
|
metric = SystemMetric(
|
|
metric_type=payload.get("metric_type", "custom"),
|
|
value={"data": payload.get("value", {}), "source": payload.get("source", "api")},
|
|
)
|
|
db.add(metric)
|
|
await db.flush()
|
|
return {"code": 200, "metric_id": str(metric.id)}
|
|
|
|
|
|
@router.get("/metrics")
|
|
async def list_metrics(
|
|
request: Request,
|
|
metric_type: str | None = None,
|
|
limit: int = 50,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
q = select(SystemMetric).order_by(SystemMetric.collected_at.desc())
|
|
if metric_type:
|
|
q = q.where(SystemMetric.metric_type == metric_type)
|
|
q = q.limit(limit)
|
|
result = await db.execute(q)
|
|
metrics = result.scalars().all()
|
|
return {
|
|
"code": 200,
|
|
"data": [{
|
|
"id": str(m.id),
|
|
"metric_type": m.metric_type,
|
|
"value": m.value,
|
|
"collected_at": m.collected_at.isoformat() if m.collected_at else None,
|
|
} for m in metrics],
|
|
}
|
|
|
|
|
|
@router.get("/cache/stats")
|
|
async def cache_stats(request: Request):
|
|
return {
|
|
"code": 200,
|
|
"data": {
|
|
"redis_available": cache_manager.available,
|
|
},
|
|
}
|
|
|
|
|
|
@router.get("/ratelimit/stats")
|
|
async def ratelimit_stats(request: Request):
|
|
remaining = await rate_limiter.remaining("global")
|
|
return {
|
|
"code": 200,
|
|
"data": {
|
|
"limit_per_minute": 60,
|
|
"window_seconds": 60,
|
|
"remaining": remaining,
|
|
},
|
|
}
|
|
|
|
|
|
@router.post("/cache/clear")
|
|
async def clear_cache(request: Request, pattern: str = "*"):
|
|
await cache_manager.delete_pattern(pattern)
|
|
return {"code": 200, "message": "缓存已清除"}
|