Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
2.7 KiB
112 lines
2.7 KiB
package stats |
|
|
|
import "fmt" |
|
|
|
// Type is the type of aggregation of apply |
|
type Type int |
|
|
|
const ( |
|
AggregateAvg Type = iota |
|
AggregateSum |
|
AggregateHistogram |
|
) |
|
|
|
var ( |
|
// HistogramPercentiles is used to determine which percentiles to return for |
|
// SimpleCounter.Aggregate |
|
HistogramPercentiles = map[string]float64{ |
|
"p50": 0.5, |
|
"p95": 0.95, |
|
"p99": 0.99, |
|
} |
|
|
|
// MinSamplesForPercentiles is used by SimpleCounter.Aggregate to determine |
|
// what the minimum number of samples is required for percentile analysis |
|
MinSamplesForPercentiles = 10 |
|
) |
|
|
|
// Aggregates can be used to merge counters together. This is not goroutine safe |
|
type Aggregates map[string]Counter |
|
|
|
// Add adds the counter for aggregation. This is not goroutine safe |
|
func (a Aggregates) Add(c Counter) error { |
|
key := c.FullKey() |
|
if counter, ok := a[key]; ok { |
|
if counter.GetType() != c.GetType() { |
|
return fmt.Errorf("stats: mismatched aggregation type for: %s", key) |
|
} |
|
counter.AddValues(c.GetValues()...) |
|
} else { |
|
a[key] = c |
|
} |
|
return nil |
|
} |
|
|
|
// Counter is the interface used by Aggregates to merge counters together |
|
type Counter interface { |
|
// FullKey is used to uniquely identify the counter |
|
FullKey() string |
|
|
|
// AddValues adds values for aggregation |
|
AddValues(...float64) |
|
|
|
// GetValues returns the values for aggregation |
|
GetValues() []float64 |
|
|
|
// GetType returns the type of aggregation to apply |
|
GetType() Type |
|
} |
|
|
|
// SimpleCounter is a basic implementation of the Counter interface |
|
type SimpleCounter struct { |
|
Key string |
|
Values []float64 |
|
Type Type |
|
} |
|
|
|
// FullKey is part of the Counter interace |
|
func (s *SimpleCounter) FullKey() string { |
|
return s.Key |
|
} |
|
|
|
// GetValues is part of the Counter interface |
|
func (s *SimpleCounter) GetValues() []float64 { |
|
return s.Values |
|
} |
|
|
|
// AddValues is part of the Counter interface |
|
func (s *SimpleCounter) AddValues(vs ...float64) { |
|
s.Values = append(s.Values, vs...) |
|
} |
|
|
|
// GetType is part of the Counter interface |
|
func (s *SimpleCounter) GetType() Type { |
|
return s.Type |
|
} |
|
|
|
// Aggregate aggregates the provided values appropriately, returning a map |
|
// from key to value. If AggregateHistogram is specified, the map will contain |
|
// the relevant percentiles as specified by HistogramPercentiles |
|
func (s *SimpleCounter) Aggregate() map[string]float64 { |
|
switch s.Type { |
|
case AggregateAvg: |
|
return map[string]float64{ |
|
s.Key: Average(s.Values), |
|
} |
|
case AggregateSum: |
|
return map[string]float64{ |
|
s.Key: Sum(s.Values), |
|
} |
|
case AggregateHistogram: |
|
histogram := map[string]float64{ |
|
s.Key: Average(s.Values), |
|
} |
|
if len(s.Values) > MinSamplesForPercentiles { |
|
for k, v := range Percentiles(s.Values, HistogramPercentiles) { |
|
histogram[fmt.Sprintf("%s.%s", s.Key, k)] = v |
|
} |
|
} |
|
return histogram |
|
} |
|
panic("stats: unsupported aggregation type") |
|
}
|
|
|