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 <seth.bunce@getcruise.com>
This commit is contained in:
parent
20eef74042
commit
2261d5cda1
|
@ -116,6 +116,34 @@ func ExponentialBuckets(start, factor float64, count int) []float64 {
|
||||||
return buckets
|
return buckets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExponentialBucketsRange creates 'count' buckets, where the lowest bucket is
|
||||||
|
// 'min' and the highest bucket is 'max'. The final +Inf bucket is not counted
|
||||||
|
// and not included in the returned slice. The returned slice is meant to be
|
||||||
|
// used for the Buckets field of HistogramOpts.
|
||||||
|
//
|
||||||
|
// The function panics if 'count' is 0 or negative, if 'min' is 0 or negative.
|
||||||
|
func ExponentialBucketsRange(min, max float64, count int) []float64 {
|
||||||
|
if count < 1 {
|
||||||
|
panic("ExponentialBucketsRange count needs a positive count")
|
||||||
|
}
|
||||||
|
if min <= 0 {
|
||||||
|
panic("ExponentialBucketsRange min needs to be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formula for exponential buckets.
|
||||||
|
// max = min*growthFactor^(bucketCount-1)
|
||||||
|
|
||||||
|
// We know max/min and highest bucket. Solve for growthFactor.
|
||||||
|
growthFactor := math.Pow(max/min, 1.0/float64(count-1))
|
||||||
|
|
||||||
|
// Now that we know growthFactor, solve for each bucket.
|
||||||
|
buckets := make([]float64, count)
|
||||||
|
for i := 1; i <= count; i++ {
|
||||||
|
buckets[i-1] = min * math.Pow(growthFactor, float64(i-1))
|
||||||
|
}
|
||||||
|
return buckets
|
||||||
|
}
|
||||||
|
|
||||||
// HistogramOpts bundles the options for creating a Histogram metric. It is
|
// HistogramOpts bundles the options for creating a Histogram metric. It is
|
||||||
// mandatory to set Name to a non-empty string. All other fields are optional
|
// mandatory to set Name to a non-empty string. All other fields are optional
|
||||||
// and can safely be left at their zero value, although it is strongly
|
// and can safely be left at their zero value, although it is strongly
|
||||||
|
|
|
@ -352,6 +352,16 @@ func TestBuckets(t *testing.T) {
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Errorf("exponential buckets: got %v, want %v", got, want)
|
t.Errorf("exponential buckets: got %v, want %v", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
got = ExponentialBucketsRange(1, 100, 10)
|
||||||
|
want = []float64{1.0, 1.6681005372000588, 2.782559402207125,
|
||||||
|
4.641588833612779, 7.742636826811273, 12.915496650148842,
|
||||||
|
21.544346900318846, 35.93813663804629, 59.94842503189414,
|
||||||
|
100.00000000000007,
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("exponential buckets range: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHistogramAtomicObserve(t *testing.T) {
|
func TestHistogramAtomicObserve(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue