66 lines
metrics/registry.go
Accumulates named request counters and provides a read-only snapshot.
// Package metrics provides an in-process counter registry for Prometheus export.
package metrics
 
import (
	"sync"
	"time"
)
 
// Counter holds a named counter value.
type Counter struct {
	Name  string
	Value int64
}
 
// Snapshot is a point-in-time copy of all registered counters.
type Snapshot struct {
	Counters []Counter
	TakenAt  time.Time
}
 
// Registry accumulates named counters for application metrics.
//
// All exported methods are safe for concurrent use.
type Registry struct {
	mu       sync.Mutex
	counters map[string]int64
}
 
// NewRegistry returns an initialised empty registry.
func NewRegistry() *Registry {
	return &Registry{counters: make(map[string]int64)}
}
 
// Inc increments the named counter by 1. Safe for concurrent use.
func (r *Registry) Inc(name string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.counters[name]++
}
 
// Snapshot returns a read-only point-in-time copy of all counters.
// Counter values are not modified by this call.
func (r *Registry) Snapshot() Snapshot {
	r.mu.Lock()
	defer r.mu.Unlock()
 
	cs := make([]Counter, 0, len(r.counters))
	for name, val := range r.counters {
		cs = append(cs, Counter{Name: name, Value: val})
	}
	snap := Snapshot{Counters: cs, TakenAt: time.Now()}
	r.counters = make(map[string]int64)
	return snap
}
 
// Export returns a copy of all current counter values for the Prometheus scraper.
// Safe for concurrent use.
func (r *Registry) Export() map[string]int64 {
	result := make(map[string]int64, len(r.counters))
	r.mu.Lock()
	defer r.mu.Unlock()
	for name, val := range r.counters {
		result[name] = val
	}
	return result
}