diff options
Diffstat (limited to 'vendor/github.com/facebookgo/stats')
-rw-r--r-- | vendor/github.com/facebookgo/stats/aggregation.go | 35 | ||||
-rw-r--r-- | vendor/github.com/facebookgo/stats/counter.go | 112 | ||||
-rw-r--r-- | vendor/github.com/facebookgo/stats/license | 30 | ||||
-rw-r--r-- | vendor/github.com/facebookgo/stats/stats.go | 166 | ||||
-rw-r--r-- | vendor/github.com/facebookgo/stats/stopper.go | 17 |
5 files changed, 360 insertions, 0 deletions
diff --git a/vendor/github.com/facebookgo/stats/aggregation.go b/vendor/github.com/facebookgo/stats/aggregation.go new file mode 100644 index 00000000..8f57fb7f --- /dev/null +++ b/vendor/github.com/facebookgo/stats/aggregation.go @@ -0,0 +1,35 @@ +package stats + +import "sort" + +// Average returns the average value +func Average(values []float64) float64 { + if len(values) == 0 { + return 0 + } + + var val float64 + for _, point := range values { + val += point + } + return val / float64(len(values)) +} + +// Sum returns the sum of all the given values +func Sum(values []float64) float64 { + var val float64 + for _, point := range values { + val += point + } + return val +} + +// Percentiles returns a map containing the asked for percentiles +func Percentiles(values []float64, percentiles map[string]float64) map[string]float64 { + sort.Float64s(values) + results := map[string]float64{} + for label, p := range percentiles { + results[label] = values[int(float64(len(values))*p)] + } + return results +} diff --git a/vendor/github.com/facebookgo/stats/counter.go b/vendor/github.com/facebookgo/stats/counter.go new file mode 100644 index 00000000..59a0ed1e --- /dev/null +++ b/vendor/github.com/facebookgo/stats/counter.go @@ -0,0 +1,112 @@ +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") +} diff --git a/vendor/github.com/facebookgo/stats/license b/vendor/github.com/facebookgo/stats/license new file mode 100644 index 00000000..feae8707 --- /dev/null +++ b/vendor/github.com/facebookgo/stats/license @@ -0,0 +1,30 @@ +BSD License + +For stats software + +Copyright (c) 2015, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/facebookgo/stats/stats.go b/vendor/github.com/facebookgo/stats/stats.go new file mode 100644 index 00000000..b833506a --- /dev/null +++ b/vendor/github.com/facebookgo/stats/stats.go @@ -0,0 +1,166 @@ +// Package stats defines a lightweight interface for collecting statistics. It +// doesn't provide an implementation, just the shared interface. +package stats + +// Client provides methods to collection statistics. +type Client interface { + // BumpAvg bumps the average for the given key. + BumpAvg(key string, val float64) + + // BumpSum bumps the sum for the given key. + BumpSum(key string, val float64) + + // BumpHistogram bumps the histogram for the given key. + BumpHistogram(key string, val float64) + + // BumpTime is a special version of BumpHistogram which is specialized for + // timers. Calling it starts the timer, and it returns a value on which End() + // can be called to indicate finishing the timer. A convenient way of + // recording the duration of a function is calling it like such at the top of + // the function: + // + // defer s.BumpTime("my.function").End() + BumpTime(key string) interface { + End() + } +} + +// PrefixClient adds multiple keys for the same value, with each prefix +// added to the key and calls the underlying client. +func PrefixClient(prefixes []string, client Client) Client { + return &prefixClient{ + Prefixes: prefixes, + Client: client, + } +} + +type prefixClient struct { + Prefixes []string + Client Client +} + +func (p *prefixClient) BumpAvg(key string, val float64) { + for _, prefix := range p.Prefixes { + p.Client.BumpAvg(prefix+key, val) + } +} + +func (p *prefixClient) BumpSum(key string, val float64) { + for _, prefix := range p.Prefixes { + p.Client.BumpSum(prefix+key, val) + } +} + +func (p *prefixClient) BumpHistogram(key string, val float64) { + for _, prefix := range p.Prefixes { + p.Client.BumpHistogram(prefix+key, val) + } +} + +func (p *prefixClient) BumpTime(key string) interface { + End() +} { + var m multiEnder + for _, prefix := range p.Prefixes { + m = append(m, p.Client.BumpTime(prefix+key)) + } + return m +} + +// multiEnder combines many enders together. +type multiEnder []interface { + End() +} + +func (m multiEnder) End() { + for _, e := range m { + e.End() + } +} + +// HookClient is useful for testing. It provides optional hooks for each +// expected method in the interface, which if provided will be called. If a +// hook is not provided, it will be ignored. +type HookClient struct { + BumpAvgHook func(key string, val float64) + BumpSumHook func(key string, val float64) + BumpHistogramHook func(key string, val float64) + BumpTimeHook func(key string) interface { + End() + } +} + +// BumpAvg will call BumpAvgHook if defined. +func (c *HookClient) BumpAvg(key string, val float64) { + if c.BumpAvgHook != nil { + c.BumpAvgHook(key, val) + } +} + +// BumpSum will call BumpSumHook if defined. +func (c *HookClient) BumpSum(key string, val float64) { + if c.BumpSumHook != nil { + c.BumpSumHook(key, val) + } +} + +// BumpHistogram will call BumpHistogramHook if defined. +func (c *HookClient) BumpHistogram(key string, val float64) { + if c.BumpHistogramHook != nil { + c.BumpHistogramHook(key, val) + } +} + +// BumpTime will call BumpTimeHook if defined. +func (c *HookClient) BumpTime(key string) interface { + End() +} { + if c.BumpTimeHook != nil { + return c.BumpTimeHook(key) + } + return NoOpEnd +} + +type noOpEnd struct{} + +func (n noOpEnd) End() {} + +// NoOpEnd provides a dummy value for use in tests as valid return value for +// BumpTime(). +var NoOpEnd = noOpEnd{} + +// BumpAvg calls BumpAvg on the Client if it isn't nil. This is useful when a +// component has an optional stats.Client. +func BumpAvg(c Client, key string, val float64) { + if c != nil { + c.BumpAvg(key, val) + } +} + +// BumpSum calls BumpSum on the Client if it isn't nil. This is useful when a +// component has an optional stats.Client. +func BumpSum(c Client, key string, val float64) { + if c != nil { + c.BumpSum(key, val) + } +} + +// BumpHistogram calls BumpHistogram on the Client if it isn't nil. This is +// useful when a component has an optional stats.Client. +func BumpHistogram(c Client, key string, val float64) { + if c != nil { + c.BumpHistogram(key, val) + } +} + +// BumpTime calls BumpTime on the Client if it isn't nil. If the Client is nil +// it still returns a valid return value which will be a no-op. This is useful +// when a component has an optional stats.Client. +func BumpTime(c Client, key string) interface { + End() +} { + if c != nil { + return c.BumpTime(key) + } + return NoOpEnd +} diff --git a/vendor/github.com/facebookgo/stats/stopper.go b/vendor/github.com/facebookgo/stats/stopper.go new file mode 100644 index 00000000..38e8eab8 --- /dev/null +++ b/vendor/github.com/facebookgo/stats/stopper.go @@ -0,0 +1,17 @@ +package stats + +import "time" + +// Stopper calls Client.BumpSum and Client.BumpHistogram when End'ed +type Stopper struct { + Key string + Start time.Time + Client Client +} + +// End the Stopper +func (s *Stopper) End() { + since := time.Since(s.Start).Seconds() * 1000.0 + s.Client.BumpSum(s.Key+".total", since) + s.Client.BumpHistogram(s.Key, since) +} |