2026-09-29 22:14:49 +08:00
|
|
|
# The gateway is the only source of per-request LLM latency covering EVERY
|
|
|
|
|
# model, including the two Ollama ones (ornith:35b, qwen2.5:3b-instruct) that
|
|
|
|
|
# expose no metrics endpoint at all. Series it emits, per
|
|
|
|
|
# internal/observability/prometheus.go:
|
|
|
|
|
# llm_ttft_seconds histogram time-to-first-token
|
|
|
|
|
# llm_itl_seconds histogram inter-token latency
|
|
|
|
|
# llm_tokens_total counter SSE chunks generated
|
|
|
|
|
# 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
|
|
|
|
|
# request_duration_seconds histogram full request
|
|
|
|
|
#
|
|
|
|
|
# Caveat: these are derived from the SSE byte stream, not from the engine.
|
|
|
|
|
# TTFT is request-start to first byte, ITL is the gap between SSE writes
|
|
|
|
|
# carrying "data: ", and llm_tokens_total counts SSE chunks rather than true
|
|
|
|
|
# tokens. They are also streaming-only — non-streaming requests record
|
|
|
|
|
# nothing. Treat vLLM's own histograms as authoritative for `reasoning`.
|
|
|
|
|
#
|
|
|
|
|
# The Deployment already carried prometheus.io/scrape annotations, but
|
|
|
|
|
# kube-prometheus-stack ignores pod annotations (no additionalScrapeConfigs,
|
|
|
|
|
# serviceMonitorSelectorNilUsesHelmValues: false), so none of the above was
|
|
|
|
|
# ever collected. This ServiceMonitor is what actually wires it up.
|
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
|
|
|
|
|
|