gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/common/metrics/exp/exp.go (about) 1 // Copyright 2018 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The aquachain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the aquachain library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Hook go-metrics into expvar 18 // on any /debug/metrics request, load all vars from the registry into expvar, and execute regular expvar handler 19 package exp 20 21 import ( 22 "expvar" 23 "fmt" 24 "net/http" 25 "sync" 26 27 "gitlab.com/aquachain/aquachain/common/metrics" 28 ) 29 30 type exp struct { 31 expvarLock sync.Mutex // expvar panics if you try to register the same var twice, so we must probe it safely 32 registry metrics.Registry 33 } 34 35 func (exp *exp) expHandler(w http.ResponseWriter, r *http.Request) { 36 // load our variables into expvar 37 exp.syncToExpvar() 38 39 // now just run the official expvar handler code (which is not publicly callable, so pasted inline) 40 w.Header().Set("Content-Type", "application/json; charset=utf-8") 41 fmt.Fprintf(w, "{\n") 42 first := true 43 expvar.Do(func(kv expvar.KeyValue) { 44 if !first { 45 fmt.Fprintf(w, ",\n") 46 } 47 first = false 48 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value) 49 }) 50 fmt.Fprintf(w, "\n}\n") 51 } 52 53 // Exp will register an expvar powered metrics handler with http.DefaultServeMux on "/debug/vars" 54 func Exp(r metrics.Registry) { 55 h := ExpHandler(r) 56 // this would cause a panic: 57 // panic: http: multiple registrations for /debug/vars 58 // http.HandleFunc("/debug/vars", e.expHandler) 59 // haven't found an elegant way, so just use a different endpoint 60 http.Handle("/debug/metrics", h) 61 } 62 63 // ExpHandler will return an expvar powered metrics handler. 64 func ExpHandler(r metrics.Registry) http.Handler { 65 e := exp{sync.Mutex{}, r} 66 return http.HandlerFunc(e.expHandler) 67 } 68 69 func (exp *exp) getInt(name string) *expvar.Int { 70 var v *expvar.Int 71 exp.expvarLock.Lock() 72 p := expvar.Get(name) 73 if p != nil { 74 v = p.(*expvar.Int) 75 } else { 76 v = new(expvar.Int) 77 expvar.Publish(name, v) 78 } 79 exp.expvarLock.Unlock() 80 return v 81 } 82 83 func (exp *exp) getFloat(name string) *expvar.Float { 84 var v *expvar.Float 85 exp.expvarLock.Lock() 86 p := expvar.Get(name) 87 if p != nil { 88 v = p.(*expvar.Float) 89 } else { 90 v = new(expvar.Float) 91 expvar.Publish(name, v) 92 } 93 exp.expvarLock.Unlock() 94 return v 95 } 96 97 func (exp *exp) publishCounter(name string, metric metrics.Counter) { 98 v := exp.getInt(name) 99 v.Set(metric.Count()) 100 } 101 102 func (exp *exp) publishGauge(name string, metric metrics.Gauge) { 103 v := exp.getInt(name) 104 v.Set(metric.Value()) 105 } 106 func (exp *exp) publishGaugeFloat64(name string, metric metrics.GaugeFloat64) { 107 exp.getFloat(name).Set(metric.Value()) 108 } 109 110 func (exp *exp) publishHistogram(name string, metric metrics.Histogram) { 111 h := metric.Snapshot() 112 ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 113 exp.getInt(name + ".count").Set(h.Count()) 114 exp.getFloat(name + ".min").Set(float64(h.Min())) 115 exp.getFloat(name + ".max").Set(float64(h.Max())) 116 exp.getFloat(name + ".mean").Set(h.Mean()) 117 exp.getFloat(name + ".std-dev").Set(h.StdDev()) 118 exp.getFloat(name + ".50-percentile").Set(ps[0]) 119 exp.getFloat(name + ".75-percentile").Set(ps[1]) 120 exp.getFloat(name + ".95-percentile").Set(ps[2]) 121 exp.getFloat(name + ".99-percentile").Set(ps[3]) 122 exp.getFloat(name + ".999-percentile").Set(ps[4]) 123 } 124 125 func (exp *exp) publishMeter(name string, metric metrics.Meter) { 126 m := metric.Snapshot() 127 exp.getInt(name + ".count").Set(m.Count()) 128 exp.getFloat(name + ".one-minute").Set(m.Rate1()) 129 exp.getFloat(name + ".five-minute").Set(m.Rate5()) 130 exp.getFloat(name + ".fifteen-minute").Set((m.Rate15())) 131 exp.getFloat(name + ".mean").Set(m.RateMean()) 132 } 133 134 func (exp *exp) publishTimer(name string, metric metrics.Timer) { 135 t := metric.Snapshot() 136 ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 137 exp.getInt(name + ".count").Set(t.Count()) 138 exp.getFloat(name + ".min").Set(float64(t.Min())) 139 exp.getFloat(name + ".max").Set(float64(t.Max())) 140 exp.getFloat(name + ".mean").Set(t.Mean()) 141 exp.getFloat(name + ".std-dev").Set(t.StdDev()) 142 exp.getFloat(name + ".50-percentile").Set(ps[0]) 143 exp.getFloat(name + ".75-percentile").Set(ps[1]) 144 exp.getFloat(name + ".95-percentile").Set(ps[2]) 145 exp.getFloat(name + ".99-percentile").Set(ps[3]) 146 exp.getFloat(name + ".999-percentile").Set(ps[4]) 147 exp.getFloat(name + ".one-minute").Set(t.Rate1()) 148 exp.getFloat(name + ".five-minute").Set(t.Rate5()) 149 exp.getFloat(name + ".fifteen-minute").Set(t.Rate15()) 150 exp.getFloat(name + ".mean-rate").Set(t.RateMean()) 151 } 152 153 func (exp *exp) syncToExpvar() { 154 exp.registry.Each(func(name string, i interface{}) { 155 switch i := i.(type) { 156 case metrics.Counter: 157 exp.publishCounter(name, i.(metrics.Counter)) 158 case metrics.Gauge: 159 exp.publishGauge(name, i.(metrics.Gauge)) 160 case metrics.GaugeFloat64: 161 exp.publishGaugeFloat64(name, i.(metrics.GaugeFloat64)) 162 case metrics.Histogram: 163 exp.publishHistogram(name, i.(metrics.Histogram)) 164 case metrics.Meter: 165 exp.publishMeter(name, i.(metrics.Meter)) 166 case metrics.Timer: 167 exp.publishTimer(name, i.(metrics.Timer)) 168 default: 169 panic(fmt.Sprintf("unsupported type for '%s': %T", name, i)) 170 } 171 }) 172 }