Richard Crowley před 14 roky
revize
f7cf4d7405
14 změnil soubory, kde provedl 468 přidání a 0 odebrání
  1. 5 0
      .gitignore
  2. 29 0
      LICENSE
  3. 25 0
      Makefile
  4. 0 0
      README.md
  5. 11 0
      cmd/metrics/Makefile
  6. 80 0
      cmd/metrics/metrics.go
  7. 46 0
      counter.go
  8. 34 0
      gauge.go
  9. 11 0
      healthcheck.go
  10. 119 0
      histogram.go
  11. 10 0
      meter.go
  12. 6 0
      metrics.go
  13. 84 0
      registry.go
  14. 8 0
      timer.go

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+*.[68]
+*.a
+*.swp
+_obj
+cmd/metrics/metrics

+ 29 - 0
LICENSE

@@ -0,0 +1,29 @@
+Copyright 2011 Richard Crowley. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    1.  Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+    2.  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.
+
+THIS SOFTWARE IS PROVIDED BY RICHARD CROWLEY ``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 RICHARD CROWLEY 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.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of Richard Crowley.

+ 25 - 0
Makefile

@@ -0,0 +1,25 @@
+include $(GOROOT)/src/Make.inc
+
+TARG=metrics
+GOFILES=\
+	counter.go\
+	gauge.go\
+	healthcheck.go\
+	histogram.go\
+	meter.go\
+	metrics.go\
+	registry.go\
+	timer.go\
+
+include $(GOROOT)/src/Make.pkg
+
+all: uninstall clean install
+	make -C cmd/metrics uninstall clean install
+
+uninstall:
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)/$(TARG).a
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)/github.com/rcrowley/go-$(TARG).a
+	rm -rf $(GOROOT)/src/pkg/github.com/rcrowley/go-$(TARG)
+	make -C cmd/metrics uninstall
+
+.PHONY: all uninstall

+ 0 - 0
README.md


+ 11 - 0
cmd/metrics/Makefile

@@ -0,0 +1,11 @@
+include $(GOROOT)/src/Make.inc
+
+TARG=metrics
+GOFILES=metrics.go
+
+include $(GOROOT)/src/Make.cmd
+
+uninstall:
+	rm -f $(GOROOT)/bin/$(TARG)
+
+.PHONY: uninstall

+ 80 - 0
cmd/metrics/metrics.go

@@ -0,0 +1,80 @@
+package main
+
+import (
+	"fmt"
+	"metrics"
+	"time"
+)
+
+func main() {
+
+	r := metrics.NewRegistry()
+
+/*
+	c := metrics.NewCounter()
+	r.RegisterCounter("foo", c)
+	for i := 0; i < 1000; i++ {
+		go func() {
+			for {
+				c.Dec(19)
+				time.Sleep(300e6)
+			}
+		}()
+		go func() {
+			for {
+				c.Inc(47)
+				time.Sleep(400e6)
+			}
+		}()
+	}
+	for {
+		fmt.Printf("c.Count(): %v\n", c.Count())
+		time.Sleep(500e6)
+	}
+*/
+
+/*
+	g := metrics.NewGauge()
+	r.RegisterGauge("bar", g)
+	for i := 0; i < 1000; i++ {
+		go func() {
+			for {
+				g.Update(19)
+				time.Sleep(300e6)
+			}
+		}()
+		go func() {
+			for {
+				g.Update(47)
+				time.Sleep(400e6)
+			}
+		}()
+	}
+	for {
+		fmt.Printf("g.Value(): %v\n", g.Value())
+		time.Sleep(500e6)
+	}
+*/
+
+	h := metrics.NewHistogram()
+	r.RegisterHistogram("baz", h)
+	for i := 0; i < 1000; i++ {
+		go func() {
+			for {
+				h.Update(19)
+				time.Sleep(300e6)
+			}
+		}()
+		go func() {
+			for {
+				h.Update(47)
+				time.Sleep(400e6)
+			}
+		}()
+	}
+	for {
+		fmt.Printf("h: %v %v %v %v %v %v\n", h.Count(), h.Sum(), h.Min(), h.Max(), h.StdDev(), h.Variance())
+		time.Sleep(500e6)
+	}
+
+}

