Pārlūkot izejas kodu

Added JSON->io.Writer; consistent ordering to WriteOnce

Stuart Carnie 11 gadi atpakaļ
vecāks
revīzija
6d82eb1add
5 mainītis faili ar 129 papildinājumiem un 10 dzēšanām
  1. 67 1
      json.go
  2. 10 0
      json_test.go
  3. 16 0
      metrics.go
  4. 17 0
      metrics_test.go
  5. 19 9
      writer.go

+ 67 - 1
json.go

@@ -1,6 +1,9 @@
 package metrics
 
-import "encoding/json"
+import (
+	"encoding/json"
+	"io"
+)
 
 // MarshalJSON returns a byte slice containing a JSON representation of all
 // the metrics in the Registry.
@@ -63,3 +66,66 @@ func (r StandardRegistry) MarshalJSON() ([]byte, error) {
 	})
 	return json.Marshal(data)
 }
+
+// WriteJSONOnce outputs metrics from the given registry to the specified writer in JSON format
+func WriteJSONOnce(r Registry, w io.Writer) {
+	data := make(map[string]map[string]interface{})
+	r.Each(func(name string, i interface{}) {
+		values := make(map[string]interface{})
+		switch metric := i.(type) {
+		case Counter:
+			values["count"] = metric.Count()
+		case Gauge:
+			values["value"] = metric.Value()
+		case GaugeFloat64:
+			values["value"] = metric.Value()
+		case Healthcheck:
+			values["error"] = nil
+			metric.Check()
+			if err := metric.Error(); nil != err {
+				values["error"] = metric.Error().Error()
+			}
+		case Histogram:
+			h := metric.Snapshot()
+			ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
+			values["count"] = h.Count()
+			values["min"] = h.Min()
+			values["max"] = h.Max()
+			values["mean"] = h.Mean()
+			values["stddev"] = h.StdDev()
+			values["median"] = ps[0]
+			values["75%"] = ps[1]
+			values["95%"] = ps[2]
+			values["99%"] = ps[3]
+			values["99.9%"] = ps[4]
+		case Meter:
+			m := metric.Snapshot()
+			values["count"] = m.Count()
+			values["1m.rate"] = m.Rate1()
+			values["5m.rate"] = m.Rate5()
+			values["15m.rate"] = m.Rate15()
+			values["mean.rate"] = m.RateMean()
+		case Timer:
+			t := metric.Snapshot()
+			ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
+			values["count"] = t.Count()
+			values["min"] = t.Min()
+			values["max"] = t.Max()
+			values["mean"] = t.Mean()
+			values["stddev"] = t.StdDev()
+			values["median"] = ps[0]
+			values["75%"] = ps[1]
+			values["95%"] = ps[2]
+			values["99%"] = ps[3]
+			values["99.9%"] = ps[4]
+			values["1m.rate"] = t.Rate1()
+			values["5m.rate"] = t.Rate5()
+			values["15m.rate"] = t.Rate15()
+			values["mean.rate"] = t.RateMean()
+		}
+		data[name] = values
+	})
+
+	enc := json.NewEncoder(w)
+	enc.Encode(data)
+}

+ 10 - 0
json_test.go

@@ -16,3 +16,13 @@ func TestRegistryMarshallJSON(t *testing.T) {
 		t.Fatalf(s)
 	}
 }
+
+func TestRegistryWriteJSONOnce(t *testing.T) {
+	r := NewRegistry()
+	r.Register("counter", NewCounter())
+	b := &bytes.Buffer{}
+	WriteJSONOnce(r, b)
+	if s := b.String(); s != "{\"counter\":{\"count\":0}}\n" {
+		t.Fail()
+	}
+}

+ 16 - 0
metrics.go

@@ -11,3 +11,19 @@ package metrics
 // This global kill-switch helps quantify the observer effect and makes
 // for less cluttered pprof profiles.
 var UseNilMetrics bool = false
+
+type metric struct {
+	name string
+	m    interface{}
+}
+
+// metrics is a slice of metrics that implements sort.Interface
+type metrics []metric
+
+func (m metrics) Len() int { return len(m) }
+
+func (m metrics) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
+
+func (m metrics) Less(i, j int) bool {
+	return m[i].name < m[j].name
+}

+ 17 - 0
metrics_test.go

