The fleet endpoint returned a bare 500, so the error banner only showed "status code 500" with no cause. Wrap the call to log the full traceback server-side and return the exception type, message and originating file:line in the HTTP detail, so the dashboard banner pinpoints the failure for an authenticated user. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
40 lines
1.4 KiB
Python
40 lines
1.4 KiB
Python
"""Dashboard aggregation endpoint (fleet-wide cockpit data)."""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import traceback
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlmodel import Session
|
|
|
|
from auth import get_current_user
|
|
from database import get_session
|
|
from models.user import User
|
|
from services import dashboard_service
|
|
|
|
logger = logging.getLogger("stackpilot.dashboard")
|
|
|
|
router = APIRouter(prefix="/api/dashboard", tags=["dashboard"])
|
|
|
|
|
|
@router.get("/fleet")
|
|
async def fleet(
|
|
refresh: bool = False,
|
|
session: Session = Depends(get_session),
|
|
_user: User = Depends(get_current_user),
|
|
) -> dict:
|
|
"""Fleet-wide 'needs attention' list, KPIs and per-host rollup across the
|
|
local host and every agent — the data behind the operator cockpit."""
|
|
try:
|
|
return await dashboard_service.compute_fleet(session, refresh=refresh)
|
|
except Exception as exc: # noqa: BLE001 — surface the real cause for diagnosis
|
|
logger.exception("compute_fleet failed")
|
|
# Deepest frame pinpoints where it broke; safe to expose to the
|
|
# authenticated user and it makes the dashboard error banner actionable.
|
|
tb = traceback.extract_tb(exc.__traceback__)
|
|
where = f" at {tb[-1].filename.split('/')[-1]}:{tb[-1].lineno}" if tb else ""
|
|
raise HTTPException(
|
|
status_code=500,
|
|
detail=f"{type(exc).__name__}: {exc}{where}",
|
|
) from exc
|