All checks were successful
CI / lint (push) Successful in 33s
CI / test (push) Successful in 2m6s
Deploy / notebooks (push) Has been skipped
CI / notebooks-smoke (push) Successful in 1m31s
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / llm (push) Successful in 1m21s
Deploy / mc (push) Has been skipped
Deploy / api (push) Successful in 1m46s
Infra CI / docs (push) Successful in 21s
Infra CI / llm (push) Successful in 15s
Infra CI / mc (push) Successful in 14s
Deploy / report (push) Successful in 11s
Infra CI / zotero (push) Successful in 17s
Infra CI / notebooks (push) Successful in 50s
Infra CI / api (push) Successful in 19s
The P26 telemetry path never reached Prometheus: setup_meter_provider only installs an in-process PrometheusMetricReader, nothing served the registry (api and llm answered 404 on /metrics), the images never installed the perf extra, STACK_TELEMETRY was off, and no scrape target existed — so the data-pipelines request-rate panel was empty from the day it was written. Now: perf.middleware.instrument mounts GET /metrics (prometheus_client registry), the api and llm images install --extra perf, compose sets STACK_TELEMETRY=true on both, services.yml scrapes api:8000 and llm:8000, and both dashboards' request-rate panels query http_server_duration_milliseconds_count (what the FastAPI instrumentor emits; stack_http_server_requests_total never existed). Verified live: stack_llm_dispatch_total is queryable in Prometheus with job=llm.
257 lines
5.4 KiB
JSON
257 lines
5.4 KiB
JSON
{
|
|
"title": "LLM service",
|
|
"uid": "llm",
|
|
"tags": [
|
|
"homelab",
|
|
"stack"
|
|
],
|
|
"timezone": "browser",
|
|
"schemaVersion": 39,
|
|
"time": {
|
|
"from": "now-6h",
|
|
"to": "now"
|
|
},
|
|
"refresh": "30s",
|
|
"panels": [
|
|
{
|
|
"id": 1,
|
|
"title": "HTTP request rate (status)",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 0,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "sum by (http_status_code) (rate(http_server_duration_milliseconds_count{job=\"llm\"}[1m]))",
|
|
"legendFormat": "{{http_status_code}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 2,
|
|
"title": "Chat answers by outcome",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 12,
|
|
"y": 0,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "sum by (outcome) (rate(stack_llm_chat_total[5m]))",
|
|
"legendFormat": "{{outcome}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 3,
|
|
"title": "Dispatch rate per host",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 8,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "sum by (host, kind) (rate(stack_llm_dispatch_total[5m]))",
|
|
"legendFormat": "{{host}} {{kind}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 4,
|
|
"title": "In-flight requests per host",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 12,
|
|
"y": 8,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "sum by (host) (stack_llm_inflight)",
|
|
"legendFormat": "{{host}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 5,
|
|
"title": "Dispatch latency p50/p95 (host, kind)",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 16,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "s"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "histogram_quantile(0.50, sum by (le, host, kind) (rate(stack_llm_dispatch_seconds_bucket[5m])))",
|
|
"legendFormat": "p50 {{host}} {{kind}}"
|
|
},
|
|
{
|
|
"expr": "histogram_quantile(0.95, sum by (le, host, kind) (rate(stack_llm_dispatch_seconds_bucket[5m])))",
|
|
"legendFormat": "p95 {{host}} {{kind}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 6,
|
|
"title": "Chat latency by stage (p50/p95)",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 12,
|
|
"y": 16,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "s"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "histogram_quantile(0.50, sum by (le, stage) (rate(stack_llm_chat_seconds_bucket[5m])))",
|
|
"legendFormat": "p50 {{stage}}"
|
|
},
|
|
{
|
|
"expr": "histogram_quantile(0.95, sum by (le, stage) (rate(stack_llm_chat_seconds_bucket[5m])))",
|
|
"legendFormat": "p95 {{stage}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 7,
|
|
"title": "Embedding throughput per host (texts/s)",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 24,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "sum by (host) (rate(stack_llm_embedded_texts_total[5m]))",
|
|
"legendFormat": "{{host}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 8,
|
|
"title": "Chat tokens by direction",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 12,
|
|
"y": 24,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "sum by (direction) (rate(stack_llm_chat_tokens_total[5m]))",
|
|
"legendFormat": "{{direction}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 9,
|
|
"title": "Indexed chunks per collection",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 32,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "sum by (collection) (rate(stack_llm_indexed_chunks_total[5m]))",
|
|
"legendFormat": "{{collection}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 10,
|
|
"title": "Indexed items (indexed vs skipped)",
|
|
"type": "timeseries",
|
|
"gridPos": {
|
|
"x": 12,
|
|
"y": 32,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "prometheus"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "sum by (collection, outcome) (rate(stack_llm_indexed_items_total[5m]))",
|
|
"legendFormat": "{{collection}} {{outcome}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 11,
|
|
"title": "LLM service log tail",
|
|
"type": "logs",
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 40,
|
|
"w": 24,
|
|
"h": 8
|
|
},
|
|
"datasource": {
|
|
"uid": "loki"
|
|
},
|
|
"targets": [
|
|
{
|
|
"expr": "{container=\"llm\"}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|