Skip to content

Commit 67ff519

Browse files
committed
chore(promHistogram): remove Merge implementation and add LinearBuckets
1 parent 9c49c82 commit 67ff519

File tree

3 files changed

+52
-70
lines changed

3 files changed

+52
-70
lines changed

prometheus_histogram.go

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"sync"
88
)
99

10-
var defaultUpperBounds = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
10+
var PrometheusHistogramDefaultBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
1111

1212
// Prometheus Histogram is a histogram for non-negative values with pre-defined buckets
1313
//
@@ -79,38 +79,6 @@ func (h *PrometheusHistogram) Update(v float64) {
7979
h.buckets[bucketIdx]++
8080
}
8181

82-
// Merge merges src to h
83-
func (h *PrometheusHistogram) Merge(src *PrometheusHistogram) {
84-
// first we must compare if the upper bounds are identical
85-
valid := true
86-
if len(h.upperBounds) != len(src.upperBounds) {
87-
valid = false
88-
} else {
89-
for i := range h.upperBounds {
90-
if h.upperBounds[i] != src.upperBounds[i] {
91-
valid = false
92-
}
93-
}
94-
}
95-
96-
if !valid {
97-
panic("impossible to merge buckets with different bucket upper bounds")
98-
}
99-
100-
h.mu.Lock()
101-
defer h.mu.Unlock()
102-
103-
src.mu.Lock()
104-
defer src.mu.Unlock()
105-
106-
h.sum += src.sum
107-
h.count += src.count
108-
109-
for i := range h.buckets {
110-
h.buckets[i] += src.buckets[i]
111-
}
112-
}
113-
11482
// NewPrometheusHistogram creates and returns new prometheus histogram with the given name.
11583
//
11684
// name must be valid Prometheus-compatible metric with possible labels.
@@ -176,7 +144,7 @@ func GetOrCreatePrometheusHistogramExt(name string, upperBounds []float64) *Prom
176144
}
177145

