2026-09-30 19:49:05 +08:00
|
|
|
# History, recorded so nobody re-derives it the hard way: on 2026-09-29 the
|
|
|
|
|
# three latency series below recorded nothing. internal/proxy/llm_metrics.go
|
|
|
|
|
# declared a capture wrapper (LLMMetricsCapture) that was never constructed
|
|
|
|
|
# anywhere, so the exporter emitted HELP-only stubs and the dashboard panels
|
|
|
|
|
# stayed empty.
|
2026-09-29 22:47:38 +08:00
|
|
|
#
|
2026-09-30 19:49:05 +08:00
|
|
|
# homelab-frontend#63 fixed exactly that. The wrapper is now
|
|
|
|
|
# ResponseWriterWrapper, constructed by NewResponseWriterWrapper
|
|
|
|
|
# (internal/proxy/llm_metrics.go:38) and installed on the streaming proxy
|
|
|
|
|
# request path. Verified live on 2026-09-29:
|
|
|
|
|
# llm_ttft_seconds count=7 sum=598.212s
|
|
|
|
|
# llm_itl_seconds count=16116
|
|
|
|
|
# llm_tokens_total 3 series
|
2026-09-29 22:47:38 +08:00
|
|
|
#
|
2026-09-30 19:49:05 +08:00
|
|
|
# These derived-from-SSE series cover EVERY model including the two Ollama ones
|
|
|
|
|
# (ornith:35b, qwen2.5:3b-instruct), which expose no metrics endpoint at all.
|
|
|
|
|
# They are proxy-side: TTFT is request-start to first byte and ITL is the gap
|
|
|
|
|
# between SSE writes, so both are granular to SSE write boundaries rather than
|
|
|
|
|
# to the engine's own token cadence. llm_tokens_total counts `data:` events,
|
|
|
|
|
# and the documented assumption in internal/proxy/llm_metrics.go is that these
|
|
|
|
|
# upstreams emit one such event per token — so it is a token count only as far
|
|
|
|
|
# as that assumption holds. vLLM's own histograms remain authoritative.
|
2026-09-29 22:47:38 +08:00
|
|
|
#
|
2026-09-30 19:49:05 +08:00
|
|
|
# Also recorded and working (3 series, one per replica):
|
2026-09-29 22:14:49 +08:00
|
|
|
# queue_full_requests_total counter backpressure rejects
|
|
|
|
|
# warmup_requests_delayed_total counter vLLM slot contention
|
|
|
|
|
# vllm_prefix_cache_hit_tokens_total counter prefix-cache hits
|
2026-09-30 19:49:05 +08:00
|
|
|
#
|
|
|
|
|
# NOT working, do not build on it: request_duration_seconds is declared and
|
|
|
|
|
# exported but has 0 samples, and its only writer Metrics.RecordRequest has
|
|
|
|
|
# zero call sites outside _test.go — verified by ast-grep, not assumed. It is
|
|
|
|
|
# the same dead-code shape this branch already corrected for the latency
|
|
|
|
|
# series, so it is listed here rather than left to be rediscovered.
|
2026-09-29 22:14:49 +08:00
|
|
|
#
|
2026-09-29 22:47:38 +08:00
|
|
|
# Also note the Deployment already carried prometheus.io/scrape annotations,
|
|
|
|
|
# but kube-prometheus-stack ignores pod annotations (no additionalScrapeConfigs,
|
|
|
|
|
# serviceMonitorSelectorNilUsesHelmValues: false) — so nothing at all was being
|
|
|
|
|
# collected before this ServiceMonitor existed.
|
2026-09-29 22:05:00 +08:00
|
|
|
apiVersion: monitoring.coreos.com/v1
|
|
|
|
|
kind: ServiceMonitor
|
|
|
|
|
metadata:
|
|
|
|
|
name: api-gateway
|
|
|
|
|
namespace: monitoring
|
|
|
|
|
labels:
|
|
|
|
|
app.kubernetes.io/name: api-gateway
|
|
|
|
|
app.kubernetes.io/part-of: api
|
|
|
|
|
spec:
|
|
|
|
|
namespaceSelector:
|
|
|
|
|
matchNames:
|
|
|
|
|
- api
|
|
|
|
|
selector:
|
|
|
|
|
matchLabels:
|
|
|
|
|
app: api-gateway
|
|
|
|
|
endpoints:
|
|
|
|
|
# api-gateway Service port IS named `http` (unlike the KServe ones), so
|
|
|
|
|
# the name form works here.
|
|
|
|
|
- port: http
|
|
|
|
|
interval: 30s
|
|
|
|
|
scrapeTimeout: 10s
|
|
|
|
|
path: /metrics
|
|
|
|
|
scheme: http
|
|
|
|
|
|