Documentation
¶
Overview ¶
Package obs is Console's instrumentation seam: a small, stdlib-only API for recording counters, gauges, histograms, and spans about Console's own behavior (application performance monitoring, see docs/design/apm.md).
Instrumented code depends only on the Recorder interface. Nop is the zero-cost default used when metrics are disabled; Memory is an in-process registry that renders the Prometheus text exposition format. The concrete Recorder is chosen in internal/app (the composition root) and exposed as App.Obs, which is always non-nil.
Label cardinality ¶
Every distinct label-value combination creates a new time series that lives for the life of the process, so label values must come from a small, bounded set. Use registered route patterns ("GET /api/flags/{key}"), HTTP methods, status classes, operation names, and provider kinds. Never use raw URL paths, flag keys, subject keys, component IDs, request IDs, error strings, or any other user-controlled or unbounded value. As a backstop, Memory caps each metric name at MaxSeriesPerMetric series; instruments requested past the cap still work but are not exported.
Histogram buckets ¶
Histograms use the fixed DefaultBuckets (upper bounds, in seconds): 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, plus +Inf.
Index ¶
- Constants
- Variables
- func RuntimeCollector(version string) func(Recorder)
- func WrapProvider(next status.Provider, rec Recorder) status.Provider
- func WrapStore(next store.Store, rec Recorder) store.Store
- type Counter
- type Gauge
- type Histogram
- type Label
- type Memory
- func (m *Memory) AddCollector(fn func(Recorder))
- func (m *Memory) Counter(name string, labels ...Label) Counter
- func (m *Memory) Gauge(name string, labels ...Label) Gauge
- func (m *Memory) Histogram(name string, labels ...Label) Histogram
- func (m *Memory) StartSpan(ctx context.Context, _ string, _ ...Label) (context.Context, func(error))
- func (m *Memory) WritePrometheus(w io.Writer) error
- type Recorder
Constants ¶
const ( // CheckDuration is the check latency histogram, labelled provider. CheckDuration = "console_check_duration_seconds" // CheckResults counts check outcomes, labelled provider and state. CheckResults = "console_check_results_total" )
Status-provider metric names.
const ( // StoreOpDuration is the per-operation latency histogram, labelled op. StoreOpDuration = "console_store_op_duration_seconds" // StoreErrors counts failed operations, labelled op. Not-found and // conflict sentinels are expected outcomes and are not counted. StoreErrors = "console_store_errors_total" )
Store metric names.
const MaxSeriesPerMetric = 1000
MaxSeriesPerMetric bounds the number of label combinations Memory retains per metric name. Combinations beyond it get working but unexported instruments, so a cardinality bug cannot exhaust memory.
Variables ¶
var DefaultBuckets = []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10}
DefaultBuckets are the fixed histogram upper bounds, in seconds, used by Memory: 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10. An implicit +Inf bucket is always added. Treat as read-only.
Functions ¶
func RuntimeCollector ¶
RuntimeCollector returns a collector, suitable for Memory.AddCollector, that samples Go runtime health via runtime/metrics (no stop-the-world) and publishes it as gauges:
- go_goroutines: live goroutines.
- go_memstats_heap_alloc_bytes: bytes of allocated heap objects.
- go_gc_pause_seconds: CUMULATIVE time spent in GC stop-the-world pauses since process start. runtime/metrics exposes pauses only as a histogram, so this is an estimate: each bucket's count is weighted by the bucket midpoint (the finite bound for open-ended buckets). It is monotonically non-decreasing; use rate() or a delta to get recent pause time.
It also sets console_build_info{version} to 1. Samples of a kind the running Go version does not provide are skipped.
func WrapProvider ¶
WrapProvider returns a status.Provider that records check latency and result counts on rec, delegating to next. The provider label is next.Name() (the provider type, never the component ID) and the state label is the core.HealthState string. Name() is read once at wrap time. A state outside the core enum (e.g. from a plugin) is counted as unknown to keep label cardinality bounded.
func WrapStore ¶
WrapStore returns a store.Store that records latency and error counts for every method on rec, delegating to next. The op label is the method name. core.ErrNotFound and core.ErrConflict are not counted as errors. Instruments are resolved once here, so the per-call path does no label lookups.
Types ¶
type Counter ¶
type Counter interface {
// Inc adds 1.
Inc()
// Add adds v. Negative values are ignored to preserve monotonicity.
Add(v float64)
}
Counter is a monotonically increasing value.
type Gauge ¶
type Gauge interface {
// Set replaces the value.
Set(v float64)
// Add adds v (which may be negative).
Add(v float64)
// Inc adds 1.
Inc()
// Dec subtracts 1.
Dec()
}
Gauge is a value that can go up and down.
type Histogram ¶
type Histogram interface {
// Observe records one observation, conventionally in seconds.
Observe(v float64)
}
Histogram samples observations into fixed buckets.
type Label ¶
Label is a single metric dimension. Names must be valid Prometheus label names ([a-zA-Z_][a-zA-Z0-9_]*); values are arbitrary but must be bounded (see the package documentation).
type Memory ¶
type Memory struct {
// contains filtered or unexported fields
}
Memory is an in-process Recorder that keeps all series in memory and renders them in the Prometheus text exposition format via Memory.WritePrometheus. Spans are no-ops that preserve the context. Create one with NewMemory.
func (*Memory) AddCollector ¶
AddCollector registers fn to run at the start of every Memory.WritePrometheus call, before rendering. Collectors refresh scrape-time values (for example runtime stats set on gauges) using the Recorder passed in. fn must not call WritePrometheus.
type Recorder ¶
type Recorder interface {
// Counter returns the counter for name and labels.
Counter(name string, labels ...Label) Counter
// Histogram returns the histogram for name and labels.
Histogram(name string, labels ...Label) Histogram
// Gauge returns the gauge for name and labels.
Gauge(name string, labels ...Label) Gauge
// StartSpan returns a derived context and a func that ends the span,
// recording err (which may be nil) as its outcome.
StartSpan(ctx context.Context, name string, labels ...Label) (context.Context, func(err error))
}
Recorder is the instrumentation seam. The zero-cost default is Nop. Implementations must be safe for concurrent use. Requesting the same name and labels repeatedly returns instruments backed by the same series.
var Nop Recorder = nop{}
Nop is the do-nothing Recorder used when observability is disabled. Calls without labels are allocation-free (verified by tests). Passing labels through the Recorder interface may allocate the variadic slice, so hot paths should resolve instruments once at construction and reuse them rather than looking them up, with labels, on every call.