+ 46 - 0
counter.go

@@ -0,0 +1,46 @@
+package metrics
+
+type Counter interface {
+	Clear()
+	Count() int64
+	Dec(int64)
+	Inc(int64)
+}
+
+type counter struct {
+	in, out chan int64
+	reset chan bool
+}
+
+func NewCounter() Counter {
+	c := &counter{make(chan int64), make(chan int64), make(chan bool)}
+	go c.arbiter()
+	return c
+}
+
+func (c *counter) Clear() {
+	c.reset <- true
+}
+
+func (c *counter) Count() int64 {
+	return <-c.out
+}
+
+func (c *counter) Dec(i int64) {
+	c.in <- -i
+}
+
+func (c *counter) Inc(i int64) {
+	c.in <- i
+}
+
+func (c *counter) arbiter() {
+	var count int64
+	for {
+		select {
+		case i := <-c.in: count += i
+		case c.out <- count:
+		case <-c.reset: count = 0
+		}
+	}
+}

+ 34 - 0
gauge.go

@@ -0,0 +1,34 @@
+package metrics
+
+type Gauge interface {
+	Update(int64)
+	Value() int64
+}
+
+type gauge struct {
+	in, out chan int64
+}
+
+func NewGauge() Gauge {
+	g := &gauge{make(chan int64), make(chan int64)}
+	go g.arbiter()
+	return g
+}
+
+func (g *gauge) Update(i int64) {
+	g.in <- i
+}
+
+func (g *gauge) Value() int64 {
+	return <-g.out
+}
+
+func (g *gauge) arbiter() {
+	var value int64
+	for {
+		select {
+		case i := <-g.in: value = i
+		case g.out <- value:
+		}
+	}
+}

+ 11 - 0
healthcheck.go

@@ -0,0 +1,11 @@
+package metrics
+
+import (
+	"os"
+)
+
+type Healthcheck interface {
+	Check()
+	Healthy()
+	Unhealthy(os.Error)
+}

+ 119 - 0
histogram.go

@@ -0,0 +1,119 @@
+package metrics
+
+import (
+	"math"
+)
+
+type Histogram interface {
+	Clear()
+	Count() int64
+	Max() int64
+	Mean() float64
+	Min() int64
+	Percentile(float64) float64
+	StdDev() float64
+	Sum() int64
+	Update(int64)
+	Variance() float64
+}
+
+type histogram struct {
+	in chan int64
+	out chan histogramV
+	reset chan bool
+}
+
+type histogramV struct {
+	count, sum, min, max int64
+	variance [2]float64
+}
+
+func NewHistogram() Histogram {
+	h := &histogram{make(chan int64), make(chan histogramV), make(chan bool)}
+	go h.arbiter()
+	return h
+}
+
+func (h *histogram) Clear() {
+	h.reset <- true
+}
+
+func (h *histogram) Count() int64 {
+	return (<-h.out).count
+}
+
+func (h *histogram) Max() int64 {
+	hv := <-h.out
+	if 0 < hv.count { return hv.max }
+	return 0
+}
+
+func (h *histogram) Mean() float64 {
+	hv := <-h.out
+	if 0 < hv.count {
+		return float64(hv.sum) / float64(hv.count)
+	}
+	return 0
+}
+
+func (h *histogram) Min() int64 {
+	hv := <-h.out
+	if 0 < hv.count { return hv.min }
+	return 0
+}
+
+func (h *histogram) Percentile(p float64) float64 {
+	// This requires sampling, which is more involved than I have time to
+	// implement this afternoon.
+	return 0.0
+}
+
+func (h *histogram) StdDev() float64 {
+	return math.Sqrt(h.Variance())
+}
+
+func (h *histogram) Sum() int64 {
+	return (<-h.out).sum
+}
+
+func (h *histogram) Update(i int64) {
+	h.in <- i
+}
+
+func (h *histogram) Variance() float64 {
+	hv := <-h.out
+	if 1 >= hv.count { return 0.0 }
+	return hv.variance[1] / float64(hv.count - 1)
+}
+
+func (h *histogram) arbiter() {
+	hv := newHistogramV()
+	for {
+		select {
+		case i := <-h.in:
+			hv.count++
+			if i < hv.min { hv.min = i }
+			if i > hv.max { hv.max = i }
+			hv.sum += i
+			f := float64(i)
+			if -1.0 == hv.variance[0] {
+				hv.variance[0] = f
+				hv.variance[1] = 0.0
+			} else {
+				m := hv.variance[0]
+				s := hv.variance[1]
+				hv.variance[0] = m + (f - m) / float64(hv.count)
+				hv.variance[1] = s + (f - m) * (f - hv.variance[0])
+			}
+		case h.out <- hv:
+		case <- h.reset: hv = newHistogramV()
+		}
+	}
+}
+
+func newHistogramV() histogramV {
+	return histogramV{
+		0, 0, math.MaxInt64, math.MinInt64,
+		[2]float64{-1.0, 0.0},
+	}
+}

