summaryrefslogtreecommitdiffhomepage
path: root/prober/histogram.go
blob: 5c52894f9eb0203f56fb9cd0e733afcf5ed4a120 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause

package prober

import (
	"slices"
	"sync"
)

// histogram serves as an adapter to the Prometheus histogram datatype.
// The prober framework passes labels at custom metric collection time that
// it expects to be coupled with the returned metrics. See ProbeClass.Metrics
// and its call sites. Native prometheus histograms cannot be collected while
// injecting more labels. Instead we use this type and pass observations +
// collection labels to prometheus.MustNewConstHistogram() at prometheus
// metric collection time.
type histogram struct {
	count          uint64
	sum            float64
	buckets        []float64
	bucketedCounts map[float64]uint64
	mx             sync.Mutex
}

// newHistogram constructs a histogram that buckets data based on the given
// slice of upper bounds.
func newHistogram(buckets []float64) *histogram {
	slices.Sort(buckets)
	return &histogram{
		buckets:        buckets,
		bucketedCounts: make(map[float64]uint64, len(buckets)),
	}
}

func (h *histogram) add(v float64) {
	h.mx.Lock()
	defer h.mx.Unlock()

	h.count++
	h.sum += v

	for _, b := range h.buckets {
		if v > b {
			continue
		}
		h.bucketedCounts[b] += 1
	}
}