feat(observability): add Prometheus/Grafana/Loki/Alertmanager/Alloy stack and remove legacy Monitoring UI

This commit is contained in:
Developer
2026-06-16 11:08:32 +00:00
parent 615e02e970
commit e2ad731b5f
80 changed files with 5020 additions and 3665 deletions
@@ -11,12 +11,10 @@ from fastapi import APIRouter, Depends
from media_library_viewer_api.clients.jellyfin import JellyfinClient
from media_library_viewer_api.dependencies import (
get_jellyfin_client,
get_monitoring_poller,
get_settings_store,
get_user_id,
)
from media_library_viewer_api.models.backups import BackupDashboardSummary
from media_library_viewer_api.services.monitoring_actions import collect_machine_overview
from media_library_viewer_api.services.settings_store import SettingsStore
logger = logging.getLogger(__name__)
@@ -46,52 +44,6 @@ def get_library_counts(
return client.library_item_counts(user_id, libraries)
@router.get("/monitoring")
def get_monitoring_overview(
store=Depends(get_settings_store),
) -> dict[str, Any]:
"""Return one lightweight monitoring row per configured machine."""
machines = [m for m in store.list_machines() if m.get("enabled")]
rows: list[dict[str, Any]] = []
for machine in machines:
try:
rows.append(collect_machine_overview(machine, store))
except Exception as exc:
logger.exception(
"Dashboard monitoring overview failed for machine_id=%s",
machine.get("id"),
)
rows.append({
"machine": {k: machine.get(k) for k in (
"id", "name", "mode", "enabled", "host", "port", "username",
"media_root", "path_prefix", "notes",
)},
"status": "",
"status_error": str(exc),
"metrics_error": str(exc),
"disk_error": str(exc),
"sample_count": 0,
"latest_sample": None,
"cpu_summary": None,
"iowait_summary": None,
"mem_summary": None,
"net_rx_summary": None,
"net_tx_summary": None,
"disk_read_summary": None,
"disk_write_summary": None,
"disk": None,
})
poller = get_monitoring_poller().snapshot()
enabled_count = sum(1 for machine in machines if machine.get("enabled"))
logger.info("Dashboard monitoring machines=%s enabled=%s", len(machines), enabled_count)
return {
"poller": poller,
"machines": rows,
"total": len(machines),
"enabled": enabled_count,
}
@router.get("/shortcuts")
def get_shortcuts(
store=Depends(get_settings_store),
@@ -144,8 +96,8 @@ def _map_sessions_to_activity_rows(sessions: list[dict[str, Any]]) -> list[dict[
has_item = bool(item)
series = item.get("SeriesName") or ""
title = (
f"{series} - {item.get('Name', '')}" if series else item.get("Name", "Unknown")
) if has_item else "(idle)"
(f"{series} - {item.get('Name', '')}" if series else item.get("Name", "Unknown")) if has_item else "(idle)"
)
if not has_item:
state_label = "idle"
@@ -162,16 +114,18 @@ def _map_sessions_to_activity_rows(sessions: list[dict[str, Any]]) -> list[dict[
if not transcode_type:
transcode_type.append("active")
results.append({
"user": session.get("UserName") or "Unknown",
"title": title,
"type": item.get("Type", "") if has_item else "",
"state": state_label,
"transcoding": "yes" if is_transcoding else "no",
"transcoding_type": ", ".join(transcode_type),
"device": session.get("DeviceName") or session.get("Client") or "",
"session_id": session.get("Id") or "",
})
results.append(
{
"user": session.get("UserName") or "Unknown",
"title": title,
"type": item.get("Type", "") if has_item else "",
"state": state_label,
"transcoding": "yes" if is_transcoding else "no",
"transcoding_type": ", ".join(transcode_type),
"device": session.get("DeviceName") or session.get("Client") or "",
"session_id": session.get("Id") or "",
}
)
return results