Skip to content

SkyLab 系統監控 ​

SkyLab 的監控分成兩層:

層看什麼在哪裡需要額外容器?
內建平台健康(DB、Redis、worker、PVE API 連線、Gateway、AI Gateway 與各模型、排程任務心跳)、系統告警+Email管理員「資源監控」頁的「系統健康」卡、活動警告否
監控 stack(選用)API 流量/延遲/錯誤率、排程與佇列指標、容器與主機資源、PostgreSQL/Redis、集中日誌、Proxmox 節點/VM 用量、Gateway 主機與 nginx、AI 請求與 LiteLLM/vLLM 推論引擎Grafana、Prometheusdocker compose --profile monitoring

Proxmox 節點/VM 的資源用量不經過 SkyLab 後端:由 PVE 內建的 Metric Server 直接推到監控 stack 的 InfluxDB。後端只檢查「自己連不連得到 PVE API」。


1. 內建(不必另外裝東西) ​

健康檢查端點 ​

端點用途權限
GET /api/v1/utils/health-check/Liveness:程序活著就回 true(compose healthcheck 用)免登入
GET /api/v1/utils/health-check/readyReadiness:DB 與 Redis 都通才 200,否則 503。回傳 {"status":"ok","checks":{"database":true,"redis":true}},不帶錯誤細節免登入
GET /api/v1/monitoring/system-health完整報告:各元件狀態與延遲、背景迴圈與每個排程任務的心跳管理員
GET /metricsPrometheus 格式指標(只在內網 backend:8000,nginx 不轉發)內網;可設 METRICS_TOKEN
GET /metrics/gateway-targets?exporter=node|nginxPrometheus http_sd:回傳 Gateway exporter 的位址(取自「閘道 VM」頁的連線設定,未設定回 [])同 /metrics

排程任務心跳 ​

主排程(scheduler,60 秒一輪,任務清單以 services/scheduling/coordinator.py 註冊的 tasks=[…] 為準)、Web Push 推播(web_push)、WireGuard 同步(wireguard)每次執行都會記錄:上次執行、上次成功、耗時、連續失敗次數、最近一次錯誤。資料寫在 Redis(skylab:hb:*,7 天過期),Redis 不可用時退回行程記憶體。

狀態判定(services/monitoring/health_policy.py):

  • 連續失敗:連續失敗 ≥ 3 次
  • 偶發失敗:失敗 1–2 次(卡片標紅,但不拉低整體狀態)
  • 停擺:超過 max(5 × 間隔, 10 分鐘) 沒有執行
  • 尚未執行:這次啟動後還沒輪到

注意:部分任務在自己內部就把例外吞掉並回傳 0(例如 process_pending_deletions),這類任務失敗時心跳仍會顯示成功,要看後端日誌。

系統告警 ​

排程任務 process_system_health_alerts 依告警檢查間隔(「資源政策」頁「資源警告」區的「檢查間隔(秒)」,最少 60 秒)評估一次,而且只在同一區的「啟用警告」打開時執行。發現下列問題時寫入 scope=system 的告警,出現在「資源監控 → 活動警告」;同一區的「Email 通知」打開時也會寄信給所有管理員:

  • 排程任務連續失敗 ≥ 3 次,或停擺
  • 背景迴圈停擺(沒有任何行程拿到 leader)
  • worker 沒有心跳、Redis 連不上、某個 PVE 連線連不上
  • Gateway:SSH 連不上、nginx 或 WireGuard 沒在跑、nginx -t 失敗(狀態「無法連線」);HTTPS 憑證剩不到 14 天或已過期(狀態「需要處理」;憑證由管理員自備、自己續期,見Gateway 的 HTTPS 憑證)
  • AI:LiteLLM 連不上或它的資料庫斷線(component:ai_gateway,使用者 API 與內建 AI 功能都會失敗);某個模型的上游推論服務(例如 DGX 上的 vLLM)健康檢查失敗(component:ai_model:<alias>,全部部署異常為「無法連線」、部分異常為「需要處理」)

