Skip to content

Commit 2261d5c

Browse files
authored
add ExponentialBucketsRange function (#899)
This function calculates exponential buckets with different arguments than the existing ExponentialBuckets function. Instead of specifying the start and factor, the user can specify the min and max bucket value. We have been doing it this way internally at my company for some time. Signed-off-by: Seth Bunce <[email protected]>
1 parent 20eef74 commit 2261d5c

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

prometheus/histogram.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,34 @@ func ExponentialBuckets(start, factor float64, count int) []float64 {
116116
return buckets
117117
}
118118

119+
// ExponentialBucketsRange creates 'count' buckets, where the lowest bucket is
120+
// 'min' and the highest bucket is 'max'. The final +Inf bucket is not counted
121+
// and not included in the returned slice. The returned slice is meant to be
122+
// used for the Buckets field of HistogramOpts.
123+
//
124+
// The function panics if 'count' is 0 or negative, if 'min' is 0 or negative.
125+
func ExponentialBucketsRange(min, max float64, count int) []float64 {
126+
if count < 1 {
127+
panic("ExponentialBucketsRange count needs a positive count")
128+
}
129+
if min <= 0 {
130+
panic("ExponentialBucketsRange min needs to be greater than 0")
131+
}
132+
133+
// Formula for exponential buckets.
134+
// max = min*growthFactor^(bucketCount-1)
135+
136+
// We know max/min and highest bucket. Solve for growthFactor.
137+
growthFactor := math.Pow(max/min, 1.0/float64(count-1))
138+
139+
// Now that we know growthFactor, solve for each bucket.
140+
buckets := make([]float64, count)
141+
for i := 1; i <= count; i++ {
142+
buckets[i-1] = min * math.Pow(growthFactor, float64(i-1))
143+
}
144+
return buckets
145+
}
146+
119147
// HistogramOpts bundles the options for creating a Histogram metric. It is
120148
// mandatory to set Name to a non-empty string. All other fields are optional
121149
// and can safely be left at their zero value, although it is strongly

prometheus/histogram_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,16 @@ func TestBuckets(t *testing.T) {
352352
if !reflect.DeepEqual(got, want) {
353353
t.Errorf("exponential buckets: got %v, want %v", got, want)
354354
}
355+
356+
got = ExponentialBucketsRange(1, 100, 10)
357+
want = []float64{1.0, 1.6681005372000588, 2.782559402207125,
358+
4.641588833612779, 7.742636826811273, 12.915496650148842,
359+
21.544346900318846, 35.93813663804629, 59.94842503189414,
360+
100.00000000000007,
361+
}
362+
if !reflect.DeepEqual(got, want) {
363+
t.Errorf("exponential buckets range: got %v, want %v", got, want)
364+
}
355365
}
356366

357367
func TestHistogramAtomicObserve(t *testing.T) {

0 commit comments

Comments
 (0)