+ 10 - 0
meter.go

@@ -0,0 +1,10 @@
+package metrics
+
+type Meter interface {
+	Count() int64
+	Mark(int64)
+	Rate1()
+	Rate5()
+	Rate15()
+	RateMean()
+}

+ 6 - 0
metrics.go

@@ -0,0 +1,6 @@
+// Go port of Coda Hale's Metrics library
+//
+// <https://github.com/rcrowley/go-metrics>
+//
+// Coda Hale's original work: <https://github.com/codahale/metrics>
+package metrics

+ 84 - 0
registry.go

@@ -0,0 +1,84 @@
+package metrics
+
+type Registry interface{
+	RegisterCounter(string, Counter)
+	RegisterGauge(string, Gauge)
+	RegisterHealthcheck(string, Healthcheck)
+	RegisterHistogram(string, Histogram)
+	RegisterMeter(string, Meter)
+	RegisterTimer(string, Timer)
+}
+
+type registry struct {
+	counters map[string]Counter
+	gauges map[string]Gauge
+	healthchecks map[string]Healthcheck
+	histograms map[string]Histogram
+	meters map[string]Meter
+	timers map[string]Timer
+}
+
+func NewRegistry() Registry {
+	return &registry {
+		make(map[string]Counter),
+		make(map[string]Gauge),
+		make(map[string]Healthcheck),
+		make(map[string]Histogram),
+		make(map[string]Meter),
+		make(map[string]Timer),
+	}
+}
+
+func (r *registry) GetCounter(name string) (Counter, bool) {
+	c, ok := r.counters[name]
+	return c, ok
+}
+
+func (r *registry) GetGauge(name string) (Gauge, bool) {
+	g, ok := r.gauges[name]
+	return g, ok
+}
+
+func (r *registry) GetHealthcheck(name string) (Healthcheck, bool) {
+	h, ok := r.healthchecks[name]
+	return h, ok
+}
+
+func (r *registry) GetHistogram(name string) (Histogram, bool) {
+	h, ok := r.histograms[name]
+	return h, ok
+}
+
+func (r *registry) GetMeter(name string) (Meter, bool) {
+	m, ok := r.meters[name]
+	return m, ok
+}
+
+func (r *registry) GetTimer(name string) (Timer, bool) {
+	t, ok := r.timers[name]
+	return t, ok
+}
+
+func (r *registry) RegisterCounter(name string, c Counter) {
+	r.counters[name] = c
+}
+
+func (r *registry) RegisterGauge(name string, g Gauge) {
+	r.gauges[name] = g
+}
+
+func (r *registry) RegisterHealthcheck(name string, h Healthcheck) {
+	r.healthchecks[name] = h
+}
+
+func (r *registry) RegisterHistogram(name string, h Histogram) {
+	r.histograms[name] = h
+}
+
+func (r *registry) RegisterMeter(name string, m Meter) {
+	r.meters[name] = m
+}
+
+func (r *registry) RegisterTimer(name string, t Timer) {
+	r.timers[name] = t
+}

+ 8 - 0
timer.go

@@ -0,0 +1,8 @@
+package metrics
+
+type Timer interface {
+}
+
+// A timer, in Coda-speak, is a meter and a histogram. Sounds like a job for
+//
+// later.