178146
func newPrometheusHistogram(upperBounds []float64) *PrometheusHistogram {
179-
validateBuckets(upperBounds)
147+
mustValidateBuckets(upperBounds)
180148
last := len(upperBounds) - 1
181149
if math.IsInf(upperBounds[last], +1) {
182150
upperBounds = upperBounds[:last] // ignore +Inf bucket as it is covered anyways
@@ -189,15 +157,34 @@ func newPrometheusHistogram(upperBounds []float64) *PrometheusHistogram {
189157
return &h
190158
}
191159

192-
func validateBuckets(upperBounds []float64) {
160+
func mustValidateBuckets(upperBounds []float64) {
161+
if err := ValidateBuckets(upperBounds); err != nil {
162+
panic(err)
163+
}
164+
}
165+
166+
func ValidateBuckets(upperBounds []float64) error {
193167
if len(upperBounds) == 0 {
194-
panic("no upper bounds were given for the buckets")
168+
return fmt.Errorf("no upper bounds were given for the buckets")
195169
}
196170
for i := 0; i < len(upperBounds)-1; i++ {
197171
if upperBounds[i] >= upperBounds[i+1] {
198-
panic("upper bounds for the buckets must be strictly increasing")
172+
return fmt.Errorf("upper bounds for the buckets must be strictly increasing")
199173
}
200174
}
175+
return nil
176+
}
177+
178+
func LinearBuckets(start, width float64, count int) []float64 {
179+
if count < 1 {
180+
panic("LinearBuckets needs a positive count")
181+
}
182+
upperBounds := make([]float64, count)
183+
for i := range upperBounds {
184+
upperBounds[i] = start
185+
start += width
186+
}
187+
return upperBounds
201188
}
202189

203190
func (h *PrometheusHistogram) marshalTo(prefix string, w io.Writer) {

prometheus_histogram_test.go

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ prefix_count 405
4444
testMarshalTo(t, h, "prefix", expected)
4545

4646
// make sure that if the +Inf bucket is manually specified it gets ignored and we have the same resutls at the end
47-
h2 := NewPrometheusHistogramExt("TestPrometheusHistogram2", append(defaultUpperBounds, math.Inf(+1)))
47+
h2 := NewPrometheusHistogramExt("TestPrometheusHistogram2", append(PrometheusHistogramDefaultBuckets, math.Inf(+1)))
4848

4949
h.Reset()
5050

@@ -63,46 +63,41 @@ prefix_count 405
6363
testMarshalTo(t, h2, "prefix", expected)
6464
}
6565

66-
func TestPrometheusHistogramMerge(t *testing.T) {
67-
name := `TestPrometheusHistogramMerge`
68-
h := NewPrometheusHistogram(name)
69-
// Write data to histogram
70-
for i := 0; i <= 10_100; i += 25 { // from 0 to 10'100 ms in 25ms steps
71-
h.Update(float64(i) * 1e-3)
72-
}
66+
func TestPrometheusHistogramLinearBuckets(t *testing.T) {
67+
const expected string = `prefix_bucket{le="0.5"} 1
68+
prefix_bucket{le="1.5"} 2
69+
prefix_bucket{le="2.5"} 3
70+
prefix_bucket{le="3.5"} 4
71+
prefix_bucket{le="4.5"} 5
72+
prefix_bucket{le="5.5"} 6
73+
prefix_bucket{le="6.5"} 7
74+
prefix_bucket{le="7.5"} 8
75+
prefix_bucket{le="8.5"} 9
76+
prefix_bucket{le="9.5"} 10
77+
prefix_bucket{le="+Inf"} 11
78+
prefix_sum 55
79+
prefix_count 11
80+
`
81+
name := "TestPrometheusHistogramLinearBuckets"
82+
upperBounds := LinearBuckets(0.5, 1.0, 10)
83+
h := NewPrometheusHistogramExt(name, upperBounds)
7384

74-
b := NewPrometheusHistogram("test")
75-
for i := 0; i <= 10_100; i += 25 { // from 0 to 10'100 ms in 25ms steps
76-
h.Update(float64(i) * 1e-3)
85+
// Write data to histogram
86+
for i := 0; i <= 10; i++ { // from 0 to 10
87+
h.Update(float64(i))
7788
}
7889

79-
h.Merge(b)
80-
8190
// Make sure the histogram prints <prefix>_bucket on marshalTo call
82-
testMarshalTo(t, h, "prefix", `prefix_bucket{le="0.005"} 2
83-
prefix_bucket{le="0.01"} 2
84-
prefix_bucket{le="0.025"} 4
85-
prefix_bucket{le="0.05"} 6
86-
prefix_bucket{le="0.1"} 10
87-
prefix_bucket{le="0.25"} 22
88-
prefix_bucket{le="0.5"} 42
89-
prefix_bucket{le="1"} 82
90-
prefix_bucket{le="2.5"} 202
91-
prefix_bucket{le="5"} 402
92-
prefix_bucket{le="10"} 802
93-
prefix_bucket{le="+Inf"} 810
94-
prefix_sum 4090.5
95-
prefix_count 810
96-
`)
91+
testMarshalTo(t, h, "prefix", expected)
9792

93+
// Make sure we panic when the count of linear buckets is < 1
9894
func() {
9995
defer func() {
10096
if r := recover(); r == nil {
101-
t.Error("Merge did not panic with mimatched buckets.")
97+
t.Errorf("LinearBuckets should've panicked with a count of 0.")
10298
}
10399
}()
104-
h2 := NewPrometheusHistogramExt("TestPrometheusHistogramMerge2", []float64{14})
105-
h.Merge(h2)
100+
_ = LinearBuckets(.14, .22, 0)
106101
}()
107102
}
108103

set.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func (s *Set) GetOrCreateHistogram(name string) *Histogram {
140140
//
141141
// The returned histogram is safe to use from concurrent goroutines.
142142
func (s *Set) NewPrometheusHistogram(name string) *PrometheusHistogram {
143-
return s.NewPrometheusHistogramExt(name, defaultUpperBounds)
143+
return s.NewPrometheusHistogramExt(name, PrometheusHistogramDefaultBuckets)
144144
}
145145

146146

@@ -176,7 +176,7 @@ func (s *Set) NewPrometheusHistogramExt(name string, upperBounds []float64) *Pro
176176
//
177177
// Performance tip: prefer NewPrometheusHistogram instead of GetOrCreatePrometheusHistogram.
178178
func (s *Set) GetOrCreatePrometheusHistogram(name string) *PrometheusHistogram {
179-
return s.GetOrCreatePrometheusHistogramExt(name, defaultUpperBounds)
179+
return s.GetOrCreatePrometheusHistogramExt(name, PrometheusHistogramDefaultBuckets)
180180
}
181181

182182
// GetOrCreatePrometheusHistogramExt returns registered prometheus histogram in

0 commit comments

Comments
 (0)