Documentation
¶
Overview ¶
Package metrics provides a Prometheus registry, a scrape handler, an HTTP request middleware, and the building block for extensible, conflict-free metrics across the SDK and the application.
One shared registry ¶
The model is a single registry, dependency-injected. The application builds one Metrics (which owns a *prometheus.Registry) at startup and passes that registry to every component that exposes metrics — SDK subsystems and the application's own business metrics alike. One registry means one /metrics endpoint and one place series can collide, so collisions are caught at startup rather than going silently unscraped.
m := metrics.New("myapp") // app-wide registry + HTTP collectors
http.Handle("/metrics", m.Handler())
Each package owns its metrics ¶
A subsystem defines its own collectors next to its code and registers them on the injected registry. It never reaches for the global default registry, so importing it has no global side effects and two subsystems never fight over registration. The outbox package is the model: outbox.NewMetrics(reg) builds servicekit_outbox_* collectors; the application just hands it m.Registry.
om := outbox.NewMetrics(m.Registry) // SDK subsystem metrics
relay := outbox.NewRelay(log, store, pub, outbox.RelayConfig{Metrics: om})
m.Registry.MustRegister(outbox.NewBacklogCollector(store, log)) // a custom collector
Adding your own metrics ¶
Application metrics use the same registry; distinct namespaces/subsystems keep names from colliding with the SDK's:
ordersTotal := metrics.Register(m.Registry, prometheus.NewCounterVec(
prometheus.CounterOpts{Namespace: "myapp", Subsystem: "orders", Name: "created_total"},
[]string{"channel"}))
ordersTotal.WithLabelValues("web").Inc()
Conflict-free registration ¶
Register is the primitive that makes this safe and ergonomic: it registers a collector and returns it, returns the already-registered equivalent instead of panicking on a duplicate (so constructing a subsystem's metrics twice — in tests, or across workers sharing a registry — is idempotent), and panics only on a genuine name clash between *different* collectors, surfacing the wiring bug at startup. A nil registry disables registration while leaving the collector's methods as safe no-ops, so a component can take an optional registry and stay metrics-agnostic.
Naming ¶
Use Namespace + Subsystem + Name on every collector. Convention here: the SDK uses the "servicekit" namespace with a per-subsystem Subsystem (e.g. servicekit_outbox_*); the application uses its own namespace. Distinct (namespace, subsystem, name) tuples are what guarantee no conflicts on the shared registry.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Register ¶ added in v0.5.0
func Register[C prometheus.Collector](reg prometheus.Registerer, c C) C
Register registers c on reg and returns it. If an identical collector is already registered (same fully-qualified name and labels) it returns the existing one instead of panicking; if a *different* collector clashes on the name it panics, surfacing the wiring bug at startup.
This is the building block for conflict-free, extensible metrics: each package (SDK or application) defines its own collectors and registers them on the one shared registry through Register. Distinct namespaces/subsystems keep names from colliding; the register-or-get behavior makes constructing a subsystem's metrics idempotent, so building it twice against the same registry (e.g. in tests, or two workers sharing a registry) reuses the collectors rather than crashing.
A nil reg disables registration: c is returned unregistered, so its methods (Inc/Observe/…) remain safe no-ops from the scrape's perspective. This lets a component accept an optional registry and stay metrics-agnostic.
Types ¶
type Metrics ¶
type Metrics struct {
Registry *prometheus.Registry
// contains filtered or unexported fields
}
Metrics bundles a registry with the standard HTTP request collectors.
func New ¶
New builds a Metrics with a fresh registry and registers Go runtime and process collectors plus HTTP request collectors.