metrics

package
v1.3.3 Latest Latest
Warning

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

Go to latest
Published: Jun 4, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package metrics is the OpenTelemetry-backed metrics surface for craftgo runtimes. It owns the project-wide MeterProvider and the Prometheus exporter that the admin server scrapes.

The package itself records no metrics directly. The HTTP instruments (`http.server.request.duration` histogram, request / response size histograms, active-request gauge) are emitted by `otelhttp.NewHandler` - wired via pkg/otel.HTTPMiddleware - against whatever MeterProvider Init (or InitDefault) installs on the global slot. Application code that wants its own counters or histograms calls `otel.Meter("...")` directly; this package exists to bootstrap and expose, not to invent a parallel API.

Index

Constants

View Source
const DefaultAdminAddr = ":9090"

DefaultAdminAddr is the conventional Prometheus admin port. Used as a hint in docs; pass any addr string to StartAdmin to override.

View Source
const DefaultMetricsPath = "/metrics"

DefaultMetricsPath is the canonical Prometheus exposition path. `StartAdmin` uses this when no WithPath option is supplied.

Variables

This section is empty.

Functions

func Init

func Init(opts ...Option) (*sdkmetric.MeterProvider, error)

Init wires an OTel MeterProvider with the supplied readers. With zero options it defaults to WithPrometheusReader so the dev-mode `/metrics` scrape works without extra plumbing. Production deployments compose the readers they actually need:

// Pull (Prometheus scrape):
metrics.Init(metrics.WithPrometheusReader())

// Push (OTLP gRPC to collector):
metrics.Init(metrics.WithOTLPgRPCReader(ctx, "collector:4317"))

// Both — side-by-side scrape and push:
metrics.Init(
    metrics.WithPrometheusReader(),
    metrics.WithOTLPgRPCReader(ctx, "collector:4317"),
)

Returns the configured provider so callers can shut it down via `provider.Shutdown(ctx)` during graceful termination - important for OTLP push so the final batch flushes before the process exits.

func InitDefault

func InitDefault() (*sdkmetric.MeterProvider, error)

InitDefault is the dev-friendly shorthand: it calls Init with the Prometheus reader and installs the standard Go runtime / process collectors so the `/metrics` scrape surfaces `go_*` (goroutines, GC, memory) and `process_*` (RSS, CPU, FDs) alongside the HTTP instruments `otelhttp` emits. Production projects pick the more granular Init when they want a different reader set.

Errors from collector registration are surfaced; the MeterProvider itself is already installed by then, so the HTTP histogram path keeps working even if a runtime collector fails to register (rare but possible if a host strips procfs).

func InitFromConfig

func InitFromConfig(ctx context.Context, c Config) (*sdkmetric.MeterProvider, *adminServer, error)

InitFromConfig dispatches the exporter selection encoded in c, then starts the admin scrape listener for the prometheus path. Returns the active MeterProvider and the admin server (nil when no admin listener was needed) so the caller can defer Shutdown on both.

When c.Enabled is false everything is (nil, nil, nil) - the caller can keep its shutdown code single-pathed.

func IsEnabled

func IsEnabled() bool

IsEnabled reports whether the package has installed a MeterProvider. Returns false until Init / InitDefault succeeds.

func RegisterRuntimeCollectors

func RegisterRuntimeCollectors() error

RegisterRuntimeCollectors attaches the standard Go runtime and process Prometheus collectors to the package registry. Call it after Init when you want `go_*` / `process_*` series alongside the OTel-bridged metrics - the config-driven main.tmpl pipeline uses it for the prometheus exporter path. Idempotent: a duplicate registration is silently swallowed so repeated boots in tests don't break.

func Registerer

func Registerer() prom.Registerer

Registerer exposes the underlying Prometheus registry so application code can attach process / runtime collectors (`prometheus.NewGoCollector`, `prometheus.NewProcessCollector`) on top of the OTel-bridged metrics. The returned interface is the standard `prometheus.Registerer`, so any client_golang-compatible metric surfaces alongside the OTel ones on the same /metrics scrape.

func ShutdownAdmin

func ShutdownAdmin(ctx context.Context, s *http.Server) error

ShutdownAdmin gracefully closes a running admin server with a bounded deadline. Tolerates a nil server so callers don't have to guard the StartAdmin("") sentinel - a no-op when nothing was started.

func SnapshotHandler

func SnapshotHandler() http.Handler

SnapshotHandler returns the Prometheus text-format exposition handler bound to the package's registry. Wire it manually on a route when StartAdmin's dedicated listener is overkill (single port deployments, sidecar scrape configs):

srv.Handle("GET /metrics", metrics.SnapshotHandler())

The handler honours the standard scrape negotiation: clients asking for `application/openmetrics-text` get OpenMetrics; the default Prometheus exposition (text/plain; version=0.0.4) is emitted otherwise. When Init / InitDefault has not been called the registry is empty - the response stays valid (an empty scrape) so health probes and monitor smoke checks still see 200.

func StartAdmin

func StartAdmin(addr string, opts ...AdminOption) (*http.Server, <-chan error)