@@ -5,6 +5,7 @@ import (
 	"log"
 	"sync"
 	"testing"
+	"sort"
 )
 
 const FANOUT = 128
@@ -105,3 +106,19 @@ func BenchmarkMetrics(b *testing.B) {
 	wgR.Wait()
 	wgW.Wait()
 }
+
+func TestMetricsSorting(t *testing.T) {
+	var data = metrics{
+		{name:"zzz"},
+		{name:"bbb"},
+		{name:"fff"},
+		{name:"ggg"},
+	}
+
+	sort.Sort(data)
+	for i, d := range []string{"bbb","fff","ggg","zzz"} {
+		if data[i].name != d {
+			t.Fail()
+		}
+	}
+}

+ 19 - 9
writer.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"io"
 	"time"
+	"sort"
 )
 
 // Output each metric in the given registry periodically using the given
@@ -15,26 +16,35 @@ func Write(r Registry, d time.Duration, w io.Writer) {
 	}
 }
 
+// WriteOnce outputs metrics for the given registry to the specified io.Writer
+//
+// WriteOnce sorts by metric name to ensure the output remains consistent between runs
 func WriteOnce(r Registry, w io.Writer) {
+	var data metrics
 	r.Each(func(name string, i interface{}) {
-		switch metric := i.(type) {
+		data = append(data, metric{name, i})
+	})
+
+	sort.Sort(data)
+	for _, i := range data {
+		switch metric := i.m.(type) {
 		case Counter:
-			fmt.Fprintf(w, "counter %s\n", name)
+			fmt.Fprintf(w, "counter %s\n", i.name)
 			fmt.Fprintf(w, "  count:       %9d\n", metric.Count())
 		case Gauge:
-			fmt.Fprintf(w, "gauge %s\n", name)
+			fmt.Fprintf(w, "gauge %s\n", i.name)
 			fmt.Fprintf(w, "  value:       %9d\n", metric.Value())
 		case GaugeFloat64:
-			fmt.Fprintf(w, "gauge %s\n", name)
+			fmt.Fprintf(w, "gauge %s\n", i.name)
 			fmt.Fprintf(w, "  value:       %f\n", metric.Value())
 		case Healthcheck:
 			metric.Check()
-			fmt.Fprintf(w, "healthcheck %s\n", name)
+			fmt.Fprintf(w, "healthcheck %s\n", i.name)
 			fmt.Fprintf(w, "  error:       %v\n", metric.Error())
 		case Histogram:
 			h := metric.Snapshot()
 			ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
-			fmt.Fprintf(w, "histogram %s\n", name)
+			fmt.Fprintf(w, "histogram %s\n", i.name)
 			fmt.Fprintf(w, "  count:       %9d\n", h.Count())
 			fmt.Fprintf(w, "  min:         %9d\n", h.Min())
 			fmt.Fprintf(w, "  max:         %9d\n", h.Max())
@@ -47,7 +57,7 @@ func WriteOnce(r Registry, w io.Writer) {
 			fmt.Fprintf(w, "  99.9%%:       %12.2f\n", ps[4])
 		case Meter:
 			m := metric.Snapshot()
-			fmt.Fprintf(w, "meter %s\n", name)
+			fmt.Fprintf(w, "meter %s\n", i.name)
 			fmt.Fprintf(w, "  count:       %9d\n", m.Count())
 			fmt.Fprintf(w, "  1-min rate:  %12.2f\n", m.Rate1())
 			fmt.Fprintf(w, "  5-min rate:  %12.2f\n", m.Rate5())
@@ -56,7 +66,7 @@ func WriteOnce(r Registry, w io.Writer) {
 		case Timer:
 			t := metric.Snapshot()
 			ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
-			fmt.Fprintf(w, "timer %s\n", name)
+			fmt.Fprintf(w, "timer %s\n", i.name)
 			fmt.Fprintf(w, "  count:       %9d\n", t.Count())
 			fmt.Fprintf(w, "  min:         %9d\n", t.Min())
 			fmt.Fprintf(w, "  max:         %9d\n", t.Max())
@@ -72,5 +82,5 @@ func WriteOnce(r Registry, w io.Writer) {
 			fmt.Fprintf(w, "  15-min rate: %12.2f\n", t.Rate15())
 			fmt.Fprintf(w, "  mean rate:   %12.2f\n", t.RateMean())
 		}
-	})
+	}
 }