github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/rcrowley/go-metrics/exp/exp.go (about) 1 // Hook go-metrics into expvar 2 // on any /debug/metrics request, load all vars from the registry into expvar, and execute regular expvar handler 3 package exp 4 5 import ( 6 "expvar" 7 "fmt" 8 "github.com/insionng/yougam/libraries/rcrowley/go-metrics" 9 "net/http" 10 "sync" 11 ) 12 13 type exp struct { 14 expvarLock sync.Mutex // expvar panics if you try to register the same var twice, so we must probe it safely 15 registry metrics.Registry 16 } 17 18 func (exp *exp) expHandler(w http.ResponseWriter, r *http.Request) { 19 // load our variables into expvar 20 exp.syncToExpvar() 21 22 // now just run the official expvar handler code (which is not publicly callable, so pasted inline) 23 w.Header().Set("Content-Type", "application/json; charset=utf-8") 24 fmt.Fprintf(w, "{\n") 25 first := true 26 expvar.Do(func(kv expvar.KeyValue) { 27 if !first { 28 fmt.Fprintf(w, ",\n") 29 } 30 first = false 31 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value) 32 }) 33 fmt.Fprintf(w, "\n}\n") 34 } 35 36 func Exp(r metrics.Registry) { 37 e := exp{sync.Mutex{}, r} 38 // this would cause a panic: 39 // panic: http: multiple registrations for /debug/vars 40 // http.HandleFunc("/debug/vars", e.expHandler) 41 // haven't found an elegant way, so just use a different endpoint 42 http.HandleFunc("/debug/metrics", e.expHandler) 43 } 44 45 func (exp *exp) getInt(name string) *expvar.Int { 46 var v *expvar.Int 47 exp.expvarLock.Lock() 48 p := expvar.Get(name) 49 if p != nil { 50 v = p.(*expvar.Int) 51 } else { 52 v = new(expvar.Int) 53 expvar.Publish(name, v) 54 } 55 exp.expvarLock.Unlock() 56 return v 57 } 58 59 func (exp *exp) getFloat(name string) *expvar.Float { 60 var v *expvar.Float 61 exp.expvarLock.Lock() 62 p := expvar.Get(name) 63 if p != nil { 64 v = p.(*expvar.Float) 65 } else { 66 v = new(expvar.Float) 67 expvar.Publish(name, v) 68 } 69 exp.expvarLock.Unlock() 70 return v 71 } 72 73 func (exp *exp) publishCounter(name string, metric metrics.Counter) { 74 v := exp.getInt(name) 75 v.Set(metric.Count()) 76 } 77 78 func (exp *exp) publishGauge(name string, metric metrics.Gauge) { 79 v := exp.getInt(name) 80 v.Set(metric.Value()) 81 } 82 func (exp *exp) publishGaugeFloat64(name string, metric metrics.GaugeFloat64) { 83 exp.getFloat(name).Set(metric.Value()) 84 } 85 86 func (exp *exp) publishHistogram(name string, metric metrics.Histogram) { 87 h := metric.Snapshot() 88 ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 89 exp.getInt(name + ".count").Set(h.Count()) 90 exp.getFloat(name + ".min").Set(float64(h.Min())) 91 exp.getFloat(name + ".max").Set(float64(h.Max())) 92 exp.getFloat(name + ".mean").Set(float64(h.Mean())) 93 exp.getFloat(name + ".std-dev").Set(float64(h.StdDev())) 94 exp.getFloat(name + ".50-percentile").Set(float64(ps[0])) 95 exp.getFloat(name + ".75-percentile").Set(float64(ps[1])) 96 exp.getFloat(name + ".95-percentile").Set(float64(ps[2])) 97 exp.getFloat(name + ".99-percentile").Set(float64(ps[3])) 98 exp.getFloat(name + ".999-percentile").Set(float64(ps[4])) 99 } 100 101 func (exp *exp) publishMeter(name string, metric metrics.Meter) { 102 m := metric.Snapshot() 103 exp.getInt(name + ".count").Set(m.Count()) 104 exp.getFloat(name + ".one-minute").Set(float64(m.Rate1())) 105 exp.getFloat(name + ".five-minute").Set(float64(m.Rate5())) 106 exp.getFloat(name + ".fifteen-minute").Set(float64((m.Rate15()))) 107 exp.getFloat(name + ".mean").Set(float64(m.RateMean())) 108 } 109 110 func (exp *exp) publishTimer(name string, metric metrics.Timer) { 111 t := metric.Snapshot() 112 ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 113 exp.getInt(name + ".count").Set(t.Count()) 114 exp.getFloat(name + ".min").Set(float64(t.Min())) 115 exp.getFloat(name + ".max").Set(float64(t.Max())) 116 exp.getFloat(name + ".mean").Set(float64(t.Mean())) 117 exp.getFloat(name + ".std-dev").Set(float64(t.StdDev())) 118 exp.getFloat(name + ".50-percentile").Set(float64(ps[0])) 119 exp.getFloat(name + ".75-percentile").Set(float64(ps[1])) 120 exp.getFloat(name + ".95-percentile").Set(float64(ps[2])) 121 exp.getFloat(name + ".99-percentile").Set(float64(ps[3])) 122 exp.getFloat(name + ".999-percentile").Set(float64(ps[4])) 123 exp.getFloat(name + ".one-minute").Set(float64(t.Rate1())) 124 exp.getFloat(name + ".five-minute").Set(float64(t.Rate5())) 125 exp.getFloat(name + ".fifteen-minute").Set(float64((t.Rate15()))) 126 exp.getFloat(name + ".mean-rate").Set(float64(t.RateMean())) 127 } 128 129 func (exp *exp) syncToExpvar() { 130 exp.registry.Each(func(name string, i interface{}) { 131 switch i.(type) { 132 case metrics.Counter: 133 exp.publishCounter(name, i.(metrics.Counter)) 134 case metrics.Gauge: 135 exp.publishGauge(name, i.(metrics.Gauge)) 136 case metrics.GaugeFloat64: 137 exp.publishGaugeFloat64(name, i.(metrics.GaugeFloat64)) 138 case metrics.Histogram: 139 exp.publishHistogram(name, i.(metrics.Histogram)) 140 case metrics.Meter: 141 exp.publishMeter(name, i.(metrics.Meter)) 142 case metrics.Timer: 143 exp.publishTimer(name, i.(metrics.Timer)) 144 default: 145 panic(fmt.Sprintf("unsupported type for '%s': %T", name, i)) 146 } 147 }) 148 }