...
1
2
3 package exp
4
5 import (
6 "expvar"
7 "fmt"
8 "net/http"
9 "sync"
10
11 "github.com/rcrowley/go-metrics"
12 )
13
14 type exp struct {
15 expvarLock sync.Mutex
16 registry metrics.Registry
17 }
18
19 func (exp *exp) expHandler(w http.ResponseWriter, r *http.Request) {
20
21 exp.syncToExpvar()
22
23
24 w.Header().Set("Content-Type", "application/json; charset=utf-8")
25 fmt.Fprintf(w, "{\n")
26 first := true
27 expvar.Do(func(kv expvar.KeyValue) {
28 if !first {
29 fmt.Fprintf(w, ",\n")
30 }
31 first = false
32 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
33 })
34 fmt.Fprintf(w, "\n}\n")
35 }
36
37
38 func Exp(r metrics.Registry) {
39 h := ExpHandler(r)
40
41
42
43
44 http.Handle("/debug/metrics", h)
45 }
46
47
48 func ExpHandler(r metrics.Registry) http.Handler {
49 e := exp{sync.Mutex{}, r}
50 return http.HandlerFunc(e.expHandler)
51 }
52
53 func (exp *exp) getInt(name string) *expvar.Int {
54 var v *expvar.Int
55 exp.expvarLock.Lock()
56 p := expvar.Get(name)
57 if p != nil {
58 v = p.(*expvar.Int)
59 } else {
60 v = new(expvar.Int)
61 expvar.Publish(name, v)
62 }
63 exp.expvarLock.Unlock()
64 return v
65 }
66
67 func (exp *exp) getFloat(name string) *expvar.Float {
68 var v *expvar.Float
69 exp.expvarLock.Lock()
70 p := expvar.Get(name)
71 if p != nil {
72 v = p.(*expvar.Float)
73 } else {
74 v = new(expvar.Float)
75 expvar.Publish(name, v)
76 }
77 exp.expvarLock.Unlock()
78 return v
79 }
80
81 func (exp *exp) publishCounter(name string, metric metrics.Counter) {
82 v := exp.getInt(name)
83 v.Set(metric.Count())
84 }
85
86 func (exp *exp) publishGauge(name string, metric metrics.Gauge) {
87 v := exp.getInt(name)
88 v.Set(metric.Value())
89 }
90 func (exp *exp) publishGaugeFloat64(name string, metric metrics.GaugeFloat64) {
91 exp.getFloat(name).Set(metric.Value())
92 }
93
94 func (exp *exp) publishHistogram(name string, metric metrics.Histogram) {
95 h := metric.Snapshot()
96 ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
97 exp.getInt(name + ".count").Set(h.Count())
98 exp.getFloat(name + ".min").Set(float64(h.Min()))
99 exp.getFloat(name + ".max").Set(float64(h.Max()))
100 exp.getFloat(name + ".mean").Set(float64(h.Mean()))
101 exp.getFloat(name + ".std-dev").Set(float64(h.StdDev()))
102 exp.getFloat(name + ".50-percentile").Set(float64(ps[0]))
103 exp.getFloat(name + ".75-percentile").Set(float64(ps[1]))
104 exp.getFloat(name + ".95-percentile").Set(float64(ps[2]))
105 exp.getFloat(name + ".99-percentile").Set(float64(ps[3]))
106 exp.getFloat(name + ".999-percentile").Set(float64(ps[4]))
107 }
108
109 func (exp *exp) publishMeter(name string, metric metrics.Meter) {
110 m := metric.Snapshot()
111 exp.getInt(name + ".count").Set(m.Count())
112 exp.getFloat(name + ".one-minute").Set(float64(m.Rate1()))
113 exp.getFloat(name + ".five-minute").Set(float64(m.Rate5()))
114 exp.getFloat(name + ".fifteen-minute").Set(float64((m.Rate15())))
115 exp.getFloat(name + ".mean").Set(float64(m.RateMean()))
116 }
117
118 func (exp *exp) publishTimer(name string, metric metrics.Timer) {
119 t := metric.Snapshot()
120 ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
121 exp.getInt(name + ".count").Set(t.Count())
122 exp.getFloat(name + ".min").Set(float64(t.Min()))
123 exp.getFloat(name + ".max").Set(float64(t.Max()))
124 exp.getFloat(name + ".mean").Set(float64(t.Mean()))
125 exp.getFloat(name + ".std-dev").Set(float64(t.StdDev()))
126 exp.getFloat(name + ".50-percentile").Set(float64(ps[0]))
127 exp.getFloat(name + ".75-percentile").Set(float64(ps[1]))
128 exp.getFloat(name + ".95-percentile").Set(float64(ps[2]))
129 exp.getFloat(name + ".99-percentile").Set(float64(ps[3]))
130 exp.getFloat(name + ".999-percentile").Set(float64(ps[4]))
131 exp.getFloat(name + ".one-minute").Set(float64(t.Rate1()))
132 exp.getFloat(name + ".five-minute").Set(float64(t.Rate5()))
133 exp.getFloat(name + ".fifteen-minute").Set(float64((t.Rate15())))
134 exp.getFloat(name + ".mean-rate").Set(float64(t.RateMean()))
135 }
136
137 func (exp *exp) syncToExpvar() {
138 exp.registry.Each(func(name string, i interface{}) {
139 switch i.(type) {
140 case metrics.Counter:
141 exp.publishCounter(name, i.(metrics.Counter))
142 case metrics.Gauge:
143 exp.publishGauge(name, i.(metrics.Gauge))
144 case metrics.GaugeFloat64:
145 exp.publishGaugeFloat64(name, i.(metrics.GaugeFloat64))
146 case metrics.Histogram:
147 exp.publishHistogram(name, i.(metrics.Histogram))
148 case metrics.Meter:
149 exp.publishMeter(name, i.(metrics.Meter))
150 case metrics.Timer:
151 exp.publishTimer(name, i.(metrics.Timer))
152 default:
153 panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
154 }
155 })
156 }
157
View as plain text