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 }