// Package metrics is a tiny in-process registry of named counters and gauges // exposed as JSON at /metricsz. No external metrics system is required. package metrics import ( "sync" "sync/atomic" ) type Registry struct { mu sync.RWMutex counters map[string]*atomic.Int64 gauges map[string]*atomic.Int64 } func NewRegistry() *Registry { return &Registry{ counters: make(map[string]*atomic.Int64), gauges: make(map[string]*atomic.Int64), } } func (r *Registry) cell(m map[string]*atomic.Int64, name string) *atomic.Int64 { r.mu.RLock() c, ok := m[name] r.mu.RUnlock() if ok { return c } r.mu.Lock() defer r.mu.Unlock() if c, ok = m[name]; !ok { c = new(atomic.Int64) m[name] = c } return c } // Inc adds delta to a monotonic counter. func (r *Registry) Inc(name string, delta int64) { r.cell(r.counters, name).Add(delta) } // Set assigns the current value of a gauge (e.g. queue depth). func (r *Registry) Set(name string, value int64) { r.cell(r.gauges, name).Store(value) } // Snapshot returns a point-in-time copy of all values for /metricsz. func (r *Registry) Snapshot() (counters, gauges map[string]int64) { r.mu.RLock() defer r.mu.RUnlock() counters = make(map[string]int64, len(r.counters)) for k, v := range r.counters { counters[k] = v.Load() } gauges = make(map[string]int64, len(r.gauges)) for k, v := range r.gauges { gauges[k] = v.Load() } return counters, gauges }