client_golang/prometheus/statistics.go

127 lines
2.6 KiB
Go

// Copyright (c) 2013, Prometheus Team
// All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package prometheus
import (
"math"
"sort"
)
// TODO(mtp): Split this out into a summary statistics file once moving/rolling
// averages are calculated.
// ReductionMethod provides a method for reducing metrics into a scalar value.
type ReductionMethod func([]float64) float64
var (
medianReducer = NearestRankReducer(50)
)
// These are the canned ReductionMethods.
var (
// Reduce to the average of the set.
AverageReducer = averageReducer
// Extract the first modal value.
FirstModeReducer = firstModeReducer
// Reduce to the maximum of the set.
MaximumReducer = maximumReducer
// Reduce to the median of the set.
MedianReducer = medianReducer
// Reduce to the minimum of the set.
MinimumReducer = minimumReducer
)
func averageReducer(input []float64) float64 {
count := 0.0
sum := 0.0
for _, v := range input {
sum += v
count++
}
if count == 0 {
return math.NaN()
}
return sum / count
}
func firstModeReducer(input []float64) float64 {
valuesToFrequency := map[float64]int64{}
largestTally := int64(math.MinInt64)
largestTallyValue := math.NaN()
for _, v := range input {
presentCount, _ := valuesToFrequency[v]
presentCount++
valuesToFrequency[v] = presentCount
if presentCount > largestTally {
largestTally = presentCount
largestTallyValue = v
}
}
return largestTallyValue
}
// Calculate the percentile by choosing the nearest neighboring value.
func nearestRank(input []float64, percentile float64) float64 {
inputSize := len(input)
if inputSize == 0 {
return math.NaN()
}
ordinalRank := math.Ceil(((percentile / 100.0) * float64(inputSize)) + 0.5)
copiedInput := make([]float64, inputSize)
copy(copiedInput, input)
sort.Float64s(copiedInput)
preliminaryIndex := int(ordinalRank) - 1
if preliminaryIndex == inputSize {
return copiedInput[preliminaryIndex-1]
}
return copiedInput[preliminaryIndex]
}
// Generate a ReductionMethod based off of extracting a given percentile value.
func NearestRankReducer(percentile float64) ReductionMethod {
return func(input []float64) float64 {
return nearestRank(input, percentile)
}
}
func minimumReducer(input []float64) float64 {
minimum := math.MaxFloat64
for _, v := range input {
minimum = math.Min(minimum, v)
}
return minimum
}
func maximumReducer(input []float64) float64 {
maximum := math.SmallestNonzeroFloat64
for _, v := range input {
maximum = math.Max(maximum, v)
}
return maximum
}