Skip to main content
Relay exposes Prometheus metrics for traffic, its own added latency, load shedding, background record loss and key health. Every Relay metric is in the relay namespace; the standard Go runtime (go_*) and process (process_*) collectors are registered too.

Scrape endpoint

Metrics are served at /metrics on the control listener (RELAY_CONTROL_PORT, default 8081), at the listener root, not under /api. Each pod reports its own counters, so scrape every pod.
Prometheus scrape config
/metrics needs no credentials. Keep the control port off the public network, or put the scrape path behind your own access control. On Kubernetes, the Helm chart can create the scrape config (serviceMonitor.enabled for the Prometheus Operator, vmPodScrape.enabled for the VictoriaMetrics operator) and ship two Grafana dashboards as ConfigMaps labelled grafana_dashboard (grafanaDashboards.enabled): Relay — Service, built on these metrics (traffic, latency, overhead, admission, in-flight requests, queue depth, records lost, keys down, per-pod runtime), and Relay — Usage (ClickHouse), which reads the ClickHouse usage store through the Grafana ClickHouse data source. See Kubernetes.

Measuring Relay overhead

relay_overhead_seconds is the time Relay adds to a request: total time minus the upstream leg, where the upstream leg runs from handing the request to the upstream until the upstream finished sending its response. What remains is routing, rate-limit reservation, key selection, request and response translation, and any failed upstream attempts before the one that succeeded. The clock starts after the credential check and the request body read, so neither is counted. It is observed only for requests whose upstream response was read to the end; a request refused before reaching an upstream, or cut off mid-response, adds no sample. relay_admission_seconds is the part before the handoff. Read it per source, as a quantile over the histogram:
Buckets run from 100 µs to 500 ms. The value depends on your deployment: the round-trip time to the state store (Valkey/Redis), whether the request is translated between shapes, and how often keys fail over. Compare it with relay_request_seconds to see what share of end-to-end latency is Relay’s. Proxy-mode requests (source="proxy") forward the body without translation, so they show the floor for your setup.

Request flow

All are labelled by source, the runner that handled the request: pipeline (normal mode), proxy, ws (a WebSocket frame), batch or count (a count-tokens request). relay_inflight_requests / relay_inflight_limit is a pod’s headroom before it starts shedding. A non-zero shed rate means the pod is at capacity, which a quota 429 (error_kind rate_limited in usage) is not.

Auth rejection reasons

reason is the message of a 401 or the error code of a 403, exactly as emitted:

Health and saturation

relay_provider_keys_down_total counts transitions into cooldown, not keys down right now: breaker state is shared across pods, so a per-pod gauge would disagree between pods, while transition counts add up. Alert on its rate.

OTLP receiver

Counted only for exports to the OTLP receiver.