137 lines
3.5 KiB
Go
137 lines
3.5 KiB
Go
|
// Package metrics defines a concurrently-accessible metrics collector.
|
||
|
//
|
||
|
// A *metrics.M value exports methods to track integer counters and maximum
|
||
|
// values. A metric has a caller-assigned string name that is not interpreted
|
||
|
// by the collector except to locate its stored value.
|
||
|
package metrics
|
||
|
|
||
|
import "sync"
|
||
|
|
||
|
// An M collects counters and maximum value trackers. A nil *M is valid, and
|
||
|
// discards all metrics. The methods of an *M are safe for concurrent use by
|
||
|
// multiple goroutines.
|
||
|
type M struct {
|
||
|
mu sync.Mutex
|
||
|
counter map[string]int64
|
||
|
maxVal map[string]int64
|
||
|
label map[string]interface{}
|
||
|
}
|
||
|
|
||
|
// New creates a new, empty metrics collector.
|
||
|
func New() *M {
|
||
|
return &M{
|
||
|
counter: make(map[string]int64),
|
||
|
maxVal: make(map[string]int64),
|
||
|
label: make(map[string]interface{}),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Count adds n to the current value of the counter named, defining the counter
|
||
|
// if it does not already exist.
|
||
|
func (m *M) Count(name string, n int64) {
|
||
|
if m != nil {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
m.counter[name] += n
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// SetMaxValue sets the maximum value metric named to the greater of n and its
|
||
|
// current value, defining the value if it does not already exist.
|
||
|
func (m *M) SetMaxValue(name string, n int64) {
|
||
|
if m != nil {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
if old, ok := m.maxVal[name]; !ok || n > old {
|
||
|
m.maxVal[name] = n
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// CountAndSetMax adds n to the current value of the counter named, and also
|
||
|
// updates a max value tracker with the same name in a single step.
|
||
|
func (m *M) CountAndSetMax(name string, n int64) {
|
||
|
if m != nil {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
if old, ok := m.maxVal[name]; !ok || n > old {
|
||
|
m.maxVal[name] = n
|
||
|
}
|
||
|
m.counter[name] += n
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// SetLabel sets the specified label to value. If value == nil the label is
|
||
|
// removed from the set.
|
||
|
//
|
||
|
// As a special case, if value has the concrete type
|
||
|
//
|
||
|
// func() interface{}
|
||
|
//
|
||
|
// then the value of the label is obtained by calling that function.
|
||
|
func (m *M) SetLabel(name string, value interface{}) {
|
||
|
if m != nil {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
if value == nil {
|
||
|
delete(m.label, name)
|
||
|
} else {
|
||
|
m.label[name] = value
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EditLabel calls edit with the current value of the specified label.
|
||
|
// The value returned by edit replaces the contents of the label.
|
||
|
// If edit returns nil, the label is removed from the set.
|
||
|
// If the label did not exist, the argument to edit is nil.
|
||
|
func (m *M) EditLabel(name string, edit func(interface{}) interface{}) {
|
||
|
if m != nil {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
newValue := edit(m.label[name])
|
||
|
if newValue == nil {
|
||
|
delete(m.label, name)
|
||
|
} else {
|
||
|
m.label[name] = newValue
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Snapshot copies an atomic snapshot of the collected metrics into the non-nil
|
||
|
// fields of the provided snapshot value. Only the fields of snap that are not
|
||
|
// nil are snapshotted.
|
||
|
func (m *M) Snapshot(snap Snapshot) {
|
||
|
if m != nil {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
if c := snap.Counter; c != nil {
|
||
|
for name, val := range m.counter {
|
||
|
c[name] = val
|
||
|
}
|
||
|
}
|
||
|
if v := snap.MaxValue; v != nil {
|
||
|
for name, val := range m.maxVal {
|
||
|
v[name] = val
|
||
|
}
|
||
|
}
|
||
|
if v := snap.Label; v != nil {
|
||
|
for name, val := range m.label {
|
||
|
if fn, ok := val.(func() interface{}); ok {
|
||
|
v[name] = fn()
|
||
|
} else {
|
||
|
v[name] = val
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// A Snapshot represents a point-in-time snapshot of a metrics collector. The
|
||
|
// fields of this type are filled in by the Snapshot method of *M.
|
||
|
type Snapshot struct {
|
||
|
Counter map[string]int64
|
||
|
MaxValue map[string]int64
|
||
|
Label map[string]interface{}
|
||
|
}
|