metrics

package
v0.18.49 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 14, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package metrics owns the application's Prometheus instrumentation.

Rationale: kube-prometheus-stack already runs in the cluster and scrapes node/k8s/cnpg/argocd metrics out of the box. Adding a /metrics endpoint to rivolt with an explicit ServiceMonitor lights up per-handler latency, Rivian-result-class counters, and the other app-shaped signals the cluster-level scrapers can't see.

All metrics live on a private *prometheus.Registry rather than the global default. Reasons:

  • Tests can spin up a fresh registry per test.
  • We don't accidentally collide with go-collector / process-collector registrations from libraries that touch promauto.
  • The handler is exported scoped to this registry, so /metrics output is exactly what we asked for.

Naming follows Prometheus conventions: snake_case, base unit suffix (_seconds, _bytes, _total).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Metrics

type Metrics struct {

	// HTTP server side.
	HTTPRequestsTotal   *prometheus.CounterVec
	HTTPRequestDuration *prometheus.HistogramVec

	// Rivian upstream classification (transient/outage/rate-limited/
	// user-action/unknown — see internal/rivian/errclass.go). Counts
	// outcomes per call class, not per error string, so cardinality
	// stays bounded.
	RivianResultsTotal *prometheus.CounterVec

	// Subscription leases owned by this pod. The lease layer
	// increments/decrements as it claims and releases.
	SubscriptionLeases prometheus.Gauge

	// Circuit breaker telemetry. State is a 0/1/2 gauge
	// (closed/half_open/open) so Grafana can alert on
	// max_over_time != 0. Trips is a counter labelled by reason
	// ("rate_limited" | "outage") so we can answer "what's making
	// it open" in one PromQL.
	RivianBreakerState prometheus.Gauge
	RivianBreakerTrips *prometheus.CounterVec
	// Global token bucket gating. Counter increments every time
	// the bucket says no, partitioned by class so we can answer
	// "is priority being starved".
	RivianRateLimitBlocked *prometheus.CounterVec
	// AI provider spend per user is intentionally NOT exposed here.
	// User-id labels would blow up cardinality at 1000 vehicles. The
	// existing internal/ai/usage.go writes per-user totals to
	// Postgres; surface those via a Grafana SQL data source if/when
	// we want to chart them.
	AIRequestsTotal *prometheus.CounterVec
	// contains filtered or unexported fields
}

Metrics is the rivolt-specific instrumentation surface. One instance is built at startup and shared with anything that emits a metric. Keep it small — adding a metric here means it shows up in Grafana, so each one should answer a real question you'd want to ask at 3am.

func New

func New() *Metrics

New constructs a Metrics with all collectors registered against a fresh registry. Pass the returned *Metrics into any package that needs to record a sample. Call Handler() to mount /metrics.

func (*Metrics) HTTPMiddleware

func (m *Metrics) HTTPMiddleware(next http.Handler) http.Handler

HTTPMiddleware records request count + latency for every handler. Uses chi's RoutePattern (e.g. "/api/state/{vehicleID}") rather than the raw URL so cardinality stays bounded as vehicles scale.

Place AFTER chi route mounting (chi resolves the pattern when the handler runs, not before) — i.e. add it inside Router.Group / on individual subrouters that have routes mounted, OR rely on chi's behaviour of populating RouteContext as routing happens. We mount it at the root using a deferred capture: the recorder reads chi.RouteContext(r.Context()).RoutePattern() AFTER ServeHTTP, by which point chi has filled it in.

func (*Metrics) Handler

func (m *Metrics) Handler() http.Handler

Handler returns the http.Handler for /metrics scoped to this Metrics' private registry. Mount under /metrics with no auth — the Prometheus scraper inside the cluster reaches it via the pod IP, and the Ingress doesn't expose it externally (see deploy/helm/rivolt/templates/ingress.yaml).

func (*Metrics) Registry

func (m *Metrics) Registry() *prometheus.Registry

Registry returns the underlying registry. Tests use this to gather expected samples without going through the HTTP handler.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL