blob: 0467fd6f55427fc125f7de4479ebc03058ba67e4 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package metrics provides tracking arbitrary metrics composed of
// values of comparable types.
package metrics
import (
"sync"
"maps"
)
// Metric1 tracks metrics of values of some type.
type Metric1[T comparable] struct {
mu sync.Mutex
m map[T]int
}
// Add adds another instance of some value.
func (m *Metric1[T]) Add(v T) {
m.mu.Lock()
defer m.mu.Unlock()
if m.m == nil {
m.m = make(map[T]int)
}
m.m[v]++
}
// Count returns the number of instances we've seen of v.
func (m *Metric1[T]) Count(v T) int {
m.mu.Lock()
defer m.mu.Unlock()
return m.m[v]
}
// Metrics returns all the values we've seen, in an indeterminate order.
func (m *Metric1[T]) Metrics() []T {
return maps.Keys(m.m)
}
type key2[T1, T2 comparable] struct {
f1 T1
f2 T2
}
// Metric2 tracks metrics of pairs of values.
type Metric2[T1, T2 comparable] struct {
mu sync.Mutex
m map[key2[T1, T2]]int
}
// Add adds another instance of some pair of values.
func (m *Metric2[T1, T2]) Add(v1 T1, v2 T2) {
m.mu.Lock()
defer m.mu.Unlock()
if m.m == nil {
m.m = make(map[key2[T1, T2]]int)
}
m.m[key2[T1, T2]{v1, v2}]++
}
// Count returns the number of instances we've seen of v1/v2.
func (m *Metric2[T1, T2]) Count(v1 T1, v2 T2) int {
m.mu.Lock()
defer m.mu.Unlock()
return m.m[key2[T1, T2]{v1, v2}]
}
// Metrics returns all the values we've seen, in an indeterminate order.
func (m *Metric2[T1, T2]) Metrics() (r1 []T1, r2 []T2) {
for _, k := range maps.Keys(m.m) {
r1 = append(r1, k.f1)
r2 = append(r2, k.f2)
}
return r1, r2
}
type key3[T1, T2, T3 comparable] struct {
f1 T1
f2 T2
f3 T3
}
// Metric3 tracks metrics of triplets of values.
type Metric3[T1, T2, T3 comparable] struct {
mu sync.Mutex
m map[key3[T1, T2, T3]]int
}
// Add adds another instance of some triplet of values.
func (m *Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
m.mu.Lock()
defer m.mu.Unlock()
if m.m == nil {
m.m = make(map[key3[T1, T2, T3]]int)
}
m.m[key3[T1, T2, T3]{v1, v2, v3}]++
}
// Count returns the number of instances we've seen of v1/v2/v3.
func (m *Metric3[T1, T2, T3]) Count(v1 T1, v2 T2, v3 T3) int {
m.mu.Lock()
defer m.mu.Unlock()
return m.m[key3[T1, T2, T3]{v1, v2, v3}]
}
// Metrics returns all the values we've seen, in an indeterminate order.
func (m *Metric3[T1, T2, T3]) Metrics() (r1 []T1, r2 []T2, r3 []T3) {
for k := range m.m {
r1 = append(r1, k.f1)
r2 = append(r2, k.f2)
r3 = append(r3, k.f3)
}
return r1, r2, r3
}