Gateway 的檢查是後端用 SSH 在 Gateway 上跑一條指令(systemctl is-active、nginx -t、讀 http.conf 引用的憑證到期日,自簽備援憑證不算),結果快取 60 秒;Gateway 沒設定時卡片顯示「停用」。

AI 的檢查是後端用受限的 runtime key(LITELLM_RUNTIME_API_KEY,不需要 master key)問 LiteLLM:/health/liveliness、/health/readiness(DB 是否連線)、/model/info(公開模型名稱)與 /health(LiteLLM 每 60 秒背景健康檢查的結果,讀快取、不會為了探測去打推論服務),結果快取 60 秒。沒設 runtime key 時卡片顯示「停用」;LiteLLM 剛啟動、背景檢查還沒跑完的模型顯示「尚未執行」,不影響整體狀態也不發告警。

同一個問題要連續兩輪都出現才開告警(吸收部署時 worker 晚起、PVE 瞬斷);問題消失就自動解除;冷卻期和資源告警共用同一個「冷卻期(分鐘)」設定。

資料庫掛掉、或整個 backend 掛掉時,告警本身寫不進去也寄不出去;這兩種情況在「系統健康」卡與 Grafana 的「SkyLab 平台」儀表板看得到,但不會主動通知。需要時可以在另一台機器用任何外部探測服務監看 /api/v1/utils/health-check/ready(非 200 即異常)。

Request ID ​

nginx 為每個請求產生 $request_id,以 X-Request-ID 轉給 backend 並寫進 nginx access log(rid=...);backend 寫進 JSON 日誌的 request_id 欄位、Sentry 的 tag,並回傳在回應標頭 X-Request-ID。使用者回報錯誤時,從瀏覽器 DevTools 看到的這個 id 可以直接在 Grafana「SkyLab 日誌」儀表板的 Request ID 欄位查到整條路徑。

Sentry ​

  • 後端與 worker:.env 設 SENTRY_DSN(可另設 SENTRY_RELEASE、SENTRY_TRACES_SAMPLE_RATE)。
  • 前端(瀏覽器):.env 設 VITE_SENTRY_DSN 後重新建置 frontend 映像(docker compose build frontend)。SDK 是獨立的 chunk,只有建置時設了 DSN 才會載入。建議在 Sentry 另開一個 Browser 專案,和後端分開看。
  • 兩邊都不送個資(send_default_pii=False)。測試(pytest)一律停用 Sentry,不會把測試產生的例外送到正式專案。

容器日誌輪替 ​

docker-compose.yml 所有服務都套用 x-logging:json-file、單檔 10 MB、保留 5 個(DOCKER_LOG_MAX_SIZE/DOCKER_LOG_MAX_FILE 可調)。應用程式另外在 logs/ 寫自己的檔案:app.log(每日輪替、保留 30 天)與 error.log(只記 ERROR 以上、每週輪替、保留約三個月)。

容器 healthcheck ​

  • db、pgbouncer:pg_isready;redis:redis-cli ping
  • backend:/api/v1/utils/health-check/
  • worker:檢查 arq 每 60 秒寫進 Redis 的 skylab:tasks:health-check(TTL 61 秒)
  • nginx:/nginx-health
  • frontend:首頁 200
  • litellm:/health/liveliness;監控 stack 裡的 prometheus、grafana、loki、influxdb 各自檢查自己的健康端點

docker compose ps 會顯示 (healthy)/(unhealthy)。注意 Docker Compose 本身不會自動重啟 unhealthy 的容器(程序直接結束時才會依 restart 政策重啟)。


2. 監控 stack ​

啟動 ​

bash
# 先在 .env 設好(至少):
#   INFLUXDB_ADMIN_PASSWORD、INFLUXDB_ADMIN_TOKEN
#(GRAFANA_ADMIN_PASSWORD 可以留空:Grafana 自己的帳密登入已關閉,見「登入 Grafana」)
docker compose --profile monitoring up -d   # 還沒設定 AI stack 時加上 --scale litellm=0

之後每次 docker compose up -d 都要帶 --profile monitoring(或在 .env 設 COMPOSE_PROFILES=monitoring),否則監控容器不會一起起來。

