metrics: updates per feedback

This commit is contained in:
Kiel barry 2018-05-21 12:07:56 -07:00
parent f6bc65fc68
commit 6eefd0b58c
21 changed files with 77 additions and 67 deletions

View file

@ -2,7 +2,7 @@ package metrics
import "sync/atomic" import "sync/atomic"
// Counters hold an int64 value that can be incremented and decremented. // Counter holds an int64 value that can be incremented and decremented.
type Counter interface { type Counter interface {
Clear() Clear()
Count() int64 Count() int64

View file

@ -19,17 +19,18 @@ var (
gcStats debug.GCStats gcStats debug.GCStats
) )
// Capture new values for the Go garbage collector statistics exported in // CaptureDebugGCStats captures new values for the Go garbage collector statistics
// debug.GCStats. This is designed to be called as a goroutine. // exported in debug.GCStats. This is designed to be called as a goroutine.
func CaptureDebugGCStats(r Registry, d time.Duration) { func CaptureDebugGCStats(r Registry, d time.Duration) {
for range time.Tick(d) { for range time.Tick(d) {
CaptureDebugGCStatsOnce(r) CaptureDebugGCStatsOnce(r)
} }
} }
// Capture new values for the Go garbage collector statistics exported in // CaptureDebugGCStatsOnce captures new values for the Go garbage collector
// debug.GCStats. This is designed to be called in a background goroutine. // statistics exported in debug.GCStats. This is designed to be called in a
// Giving a registry which has not been given to RegisterDebugGCStats will // background goroutine.Giving a registry which has not been given to
// RegisterDebugGCStats will
// panic. // panic.
// //
// Be careful (but much less so) with this because debug.ReadGCStats calls // Be careful (but much less so) with this because debug.ReadGCStats calls
@ -50,8 +51,8 @@ func CaptureDebugGCStatsOnce(r Registry) {
debugMetrics.GCStats.PauseTotal.Update(int64(gcStats.PauseTotal)) debugMetrics.GCStats.PauseTotal.Update(int64(gcStats.PauseTotal))
} }
// Register metrics for the Go garbage collector statistics exported in // RegisterDebugGCStats registers metrics for the Go garbage collector statistics
// debug.GCStats. The metrics are named by their fully-qualified Go symbols, // exported in debug.GCStats. The metrics are named by their fully-qualified Go symbols,
// i.e. debug.GCStats.PauseTotal. // i.e. debug.GCStats.PauseTotal.
func RegisterDebugGCStats(r Registry) { func RegisterDebugGCStats(r Registry) {
debugMetrics.GCStats.LastGC = NewGauge() debugMetrics.GCStats.LastGC = NewGauge()

View file

@ -6,7 +6,7 @@ import (
"sync/atomic" "sync/atomic"
) )
// EWMAs continuously calculate an exponentially-weighted moving average // EWMA continuously calculates an exponentially-weighted moving average
// based on an outside source of clock ticks. // based on an outside source of clock ticks.
type EWMA interface { type EWMA interface {
Rate() float64 Rate() float64

View file

@ -1,5 +1,7 @@
// Hook go-metrics into expvar // Package exp hooks go-metrics into expvar.
// on any /debug/metrics request, load all vars from the registry into expvar, and execute regular expvar handler //
// On any /debug/metrics request, loads all vars from the registry into expvar,
// and executes regular expvar handler.
package exp package exp
import ( import (

View file

@ -2,7 +2,7 @@ package metrics
import "sync/atomic" import "sync/atomic"
// Gauges hold an int64 value that can be set arbitrarily. // Gauge holds an int64 value that can be set arbitrarily.
type Gauge interface { type Gauge interface {
Snapshot() Gauge Snapshot() Gauge
Update(int64) Update(int64)

View file

@ -2,7 +2,7 @@ package metrics
import "sync" import "sync"
// GaugeFloat64s hold a float64 value that can be set arbitrarily. // GaugeFloat64 holds a float64 value that can be set arbitrarily.
type GaugeFloat64 interface { type GaugeFloat64 interface {
Snapshot() GaugeFloat64 Snapshot() GaugeFloat64
Update(float64) Update(float64)
@ -38,7 +38,7 @@ func NewRegisteredGaugeFloat64(name string, r Registry) GaugeFloat64 {
return c return c
} }
// NewFunctionalGauge constructs a new FunctionalGauge. // NewFunctionalGaugeFloat64 constructs a new FunctionalGauge.
func NewFunctionalGaugeFloat64(f func() float64) GaugeFloat64 { func NewFunctionalGaugeFloat64(f func() float64) GaugeFloat64 {
if !Enabled { if !Enabled {
return NilGaugeFloat64{} return NilGaugeFloat64{}
@ -46,7 +46,7 @@ func NewFunctionalGaugeFloat64(f func() float64) GaugeFloat64 {
return &FunctionalGaugeFloat64{value: f} return &FunctionalGaugeFloat64{value: f}
} }
// NewRegisteredFunctionalGauge constructs and registers a new StandardGauge. // NewRegisteredFunctionalGaugeFloat64 constructs and registers a new StandardGauge.
func NewRegisteredFunctionalGaugeFloat64(name string, r Registry, f func() float64) GaugeFloat64 { func NewRegisteredFunctionalGaugeFloat64(name string, r Registry, f func() float64) GaugeFloat64 {
c := NewFunctionalGaugeFloat64(f) c := NewFunctionalGaugeFloat64(f)
if nil == r { if nil == r {
@ -70,7 +70,7 @@ func (GaugeFloat64Snapshot) Update(float64) {
// Value returns the value at the time the snapshot was taken. // Value returns the value at the time the snapshot was taken.
func (g GaugeFloat64Snapshot) Value() float64 { return float64(g) } func (g GaugeFloat64Snapshot) Value() float64 { return float64(g) }
// NilGauge is a no-op Gauge. // NilGaugeFloat64 is a no-op Gauge.
type NilGaugeFloat64 struct{} type NilGaugeFloat64 struct{}
// Snapshot is a no-op. // Snapshot is a no-op.

View file

@ -1,6 +1,6 @@
package metrics package metrics
// Healthchecks hold an error value describing an arbitrary up/down status. // Healthcheck holds an error value describing an arbitrary up/down status.
type Healthcheck interface { type Healthcheck interface {
Check() Check()
Error() error Error() error

View file

@ -1,6 +1,6 @@
package metrics package metrics
// Histograms calculate distribution statistics from a series of int64 values. // Histogram calculates distribution statistics from a series of int64 values.
type Histogram interface { type Histogram interface {
Clear() Clear()
Count() int64 Count() int64

View file

@ -26,6 +26,8 @@ func WriteJSONOnce(r Registry, w io.Writer) {
json.NewEncoder(w).Encode(r) json.NewEncoder(w).Encode(r)
} }
// MarshalJSON returns a byte slice containing a JSON representation of all
// the metrics in the Registry.
func (p *PrefixedRegistry) MarshalJSON() ([]byte, error) { func (p *PrefixedRegistry) MarshalJSON() ([]byte, error) {
return json.Marshal(p.GetAll()) return json.Marshal(p.GetAll())
} }

View file

@ -11,6 +11,7 @@ import (
const Operations = "operations" const Operations = "operations"
const OperationsShort = "ops" const OperationsShort = "ops"
// LibratoClient holds an email and a token.
type LibratoClient struct { type LibratoClient struct {
Email, Token string Email, Token string
} }
@ -52,7 +53,7 @@ const (
Counters = "counters" Counters = "counters"
Gauges = "gauges" Gauges = "gauges"
MetricsPostUrl = "https://metrics-api.librato.com/v1/metrics" MetricsPostURL = "https://metrics-api.librato.com/v1/metrics"
) )
type Measurement map[string]interface{} type Measurement map[string]interface{}
@ -80,7 +81,7 @@ func (c *LibratoClient) PostMetrics(batch Batch) (err error) {
return return
} }
if req, err = http.NewRequest("POST", MetricsPostUrl, bytes.NewBuffer(js)); err != nil { if req, err = http.NewRequest("POST", MetricsPostURL, bytes.NewBuffer(js)); err != nil {
return return
} }

View file

@ -43,7 +43,7 @@ func Librato(r metrics.Registry, d time.Duration, e string, t string, s string,
func (rep *Reporter) Run() { func (rep *Reporter) Run() {
log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015") log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015")
ticker := time.Tick(rep.Interval) ticker := time.Tick(rep.Interval)
metricsApi := &LibratoClient{rep.Email, rep.Token} metricsAPI := &LibratoClient{rep.Email, rep.Token}
for now := range ticker { for now := range ticker {
var metrics Batch var metrics Batch
var err error var err error
@ -51,7 +51,7 @@ func (rep *Reporter) Run() {
log.Printf("ERROR constructing librato request body %s", err) log.Printf("ERROR constructing librato request body %s", err)
continue continue
} }
if err := metricsApi.PostMetrics(metrics); err != nil { if err := metricsAPI.PostMetrics(metrics); err != nil {
log.Printf("ERROR sending metrics to librato %s", err) log.Printf("ERROR sending metrics to librato %s", err)
continue continue
} }

View file

@ -4,15 +4,18 @@ import (
"time" "time"
) )
// Logger will print any number of passed arguments of type interface.
type Logger interface { type Logger interface {
Printf(format string, v ...interface{}) Printf(format string, v ...interface{})
} }
// Log outputs each metric in the given registry periodically using the given
// logger and current time in nanos.
func Log(r Registry, freq time.Duration, l Logger) { func Log(r Registry, freq time.Duration, l Logger) {
LogScaled(r, freq, time.Nanosecond, l) LogScaled(r, freq, time.Nanosecond, l)
} }
// Output each metric in the given registry periodically using the given // LogScaled outputs each metric in the given registry periodically using the given
// logger. Print timings in `scale` units (eg time.Millisecond) rather than nanos. // logger. Print timings in `scale` units (eg time.Millisecond) rather than nanos.
func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) {
du := float64(scale) du := float64(scale)

View file

@ -5,7 +5,7 @@ import (
"time" "time"
) )
// Meters count events to produce exponentially-weighted moving average rates // Meter counts events to produce exponentially-weighted moving average rates
// at one-, five-, and fifteen-minutes and a mean rate. // at one-, five-, and fifteen-minutes and a mean rate.
type Meter interface { type Meter interface {
Count() int64 Count() int64
@ -46,7 +46,7 @@ func NewMeter() Meter {
return m return m
} }
// NewMeter constructs and registers a new StandardMeter and launches a // NewRegisteredMeter constructs and registers a new StandardMeter and launches a
// goroutine. // goroutine.
// Be sure to unregister the meter from the registry once it is of no use to // Be sure to unregister the meter from the registry once it is of no use to
// allow for garbage collection. // allow for garbage collection.
@ -110,7 +110,7 @@ func (NilMeter) Rate1() float64 { return 0.0 }
// Rate5 is a no-op. // Rate5 is a no-op.
func (NilMeter) Rate5() float64 { return 0.0 } func (NilMeter) Rate5() float64 { return 0.0 }
// Rate15is a no-op. // Rate15 is a no-op.
func (NilMeter) Rate15() float64 { return 0.0 } func (NilMeter) Rate15() float64 { return 0.0 }
// RateMean is a no-op. // RateMean is a no-op.

View file

@ -2,7 +2,7 @@
// //
// <https://github.com/rcrowley/go-metrics> // <https://github.com/rcrowley/go-metrics>
// //
// Coda Hale's original work: <https://github.com/codahale/metrics> // Package metrics is a go port of Coda Hale's original work: <https://github.com/codahale/metrics>
package metrics package metrics
import ( import (
@ -19,7 +19,7 @@ import (
// //
// This global kill-switch helps quantify the observer effect and makes // This global kill-switch helps quantify the observer effect and makes
// for less cluttered pprof profiles. // for less cluttered pprof profiles.
var Enabled bool = false var Enabled = false
// MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. // MetricsEnabledFlag is the CLI flag name to use to enable metrics collections.
const MetricsEnabledFlag = "metrics" const MetricsEnabledFlag = "metrics"

View file

@ -10,7 +10,7 @@ import (
"time" "time"
) )
var shortHostName string = "" var shortHostName string
// OpenTSDBConfig provides a container with configuration parameters for // OpenTSDBConfig provides a container with configuration parameters for
// the OpenTSDB exporter // the OpenTSDB exporter

View file

@ -50,33 +50,32 @@ type Registry interface {
UnregisterAll() UnregisterAll()
} }
// The standard implementation of a Registry is a mutex-protected map // StandardRegistry is a mutex protected implementation of a Registry.
// of names to metrics.
type StandardRegistry struct { type StandardRegistry struct {
metrics map[string]interface{} metrics map[string]interface{}
mutex sync.Mutex mutex sync.Mutex
} }
// Create a new registry. // NewRegistry creates a new registry.
func NewRegistry() Registry { func NewRegistry() Registry {
return &StandardRegistry{metrics: make(map[string]interface{})} return &StandardRegistry{metrics: make(map[string]interface{})}
} }
// Call the given function for each registered metric. // Each calls the given function for each registered metric.
func (r *StandardRegistry) Each(f func(string, interface{})) { func (r *StandardRegistry) Each(f func(string, interface{})) {
for name, i := range r.registered() { for name, i := range r.registered() {
f(name, i) f(name, i)
} }
} }
// Get the metric by the given name or nil if none is registered. // Get gets the metric by the given name or nil if none is registered.
func (r *StandardRegistry) Get(name string) interface{} { func (r *StandardRegistry) Get(name string) interface{} {
r.mutex.Lock() r.mutex.Lock()
defer r.mutex.Unlock() defer r.mutex.Unlock()
return r.metrics[name] return r.metrics[name]
} }
// Gets an existing metric or creates and registers a new one. Threadsafe // GetOrRegister gets an existing metric or creates and registers a new one. Threadsafe
// alternative to calling Get and Register on failure. // alternative to calling Get and Register on failure.
// The interface can be the metric to register if not found in registry, // The interface can be the metric to register if not found in registry,
// or a function returning the metric for lazy instantiation. // or a function returning the metric for lazy instantiation.
@ -101,7 +100,7 @@ func (r *StandardRegistry) Register(name string, i interface{}) error {
return r.register(name, i) return r.register(name, i)
} }
// Run all registered healthchecks. // RunHealthchecks runs all registered healthchecks.
func (r *StandardRegistry) RunHealthchecks() { func (r *StandardRegistry) RunHealthchecks() {
r.mutex.Lock() r.mutex.Lock()
defer r.mutex.Unlock() defer r.mutex.Unlock()
@ -181,7 +180,7 @@ func (r *StandardRegistry) Unregister(name string) {
delete(r.metrics, name) delete(r.metrics, name)
} }
// Unregister all metrics. (Mostly for testing.) // UnregisterAll unregisters all metrics. Mostly for testing.
func (r *StandardRegistry) UnregisterAll() { func (r *StandardRegistry) UnregisterAll() {
r.mutex.Lock() r.mutex.Lock()
defer r.mutex.Unlock() defer r.mutex.Unlock()
@ -244,7 +243,7 @@ func NewPrefixedChildRegistry(parent Registry, prefix string) Registry {
} }
} }
// Call the given function for each registered metric. // Each calls the given function for each registered metric.
func (r *PrefixedRegistry) Each(fn func(string, interface{})) { func (r *PrefixedRegistry) Each(fn func(string, interface{})) {
wrappedFn := func(prefix string) func(string, interface{}) { wrappedFn := func(prefix string) func(string, interface{}) {
return func(name string, iface interface{}) { return func(name string, iface interface{}) {
@ -276,7 +275,7 @@ func (r *PrefixedRegistry) Get(name string) interface{} {
return r.underlying.Get(realName) return r.underlying.Get(realName)
} }
// Gets an existing metric or registers the given one. // GetOrRegister gets an existing metric or registers the given one.
// The interface can be the metric to register if not found in registry, // The interface can be the metric to register if not found in registry,
// or a function returning the metric for lazy instantiation. // or a function returning the metric for lazy instantiation.
func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} { func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} {
@ -290,7 +289,7 @@ func (r *PrefixedRegistry) Register(name string, metric interface{}) error {
return r.underlying.Register(realName, metric) return r.underlying.Register(realName, metric)
} }
// Run all registered healthchecks. // RunHealthchecks runs all registered healthchecks.
func (r *PrefixedRegistry) RunHealthchecks() { func (r *PrefixedRegistry) RunHealthchecks() {
r.underlying.RunHealthchecks() r.underlying.RunHealthchecks()
} }
@ -306,14 +305,14 @@ func (r *PrefixedRegistry) Unregister(name string) {
r.underlying.Unregister(realName) r.underlying.Unregister(realName)
} }
// Unregister all metrics. (Mostly for testing.) // UnregisterAll unregisters all metrics. Mostly for testing.
func (r *PrefixedRegistry) UnregisterAll() { func (r *PrefixedRegistry) UnregisterAll() {
r.underlying.UnregisterAll() r.underlying.UnregisterAll()
} }
var DefaultRegistry Registry = NewRegistry() var DefaultRegistry = NewRegistry()
// Call the given function for each registered metric. // Each calls the given function for each registered metric.
func Each(f func(string, interface{})) { func Each(f func(string, interface{})) {
DefaultRegistry.Each(f) DefaultRegistry.Each(f)
} }
@ -323,7 +322,7 @@ func Get(name string) interface{} {
return DefaultRegistry.Get(name) return DefaultRegistry.Get(name)
} }
// Gets an existing metric or creates and registers a new one. Threadsafe // GetOrRegister gets an existing metric or creates and registers a new one. Threadsafe
// alternative to calling Get and Register on failure. // alternative to calling Get and Register on failure.
func GetOrRegister(name string, i interface{}) interface{} { func GetOrRegister(name string, i interface{}) interface{} {
return DefaultRegistry.GetOrRegister(name, i) return DefaultRegistry.GetOrRegister(name, i)
@ -335,7 +334,7 @@ func Register(name string, i interface{}) error {
return DefaultRegistry.Register(name, i) return DefaultRegistry.Register(name, i)
} }
// Register the given metric under the given name. Panics if a metric by the // MustRegister registers the given metric under the given name. Panics if a metric by the
// given name is already registered. // given name is already registered.
func MustRegister(name string, i interface{}) { func MustRegister(name string, i interface{}) {
if err := Register(name, i); err != nil { if err := Register(name, i); err != nil {
@ -343,7 +342,7 @@ func MustRegister(name string, i interface{}) {
} }
} }
// Run all registered healthchecks. // RunHealthchecks runs all registered healthchecks.
func RunHealthchecks() { func RunHealthchecks() {
DefaultRegistry.RunHealthchecks() DefaultRegistry.RunHealthchecks()
} }

View file

@ -7,7 +7,8 @@ import (
"time" "time"
) )
// Initial slice capacity for the values stored in a ResettingTimer // InitialResettingTimerSliceCap is the initial slice capacity for the values
// stored in a ResettingTimer.
const InitialResettingTimerSliceCap = 10 const InitialResettingTimerSliceCap = 10
// ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval. // ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval.
@ -113,21 +114,21 @@ func (t *StandardResettingTimer) Mean() float64 {
panic("Mean called on a StandardResettingTimer") panic("Mean called on a StandardResettingTimer")
} }
// Record the duration of the execution of the given function. // Time records the duration of the execution of the given function.
func (t *StandardResettingTimer) Time(f func()) { func (t *StandardResettingTimer) Time(f func()) {
ts := time.Now() ts := time.Now()
f() f()
t.Update(time.Since(ts)) t.Update(time.Since(ts))
} }
// Record the duration of an event. // Update records the duration of an event.
func (t *StandardResettingTimer) Update(d time.Duration) { func (t *StandardResettingTimer) Update(d time.Duration) {
t.mutex.Lock() t.mutex.Lock()
defer t.mutex.Unlock() defer t.mutex.Unlock()
t.values = append(t.values, int64(d)) t.values = append(t.values, int64(d))
} }
// Record the duration of an event that started at a time and ends now. // UpdateSince records the duration of an event that started at a time and ends now.
func (t *StandardResettingTimer) UpdateSince(ts time.Time) { func (t *StandardResettingTimer) UpdateSince(ts time.Time) {
t.mutex.Lock() t.mutex.Lock()
defer t.mutex.Unlock() defer t.mutex.Unlock()
@ -211,7 +212,7 @@ func (t *ResettingTimerSnapshot) calc(percentiles []float64) {
// math.Floor(x + 0.5) // math.Floor(x + 0.5)
indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5)) indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
if pct >= 0 { if pct >= 0 {
indexOfPerc -= 1 // index offset=0 indexOfPerc-- // index offset=0
} }
thresholdBoundary = t.values[indexOfPerc] thresholdBoundary = t.values[indexOfPerc]
} }

View file

@ -52,18 +52,18 @@ var (
threadCreateProfile = pprof.Lookup("threadcreate") threadCreateProfile = pprof.Lookup("threadcreate")
) )
// Capture new values for the Go runtime statistics exported in // CaptureRuntimeMemStats captures new values for the Go runtime statistics exported
// runtime.MemStats. This is designed to be called as a goroutine. // in runtime.MemStats. This is designed to be called as a goroutine.
func CaptureRuntimeMemStats(r Registry, d time.Duration) { func CaptureRuntimeMemStats(r Registry, d time.Duration) {
for range time.Tick(d) { for range time.Tick(d) {
CaptureRuntimeMemStatsOnce(r) CaptureRuntimeMemStatsOnce(r)
} }
} }
// Capture new values for the Go runtime statistics exported in // CaptureRuntimeMemStatsOnce captures new values for the Go runtime statistics
// runtime.MemStats. This is designed to be called in a background // exported in runtime.MemStats. This is designed to be called in a background
// goroutine. Giving a registry which has not been given to // goroutine. Giving a registry which has not been given to RegisterRuntimeMemStats
// RegisterRuntimeMemStats will panic. // will panic.
// //
// Be very careful with this because runtime.ReadMemStats calls the C // Be very careful with this because runtime.ReadMemStats calls the C
// functions runtime·semacquire(&runtime·worldsema) and runtime·stoptheworld() // functions runtime·semacquire(&runtime·worldsema) and runtime·stoptheworld()
@ -142,7 +142,7 @@ func CaptureRuntimeMemStatsOnce(r Registry) {
runtimeMetrics.NumThread.Update(int64(threadCreateProfile.Count())) runtimeMetrics.NumThread.Update(int64(threadCreateProfile.Count()))
} }
// Register runtimeMetrics for the Go runtime statistics exported in runtime and // RegisterRuntimeMemStats registers runtimeMetrics for the Go runtime statistics exported in runtime and
// specifically runtime.MemStats. The runtimeMetrics are named by their // specifically runtime.MemStats. The runtimeMetrics are named by their
// fully-qualified Go symbols, i.e. runtime.MemStats.Alloc. // fully-qualified Go symbols, i.e. runtime.MemStats.Alloc.
func RegisterRuntimeMemStats(r Registry) { func RegisterRuntimeMemStats(r Registry) {

View file

@ -10,7 +10,7 @@ import (
const rescaleThreshold = time.Hour const rescaleThreshold = time.Hour
// Samples maintain a statistically-significant selection of values from // Sample maintains a statistically-significant selection of values from
// a stream. // a stream.
type Sample interface { type Sample interface {
Clear() Clear()
@ -214,7 +214,7 @@ func (NilSample) Percentiles(ps []float64) []float64 {
// Size is a no-op. // Size is a no-op.
func (NilSample) Size() int { return 0 } func (NilSample) Size() int { return 0 }
// Sample is a no-op. // Snapshot is a no-op.
func (NilSample) Snapshot() Sample { return NilSample{} } func (NilSample) Snapshot() Sample { return NilSample{} }
// StdDev is a no-op. // StdDev is a no-op.
@ -268,7 +268,7 @@ func SampleMin(values []int64) int64 {
return min return min
} }
// SamplePercentiles returns an arbitrary percentile of the slice of int64. // SamplePercentile returns an arbitrary percentile of the slice of int64.
func SamplePercentile(values int64Slice, p float64) float64 { func SamplePercentile(values int64Slice, p float64) float64 {
return SamplePercentiles(values, []float64{p})[0] return SamplePercentiles(values, []float64{p})[0]
} }
@ -302,6 +302,7 @@ type SampleSnapshot struct {
values []int64 values []int64
} }
// NewSampleSnapshot creates a new sample snapshot.
func NewSampleSnapshot(count int64, values []int64) *SampleSnapshot { func NewSampleSnapshot(count int64, values []int64) *SampleSnapshot {
return &SampleSnapshot{ return &SampleSnapshot{
count: count, count: count,
@ -394,7 +395,7 @@ func SampleVariance(values []int64) float64 {
return sum / float64(len(values)) return sum / float64(len(values))
} }
// A uniform sample using Vitter's Algorithm R. // UniformSample represents a uniform sample using Vitter's Algorithm R.
// //
// <http://www.cs.umd.edu/~samir/498/vitter.pdf> // <http://www.cs.umd.edu/~samir/498/vitter.pdf>
type UniformSample struct { type UniformSample struct {

View file

@ -8,7 +8,7 @@ import (
"time" "time"
) )
// Output each metric in the given registry to syslog periodically using // Syslog outputs each metric in the given registry to syslog periodically using
// the given syslogger. // the given syslogger.
func Syslog(r Registry, d time.Duration, w *syslog.Writer) { func Syslog(r Registry, d time.Duration, w *syslog.Writer) {
for range time.Tick(d) { for range time.Tick(d) {

View file

@ -5,7 +5,7 @@ import (
"time" "time"
) )
// Timers capture the duration and rate of events. // Timer captures the duration and rate of events.
type Timer interface { type Timer interface {
Count() int64 Count() int64
Max() int64 Max() int64
@ -221,14 +221,14 @@ func (t *StandardTimer) Sum() int64 {
return t.histogram.Sum() return t.histogram.Sum()
} }
// Record the duration of the execution of the given function. // Time records the duration of the execution of the given function.
func (t *StandardTimer) Time(f func()) { func (t *StandardTimer) Time(f func()) {
ts := time.Now() ts := time.Now()
f() f()
t.Update(time.Since(ts)) t.Update(time.Since(ts))
} }
// Record the duration of an event. // Update records the duration of an event.
func (t *StandardTimer) Update(d time.Duration) { func (t *StandardTimer) Update(d time.Duration) {
t.mutex.Lock() t.mutex.Lock()
defer t.mutex.Unlock() defer t.mutex.Unlock()
@ -236,7 +236,7 @@ func (t *StandardTimer) Update(d time.Duration) {
t.meter.Mark(1) t.meter.Mark(1)
} }
// Record the duration of an event that started at a time and ends now. // UpdateSince records the duration of an event that started at a time and ends now.
func (t *StandardTimer) UpdateSince(ts time.Time) { func (t *StandardTimer) UpdateSince(ts time.Time) {
t.mutex.Lock() t.mutex.Lock()
defer t.mutex.Unlock() defer t.mutex.Unlock()