feat(metrics): sparklines 串接真實數據 + TOOL_LINKS 移至 API (2026-04-04 ogt)
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 7m6s

前端 page.tsx:
- 今日事件 sparkline: 過去 6 小時每小時事件數 (從 incidents 計算)
- MTTR sparkline: 各已解決 incident 修復時間序列 (從 incidents 計算)
- 無數據時不顯示 sparkline (undefined 渲染 nothing)
- 移除硬碼 TOOL_LINKS,改讀 API 回傳的 tool.url

後端 monitoring.py:
- 每個 probe 函數回傳 dict 加入 "url" 欄位
- 前端工具連結由後端集中管理,解決多環境問題

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-04 11:09:04 +08:00
parent 5e836bde24
commit 200c382ca4
2 changed files with 45 additions and 31 deletions

View File

@@ -53,12 +53,13 @@ async def _probe_grafana(client: httpx.AsyncClient) -> dict:
"version": version,
"stats": f"面板 {dash_count}" if dash_count is not None else "監控面板",
"description": "指標視覺化 · Dashboard",
"url": base,
}
except Exception as e:
logger.warning("grafana_probe_failed", error=str(e))
return {
"name": "Grafana", "status": "down", "version": None,
"stats": None, "description": "指標視覺化 · Dashboard",
"stats": None, "description": "指標視覺化 · Dashboard", "url": base,
}
@@ -91,12 +92,13 @@ async def _probe_prometheus(client: httpx.AsyncClient) -> dict:
"stats": " · ".join(stats_parts),
"description": "時序資料庫 · 告警規則",
"firing_count": firing_count,
"url": base,
}
except Exception as e:
logger.warning("prometheus_probe_failed", error=str(e))
return {
"name": "Prometheus", "status": "down", "version": None,
"stats": None, "description": "時序資料庫 · 告警規則", "firing_count": 0,
"stats": None, "description": "時序資料庫 · 告警規則", "firing_count": 0, "url": base,
}
@@ -119,12 +121,13 @@ async def _probe_sentry(client: httpx.AsyncClient) -> dict:
"version": version,
"stats": "Error Tracking · Issue",
"description": "錯誤追蹤 · Issue 管理",
"url": base,
}
except Exception as e:
logger.warning("sentry_probe_failed", error=str(e))
return {
"name": "Sentry", "status": "down", "version": None,
"stats": None, "description": "錯誤追蹤 · Issue 管理",
"stats": None, "description": "錯誤追蹤 · Issue 管理", "url": base,
}
@@ -141,12 +144,13 @@ async def _probe_langfuse(client: httpx.AsyncClient) -> dict:
"version": version,
"stats": "LLM Tracing · AI 觀測",
"description": "LLM 追蹤 · AI 成本監控",
"url": base,
}
except Exception as e:
logger.warning("langfuse_probe_failed", error=str(e))
return {
"name": "Langfuse", "status": "down", "version": None,
"stats": None, "description": "LLM 追蹤 · AI 成本監控",
"stats": None, "description": "LLM 追蹤 · AI 成本監控", "url": base,
}
@@ -161,6 +165,7 @@ async def _probe_signoz(client: httpx.AsyncClient) -> dict:
"version": None,
"stats": "APM · Trace · Log",
"description": "可觀測性平台 · OTEL",
"url": base,
}
except Exception as e:
logger.warning("signoz_probe_failed", error=str(e))
@@ -169,13 +174,13 @@ async def _probe_signoz(client: httpx.AsyncClient) -> dict:
if r2.status_code in (200, 301, 302):
return {
"name": "SigNoz", "status": "up", "version": None,
"stats": "APM · Trace · Log", "description": "可觀測性平台 · OTEL",
"stats": "APM · Trace · Log", "description": "可觀測性平台 · OTEL", "url": base,
}
except Exception:
pass
return {
"name": "SigNoz", "status": "down", "version": None,
"stats": None, "description": "可觀測性平台 · OTEL",
"stats": None, "description": "可觀測性平台 · OTEL", "url": base,
}
@@ -192,12 +197,13 @@ async def _probe_gitea(client: httpx.AsyncClient) -> dict:
"version": version,
"stats": "CI/CD · Git · Mirror",
"description": "代碼倉庫 · Pipeline",
"url": base,
}
except Exception as e:
logger.warning("gitea_probe_failed", error=str(e))
return {
"name": "Gitea", "status": "down", "version": None,
"stats": None, "description": "代碼倉庫 · Pipeline",
"stats": None, "description": "代碼倉庫 · Pipeline", "url": base,
}