用 CI 部署(Deploy to PVE Test workflow)時:workflow 用的是部署機的 /opt/skylab/.env,所以要在那份檔案加上 COMPOSE_PROFILES=monitoring(連同上面的密碼/token),再重新跑一次部署。

rootless Docker ​

先用 docker info --format '{{.SecurityOptions}}' 確認:輸出有 name=rootless 就是 rootless(self-hosted runner 的部署機是)。rootless 的 Docker socket 與資料目錄都在使用者自己的路徑下,要在 .env 補三行,否則 Alloy 收不到任何容器日誌、cAdvisor 抓不到容器:

bash
# <uid> 用 `id -u` 查;Docker Root Dir 用 `docker info --format '{{.DockerRootDir}}'` 查
DOCKER_SOCKET=/run/user/<uid>/docker.sock
CONTAINERD_SOCKET=/run/user/<uid>/docker/containerd/containerd.sock
DOCKER_DATA_ROOT=/home/<user>/.local/share/docker

cAdvisor 要看到逐一容器的 CPU/記憶體,還需要 cgroup v2 的委派:docker info --format '{{.CgroupDriver}} {{.CgroupVersion}}' 應為 systemd 2。若是 none/cgroupfs,其他監控照常運作,只有「SkyLab 基礎設施」的容器面板會是空的;啟用方式見 Docker 官方 rootless 文件的 “Limiting resources”(/etc/systemd/system/user@.service.d/delegate.conf 設 Delegate=cpu cpuset io memory pids 後重新登入)。

node-exporter 在 rootless 下照樣讀得到主機的 CPU、記憶體與磁碟(rootlesskit 預設不建立 pid namespace);網卡流量看到的是容器自己的網路。部署機若是 PVE 上的 VM,主機網卡流量可以看 Proxmox 儀表板裡該 VM 的網路(PVE Metric Server 回報)。

服務用途入口
Grafana儀表板http://<SkyLab>/grafana/(經 nginx);主機上的 http://127.0.0.1:3000/grafana/ 只在下方的內建 admin 緊急登入時有用
Prometheus指標收集(不設告警規則)http://127.0.0.1:9090(只綁本機,SSH tunnel 使用)
Loki + Alloy所有容器日誌,保留 14 天在 Grafana 查
InfluxDB 2Proxmox Metric Server 推送目的地:8086(見下方設定)
postgres-exporter/redis-exporter/cAdvisor/node-exporter資料庫、快取、容器、主機指標Prometheus 內部抓取

