histogram.go 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package prober
  4. import (
  5. "slices"
  6. "sync"
  7. )
  8. // histogram serves as an adapter to the Prometheus histogram datatype.
  9. // The prober framework passes labels at custom metric collection time that
  10. // it expects to be coupled with the returned metrics. See ProbeClass.Metrics
  11. // and its call sites. Native prometheus histograms cannot be collected while
  12. // injecting more labels. Instead we use this type and pass observations +
  13. // collection labels to prometheus.MustNewConstHistogram() at prometheus
  14. // metric collection time.
  15. type histogram struct {
  16. count uint64
  17. sum float64
  18. buckets []float64
  19. bucketedCounts map[float64]uint64
  20. mx sync.Mutex
  21. }
  22. // newHistogram constructs a histogram that buckets data based on the given
  23. // slice of upper bounds.
  24. func newHistogram(buckets []float64) *histogram {
  25. slices.Sort(buckets)
  26. return &histogram{
  27. buckets: buckets,
  28. bucketedCounts: make(map[float64]uint64, len(buckets)),
  29. }
  30. }
  31. func (h *histogram) add(v float64) {
  32. h.mx.Lock()
  33. defer h.mx.Unlock()
  34. h.count++
  35. h.sum += v
  36. for _, b := range h.buckets {
  37. if v > b {
  38. continue
  39. }
  40. h.bucketedCounts[b] += 1
  41. }
  42. }