StartAdmin spins up a dedicated HTTP listener exposing the metrics snapshot on a separate admin port (Prometheus convention, default `:9090`). Keeping telemetry off the public traffic listener is the idiomatic split - public clients get the typed API on the main port, ops scrape the admin port without being firewalled in.

addr controls the listen address (`:9090`, `127.0.0.1:9090`, ...); pass an empty string to opt out of the listener entirely (the function returns nil + nil so callers can leave the call site unconditional). Path defaults to DefaultMetricsPath; override with WithPath when a different convention applies.

The returned `*http.Server` is the live listener; callers Shutdown it during their main lifecycle (typical pattern: pair with the public server's Shutdown so `Ctrl+C` drains both).

On listener errors the returned `<-chan error` channel surfaces the failure asynchronously so the caller can decide whether to log + continue (admin failures usually shouldn't kill the public server) or hard-exit. The channel is buffered so a never-read receiver does not block the goroutine that closes it.

Types

type AdminOption

type AdminOption func(*adminConfig)

AdminOption mutates the admin server's configuration. Callers compose options at the call site:

metrics.StartAdmin(":9090", metrics.WithPath("/internal/metrics"))

New knobs land here as additional `WithX` constructors so the StartAdmin signature stays stable.

func WithPath

func WithPath(p string) AdminOption

WithPath overrides the route the metrics snapshot is served on. Defaults to DefaultMetricsPath (`/metrics`). Useful when an existing reverse proxy already claims that path or the company convention is something else (`/internal/metrics`, `/_/observability`, ...).

type Config

type Config struct {
	// Enabled toggles the MeterProvider install AND the admin
	// listener startup. False = no-op meter (otelhttp's recorder
	// stays silent).
	Enabled bool `yaml:"enabled"`
	// Exporter selects the data path:
	//   - "prometheus" / "" - pull on AdminAddr (default)
	//   - "otlp_grpc"  - push via OTLP gRPC
	//   - "otlp_http"  - push via OTLP HTTP/protobuf
	//   - "none"       - meter installed without exporter (testing)
	Exporter string `yaml:"exporter"`
	// Endpoint is the collector address for OTLP exporters. Ignored
	// for "prometheus" / "none".
	Endpoint string `yaml:"endpoint"`
	// AdminAddr is the bind address for the Prometheus scrape
	// listener. Ignored unless Exporter == "prometheus".
	AdminAddr string `yaml:"adminAddr"`
	// Path is the scrape route (default "/metrics"). Override when a
	// reverse proxy already claims that path.
	Path string `yaml:"path"`
}

Config is the YAML-shaped meter configuration the generated runtime hands to InitFromConfig. Mirrors the `metrics:` block in `config/config.yaml` so the call site reads `metrics.InitFromConfig(ctx, cfg.Metrics)`. Defining the type here keeps the exporter dispatch + admin-listener wiring in the library.

type Option

type Option func(*config)

Option configures the MeterProvider built by Init. Each option either appends a Reader to the provider (Prometheus pull, OTLP gRPC push, OTLP HTTP push) or attaches metadata. Errors that occur while building exporters are captured on the config; the first error short-circuits the rest and surfaces from Init.

func WithOTLPHTTPReader

func WithOTLPHTTPReader(ctx context.Context, endpoint string, opts ...otlpmetrichttp.Option) Option

WithOTLPHTTPReader adds a periodic OTLP HTTP/protobuf push exporter pointed at endpoint (e.g. `"http://collector:4318"` for plain HTTP or `"https://collector.example.com"` for TLS). Same insecure-by- default trade-off as WithOTLPgRPCReader; pass `otlpmetrichttp.WithTLSClientConfig(...)` to opt into TLS.

func WithOTLPgRPCReader

func WithOTLPgRPCReader(ctx context.Context, addr string, opts ...otlpmetricgrpc.Option) Option

WithOTLPgRPCReader adds a periodic OTLP gRPC push exporter pointed at addr (e.g. `"otel-collector.observability:4317"`). Push interval defaults to 60s - the OTel SDK default; pass `otlpmetricgrpc.WithCompressor("gzip")` and friends through opts for transport tuning. By default the connection is INSECURE (plain-text, no TLS) so collectors on the local k8s network work out of the box; supply `otlpmetricgrpc.WithTLSCredentials(...)` to override for cross-cluster traffic.

func WithPrometheusReader

func WithPrometheusReader() Option

WithPrometheusReader adds a Prometheus pull exporter scoped to the package registry. Pair it with StartAdmin (or wire SnapshotHandler manually) to expose `/metrics` for scrapers.

The default when Init is called with no options.

func WithReader

func WithReader(r sdkmetric.Reader) Option

WithReader is the escape hatch: hand any pre-built `sdkmetric.Reader` to Init. Use it when the project needs a custom exporter (in-memory for tests, third-party SaaS, exotic transport) the Prometheus / OTLP helpers don't cover. Stack as many WithReader options as needed - the same MeterProvider fans every metric to all readers.

Jump to

Keyboard shortcuts

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