SkyLab「資源監控」頁右上角的「在 Grafana 查看詳細」按鈕只在監控 stack 有啟用時出現:後端(POST /api/v1/monitoring/grafana/session)探測 GRAFANA_INTERNAL_URL(預設 http://grafana:3000/grafana)的 /api/health,連得到才顯示,結果快取一分鐘;按鈕連到 .env 的 GRAFANA_ROOT_URL,沒設時連同網域的 /grafana/。

監控 stack 只負責收集與呈現,不發告警通知(沒有 Prometheus 告警規則、Alertmanager 或 Grafana alerting)。平台本身的異常由內建的「系統告警」處理(見上方)。

Grafana 儀表板(已自動匯入,資料夾「SkyLab」) ​

  • SkyLab 平台(首頁):backend 狀態、請求量、5xx 比例、p95 延遲、WebSocket 連線、佇列積壓、最慢/錯誤最多的路由、排程任務狀態表、任務失敗與耗時、背景任務紀錄、依賴元件狀態與延遲
  • SkyLab 基礎設施:各容器 CPU/記憶體/網路、PostgreSQL(連線、交易、cache 命中率、deadlock、大小)、Redis、SkyLab 主機 CPU/記憶體/磁碟(只看 job="node",不含 Gateway)
  • SkyLab 日誌:依服務與關鍵字篩選、錯誤日誌、以 Request ID 追蹤
  • Proxmox VE(Metric Server):節點 CPU/記憶體/IO wait/load、CPU 與記憶體最高的 VM/LXC、各儲存使用率;最下方「Gateway VM(PVE 回報)」一列看 Gateway 這台 VM 的 CPU、記憶體、網路與磁碟 IO(上方「Gateway VM」選單選擇,名稱含 gateway 的會自動排第一個)
  • SkyLab Gateway:Gateway 主機上 exporter 的資料——SkyLab 健康探測/exporter/nginx 狀態、nginx 活躍連線、開機時間、CPU/記憶體/磁碟、各網卡流量(wg0 是 WireGuard)、TCP 連線數、nginx 連線狀態與請求速率(見下方「Gateway 監控」)
  • SkyLab AI:AI Gateway/LiteLLM/推論引擎狀態、可用模型數、每分鐘請求與平台錯誤率;Campus 端(使用者 API 金鑰與內建 AI 功能)依模型的請求量、結果類別、端到端與首字延遲、token 吞吐、來源;vLLM 的執行中/排隊請求、KV cache 使用率、prefill/decode 吞吐、TTFT、token 間延遲、端到端延遲、結束原因、搶占次數;LiteLLM 的狀態碼、上游部署成功/失敗、上游與 gateway 自身延遲、部署狀態(見下方「AI 模組監控」)。「AI 用量監控」頁右上角的「在 Grafana 查看詳細」直接開這個儀表板(只有管理員、且監控 stack 啟用時顯示)

對外網址不是 http://localhost 時,設 GRAFANA_ROOT_URL=https://你的網域/grafana/。

登入 Grafana ​

SkyLab 管理員免密碼登入:開過「資源監控」頁之後,點「在 Grafana 查看詳細」(或直接開 /grafana/)就會以自己的 SkyLab 帳號登入,Grafana 裡的角色是 Admin,帳號第一次進來時自動建立(登入名稱=SkyLab email)。

  1. 資源監控頁呼叫 POST /monitoring/grafana/session,後端發 skylab_grafana cookie:httponly、只在 /grafana/ 路徑送出、效期 GRAFANA_SESSION_EXPIRE_MINUTES(預設 480 分鐘),頁面開著時每 30 分鐘續期;HTTPS 下加 Secure。
  2. nginx 對 /grafana/ 的每個請求先 auth_request 到後端 /monitoring/grafana/auth(只給 nginx 內部呼叫,對外入口回 404)。後端驗 cookie 並重新檢查帳號:停用、改密碼/強制登出(token_version)、失去管理員權限、被要求綁定兩步驟驗證但還沒綁,都會在 10 秒內失效。通過時回 X-WEBAUTH-USER/EMAIL/NAME/ROLE(quoted-printable,中文姓名才放得進 HTTP 標頭)。
  3. nginx 一律以後端的回覆覆寫這四個標頭(瀏覽器自己帶的會被丟掉),Grafana auth.proxy 只信任 nginx 在 grafana-authproxy 網路上的固定 IP(GF_AUTH_PROXY_WHITELIST)。Grafana 不另外發 session,每個請求都重新驗證。
  4. 登出 SkyLab 時一併刪掉這個 cookie。

Grafana 自己的帳密登入已關閉:登入表單與 HTTP API 的 basic auth 都關掉了(docker-compose.yml 的 GF_AUTH_DISABLE_LOGIN_FORM=true、GF_AUTH_BASIC_ENABLED=false),對外的 /grafana/ 只能經上面的 SkyLab 管理員免密碼登入進入。沒有有效 cookie(例如沒先開資源監控頁、cookie 過期)或後端掛掉時,/grafana/ 只會顯示沒有帳號/密碼欄位的 Grafana 登入頁,請先在 SkyLab 開「資源監控」頁。

SkyLab 管理員在 Grafana 主組織裡的角色是 Admin,儀表板、資料來源、使用者與 service account 都能管理。Grafana 內建的 admin 帳號(server admin)仍然存在,只是無法登入;它的密碼是 GRAFANA_ADMIN_PASSWORD,留空(或仍是範本的 changethis/admin)時容器改用隨機密碼,不再落回 Grafana 預設的 admin。Grafana 只在第一次啟動時寫入這個密碼,所以既有安裝的舊密碼仍留在 Grafana 資料庫裡(只是不能再拿來登入),之後改 .env 也不會生效。

需要用內建 admin 時(SkyLab 登入壞掉,或要改 Grafana 全站設定),在 SkyLab 主機上:

  1. 在容器裡設新密碼:docker compose exec grafana grafana cli admin reset-admin-password '新密碼'。
  2. 在 docker-compose.yml 旁邊放一個 docker-compose.override.yml 暫時打開登入表單,再執行 docker compose --profile monitoring up -d grafana:
    yaml
    services:
      grafana:
        environment:
          GF_AUTH_DISABLE_LOGIN_FORM: "false"
    這段期間對外的 /grafana/ 也看得到登入表單,建議經 SSH tunnel 連 http://127.0.0.1:3000/grafana/ 登入,並盡快結束。
  3. 用完刪掉 override 檔,再跑一次同樣的 up -d grafana,並把密碼再重設成隨機值。

網段設定:grafana-authproxy 是只有 nginx 與 Grafana 的 docker 網路,預設 172.30.253.0/28、nginx 固定 172.30.253.2(放在動態分配範圍 172.30.253.8/29 之外)。與主機或其他網路衝突時,在 .env 一起改 GRAFANA_AUTHPROXY_SUBNET、GRAFANA_AUTHPROXY_IP_RANGE、GRAFANA_AUTHPROXY_NGINX_IP。設 GRAFANA_AUTH_PROXY_ENABLED=false 會關掉免密碼登入,也就沒有任何從網頁進入 Grafana 的方式(上面的緊急程序除外)。

Proxmox VE Metric Server 設定 ​

  1. .env 設:

    • INFLUXDB_ADMIN_TOKEN:換成隨機長字串(openssl rand -hex 32)
    • INFLUXDB_BIND_ADDRESS:PVE 節點連得到的 SkyLab 主機 IP(或 0.0.0.0),預設只綁 127.0.0.1
  2. docker compose --profile monitoring up -d influxdb

  3. 建立 PVE 專用、只能寫入的 token(不要把 admin token 放到 PVE):

    bash
    docker compose exec influxdb influx bucket list --org skylab   # 記下 proxmox 的 bucket ID
    docker compose exec influxdb influx auth create --org skylab \
      --write-bucket <bucket-id> --description "proxmox metric server"
  4. PVE 網頁:Datacenter → Metric Server → Add → InfluxDB

    • Name:skylab
    • Server:SkyLab 主機 IP,Port:8086
    • Protocol:HTTP(InfluxDB 2 的 HTTP API)
    • Organization:skylab,Bucket:proxmox
    • Token:第 3 步產生的寫入 token

    或在任一節點下指令:

    bash
    pvesh create /cluster/metrics/server/skylab --type influxdb \
      --server <SkyLab IP> --port 8086 --influxdbproto http \
      --organization skylab --bucket proxmox --token <寫入 token>
  5. 設定是整個叢集共用;多個 PVE 連線(多個叢集)就在每個叢集各設一次。約 10 秒後 Grafana 的 Proxmox 儀表板就有資料。

有多組 SkyLab 或想用社群版儀表板時,也可以在 Grafana 匯入 ID 15356(Proxmox [Flux]),資料來源選「InfluxDB (Proxmox)」。

Gateway 監控 ​

Gateway 主機由 gateway/install.sh 安裝兩個 exporter(Debian 套件),Prometheus 透過 backend 的 /metrics/gateway-targets(http_sd)自動找到 Gateway 的位址,不必手動改 prometheus.yml:

exporterport內容
prometheus-node-exporter9100CPU、記憶體、磁碟、各網卡流量(含 wg0)、TCP 連線數
prometheus-nginx-exporter9113nginx 的 stub_status(活躍連線、請求數);stub_status 只綁 127.0.0.1:9180

安裝時要用 MONITORING_ALLOW_FROM 指定 Prometheus 所在主機(通常就是跑 SkyLab 的那台)的 IP,UFW 只對它開放這兩個 port:

bash
sudo MONITORING_ALLOW_FROM=192.0.2.20 bash install.sh

沒設的話 exporter 照樣會裝,但 Prometheus 連不進來,gateway-node/gateway-nginx 兩個 job 會一直 down(「SkyLab Gateway」儀表板的 exporter 狀態顯示 DOWN)。從「閘道 VM」頁的「安裝服務」分頁執行安裝時,改填「監控放行來源」欄位。已經裝好的 Gateway 帶著這個位址重跑一次安裝即可補上。

exporter 裝不起來或啟動失敗(例如 port 被占用)時,安裝腳本只會警告並繼續,nginx 與 WireGuard 照樣裝好;用 journalctl -u prometheus-node-exporter -u prometheus-nginx-exporter 查原因,修好後重跑 install.sh。

stub_status 只涵蓋 http(對外網址);Port 轉發(nginx stream)沒有對應的連線統計,請看「SkyLab Gateway」儀表板的 TCP 連線數與網卡流量。

Gateway 服務異常、憑證快到期的通知由內建的系統告警負責(component:gateway),監控 stack 這邊只看圖。

AI 模組監控 ​

AI 的資料來自三個地方,Prometheus 都自動抓,不必手動改 prometheus.yml:

job來源內容
skylab-backendbackend /metrics 的 skylab_ai_*SkyLab 這一側:每次使用者 API 金鑰(source=api_key)與內建 AI 功能(source=platform)呼叫的結果、延遲、首字延遲、token
litellmlitellm:4000/metrics(Compose 內網)LiteLLM 的 prometheus callback:請求與狀態碼、上游部署成功/失敗、上游延遲、gateway 自身開銷、部署狀態
vllm每台 vLLM 的 /metrics引擎本身:執行中/排隊請求、KV cache、prefill/decode 吞吐、TTFT、token 間延遲、搶占
  • vLLM 目標由 bash scripts/prepare-ai-stack.sh 依 vllm-service/models.json 寫進 monitoring/prometheus/targets/vllm.json(Git 忽略),同一台上游只抓一次;改模型或 IP 後重新部署,Prometheus 一分鐘內自動換目標。local 模型經 host.docker.internal 連主機(與 LiteLLM 相同)。
  • 遠端推論主機(DGX 等)的防火牆要放行 Prometheus 所在主機(通常就是 SkyLab 部署機)連推論埠;和 LiteLLM 需要的是同一條規則。vLLM 的 /metrics 不需要 API key(它只保護 /v1)。「SkyLab AI」儀表板的「推論引擎」顯示 DOWN 時,先在部署機 curl http://<DGX_IP>:8103/metrics 確認。
  • LiteLLM /metrics 免驗證:config.template.yaml 設了 require_auth_for_metrics_endpoint: false,否則只有 master key 讀得到(不能把 master key 放進 Prometheus)。LiteLLM 只在 Compose 內網與主機 127.0.0.1:4000,nginx 不轉發,所以不會對外公開。litellm job 會丟掉 requested_model、client_ip、user_agent、金鑰雜湊等無上限的 label,分模型改看部署層的 litellm_model_name/model。
  • GPU 本身(溫度、顯存、使用率)不在這裡;需要時在 DGX 上另外跑 NVIDIA DCGM exporter,再照 Gateway 的方式加一個 Prometheus job。

模型不健康、LiteLLM 或它的資料庫掛掉的通知由內建的系統告警負責(component:ai_gateway、component:ai_model:<alias>),監控 stack 這邊只看圖。

/metrics 驗證(選用) ​

/metrics 只在 compose 內網與 127.0.0.1:8000 開放,nginx 對 /metrics 回 404。若主機上還有其他不信任的程式,可以加上 token:

  1. .env 設 METRICS_TOKEN=<隨機字串>
  2. 把同一個字串寫進 monitoring/prometheus/metrics_token(單行,勿提交到 git)
  3. 取消 monitoring/prometheus/prometheus.yml 中 skylab-backend job 那三行 authorization 的註解,並在 gateway-node、gateway-nginx 兩個 job 的 http_sd_configs 加上同樣的區塊(/metrics/gateway-targets 也驗同一個 token),再重啟 prometheus

指標一覽(backend /metrics) ​

指標說明
http_requests_total{method,path,status,workload}、http_request_duration_seconds{method,path,workload}以 method/路由樣板分一般 API、AI 生成與 other;對不到路由仍為 path="<unmatched>";HTTP duration 含 ASGI 收尾,上界 600 秒不是 timeout。
http_requests_in_progress處理中的請求數
skylab_websocket_connections{kind}vnc/terminal/jobs/classroom/classroom_watch/course_progress
skylab_scheduler_task_runs_total{loop,task,result}、skylab_scheduler_task_duration_seconds排程任務執行次數與耗時
skylab_scheduler_task_last_success_timestamp_seconds、skylab_scheduler_task_consecutive_failures心跳
skylab_scheduler_loop_last_tick_timestamp_seconds、skylab_scheduler_loop_is_leader迴圈是否在跑、這個行程是不是 leader
skylab_dependency_up{component}、skylab_dependency_latency_secondsdatabase/redis/worker/pve:<id>/gateway/ai_gateway/ai_model:<alias>
skylab_queue_jobs{queue}arq 佇列等待中的任務數
skylab_task_records{status}queued/running(當下)、failed_24h/succeeded_24h
skylab_ai_requests_total{source,model,request_type,outcome}AI 呼叫次數;outcome=success/client_error/rate_limited/unavailable/upstream_error/stream_error/cancelled/error
skylab_ai_request_duration_seconds{source,model,stream,request_type,outcome}、skylab_ai_time_to_first_token_seconds{source,model}Public 每筆 logical request/System 每次模型呼叫的耗時;TTFT 僅 public 串流首字。取消不進 duration,System 非串流沒有 TTFT 樣本。
skylab_ai_proxy_queue_wait_seconds{model}每筆公開 logical request 終止時記一次累積 admission/retry cooldown 等待;排除 catalogue/生成;取消/失敗也記錄。
skylab_ai_workflows_total{route,outcome,terminal_reason}Navigation/PVE 流程終止結果;HTTP 200 fallback、adherence 失敗與政策拒絕分開,不等於模型呼叫數。
skylab_ai_tokens_total{source,model,direction}模型回報的 input/output token

依賴元件與佇列指標在 Prometheus 抓取時才更新(最多每 5 秒一次);PVE 連線、Gateway 與 AI 狀態沿用最近一次系統健康檢查的結果,不會因為 Prometheus 抓取而去打 PVE/SSH/LiteLLM。

skylab_ai_* 的 model 只保留 LiteLLM 成功服務過、或健康檢查查到的模型名稱(上限 100 個),呼叫端亂填的名稱一律歸為 other,時間序列數量才有上限。

判讀 AI 面板:

  • 改指標名稱或 bucket 時,所有 backend instance 與儀表板要一起更新。要比較改版前後,等最後一個舊 instance 退出、且過了最長查詢窗(15 分鐘)之後再看。
  • 面板空白代表沒有樣本。分位數落在 +Inf 時會被截在最大的有限 bucket,所以要一併看超過 600 秒的比例、樣本數與等待中的請求。
  • structured logs ai_relay_finished 與 ai_workflow_finished 會把 root/child request ID 對應到有限的終止原因與各階段耗時,不含 prompt、回答或工具 payload;這些 ID 不會放進 metric label。PVE 助手的一筆 HTTP 請求可能包含多次生成/adherence 呼叫與工具執行,不要把各階段的 P95 相加。
  • 認證、DB 連線、用量 backlog、retry 與 event-loop lag 面板可以用來解釋某段時間為什麼變慢;scrape 之間短暫的 event loop 阻塞可能抓不到。

資源與保留期 ​

元件保留調整
Prometheus15 天PROMETHEUS_RETENTION
Loki14 天monitoring/loki/loki-config.yml 的 retention_period
InfluxDB(Proxmox)30 天INFLUXDB_RETENTION(只在第一次初始化時生效)

整套監控 stack 約需 1–1.5 GB 記憶體。cAdvisor 與 node-exporter 讀的是主機資訊,在 Docker Desktop(Windows/macOS)上看到的是 Docker VM 而不是實體主機。

以 AGPL-3.0 授權釋出。