From 14c96306a02197a7404136eb0d92ad9b3461389a Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 17 Jan 2014 16:15:23 -0800 Subject: [PATCH] feat(metrics): Add metrics pkg --- metrics/metrics.go | 42 ++++++++++++++++++++++ metrics/nil.go | 25 +++++++++++++ metrics/standard.go | 87 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 metrics/metrics.go create mode 100644 metrics/nil.go create mode 100644 metrics/standard.go diff --git a/metrics/metrics.go b/metrics/metrics.go new file mode 100644 index 000000000..6998aed88 --- /dev/null +++ b/metrics/metrics.go @@ -0,0 +1,42 @@ +// Package metrics provides both a means of generating metrics and the ability +// to send metric data to a graphite endpoint. +// The usage of this package without providing a graphite_addr when calling +// NewBucket results in NOP metric objects. No data will be collected. +package metrics + +import ( + "io" + + gometrics "github.com/rcrowley/go-metrics" +) + +type Timer gometrics.Timer +type Gauge gometrics.Gauge + +type Bucket interface { + // If a timer exists in this Bucket, return it. Otherwise, create + // a new timer with the given name and store it in this Bucket. + // The returned object will fulfull the Timer interface. + Timer(name string) Timer + + // This acts similarly to Timer, but with objects that fufill the + // Gauge interface. + Gauge(name string) Gauge + + // Write the current state of all Metrics in a human-readable format + // to the provide io.Writer. + Dump(io.Writer) + + // Instruct the Bucket to periodically push all metric data to the + // provided graphite endpoint. + Publish(string) error +} + +// Create a new Bucket object that periodically +func NewBucket(name string) Bucket { + if name == "" { + return nilBucket{} + } + + return newStandardBucket(name) +} diff --git a/metrics/nil.go b/metrics/nil.go new file mode 100644 index 000000000..b24a02229 --- /dev/null +++ b/metrics/nil.go @@ -0,0 +1,25 @@ +package metrics + +import ( + "io" + + gometrics "github.com/rcrowley/go-metrics" +) + +type nilBucket struct{} + +func (nmb nilBucket) Dump(w io.Writer) { + return +} + +func (nmb nilBucket) Timer(name string) Timer { + return gometrics.NilTimer{} +} + +func (nmf nilBucket) Gauge(name string) Gauge { + return gometrics.NilGauge{} +} + +func (nmf nilBucket) Publish(string) error { + return nil +} diff --git a/metrics/standard.go b/metrics/standard.go new file mode 100644 index 000000000..c77ef1218 --- /dev/null +++ b/metrics/standard.go @@ -0,0 +1,87 @@ +package metrics + +import ( + "io" + "net" + "sync" + "time" + + gometrics "github.com/rcrowley/go-metrics" +) + +const ( + // RuntimeMemStatsSampleInterval is the interval in seconds at which the + // Go runtime's memory statistics will be gathered. + RuntimeMemStatsSampleInterval = time.Duration(2) * time.Second + + // GraphitePublishInterval is the interval in seconds at which all + // gathered statistics will be published to a Graphite endpoint. + GraphitePublishInterval = time.Duration(2) * time.Second +) + + +type standardBucket struct { + sync.Mutex + name string + registry gometrics.Registry + timers map[string]Timer + gauges map[string]Gauge +} + +func newStandardBucket(name string) standardBucket { + registry := gometrics.NewRegistry() + + gometrics.RegisterRuntimeMemStats(registry) + go gometrics.CaptureRuntimeMemStats(registry, RuntimeMemStatsSampleInterval) + + return standardBucket{ + name: name, + registry: registry, + timers: make(map[string]Timer), + gauges: make(map[string]Gauge), + } +} + +func (smb standardBucket) Dump(w io.Writer) { + gometrics.WriteOnce(smb.registry, w) + return +} + +func (smb standardBucket) Timer(name string) Timer { + smb.Lock() + defer smb.Unlock() + + timer, ok := smb.timers[name] + if !ok { + timer = gometrics.NewTimer() + smb.timers[name] = timer + smb.registry.Register(name, timer) + } + + return timer +} + +func (smb standardBucket) Gauge(name string) Gauge { + smb.Lock() + defer smb.Unlock() + + gauge, ok := smb.gauges[name] + if !ok { + gauge = gometrics.NewGauge() + smb.gauges[name] = gauge + smb.registry.Register(name, gauge) + } + + return gauge +} + +func (smb standardBucket) Publish(graphite_addr string) error { + addr, err := net.ResolveTCPAddr("tcp", graphite_addr) + if err != nil { + return err + } + + go gometrics.Graphite(smb.registry, GraphitePublishInterval, smb.name, addr) + + return nil +}