github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/metrics/exp/exp.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:39</date>
    10  //</624450098406887424>
    11  
    12  //将Go度量挂钩到expvar中
    13  //在任何/debug/metrics请求上,将注册表中的所有var加载到expvar,并执行常规expvar处理程序
    14  package exp
    15  
    16  import (
    17  	"expvar"
    18  	"fmt"
    19  	"net/http"
    20  	"sync"
    21  
    22  	"github.com/ethereum/go-ethereum/metrics"
    23  )
    24  
    25  type exp struct {
    26  expvarLock sync.Mutex //如果您尝试注册同一个var两次,expvar将崩溃,因此我们必须安全地探测它。
    27  	registry   metrics.Registry
    28  }
    29  
    30  func (exp *exp) expHandler(w http.ResponseWriter, r *http.Request) {
    31  //将变量加载到expvar中
    32  	exp.syncToExpvar()
    33  
    34  //现在只需运行官方的expvar处理程序代码(它不是可公开调用的,所以是内联粘贴的)
    35  	w.Header().Set("Content-Type", "application/json; charset=utf-8")
    36  	fmt.Fprintf(w, "{\n")
    37  	first := true
    38  	expvar.Do(func(kv expvar.KeyValue) {
    39  		if !first {
    40  			fmt.Fprintf(w, ",\n")
    41  		}
    42  		first = false
    43  		fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
    44  	})
    45  	fmt.Fprintf(w, "\n}\n")
    46  }
    47  
    48  //exp将使用http.defaultservemux在“/debug/vars”上注册一个expvar支持的度量处理程序。
    49  func Exp(r metrics.Registry) {
    50  	h := ExpHandler(r)
    51  //这会引起恐慌:
    52  //死机:http:/debug/vars的多个注册
    53  //http.handlefunc(“/debug/vars”,e.exphandler)
    54  //还没有找到一种优雅的方式,所以只需使用一个不同的端点
    55  	http.Handle("/debug/metrics", h)
    56  }
    57  
    58  //exphandler将返回一个expvar支持的度量处理程序。
    59  func ExpHandler(r metrics.Registry) http.Handler {
    60  	e := exp{sync.Mutex{}, r}
    61  	return http.HandlerFunc(e.expHandler)
    62  }
    63  
    64  func (exp *exp) getInt(name string) *expvar.Int {
    65  	var v *expvar.Int
    66  	exp.expvarLock.Lock()
    67  	p := expvar.Get(name)
    68  	if p != nil {
    69  		v = p.(*expvar.Int)
    70  	} else {
    71  		v = new(expvar.Int)
    72  		expvar.Publish(name, v)
    73  	}
    74  	exp.expvarLock.Unlock()
    75  	return v
    76  }
    77  
    78  func (exp *exp) getFloat(name string) *expvar.Float {
    79  	var v *expvar.Float
    80  	exp.expvarLock.Lock()
    81  	p := expvar.Get(name)
    82  	if p != nil {
    83  		v = p.(*expvar.Float)
    84  	} else {
    85  		v = new(expvar.Float)
    86  		expvar.Publish(name, v)
    87  	}
    88  	exp.expvarLock.Unlock()
    89  	return v
    90  }
    91  
    92  func (exp *exp) publishCounter(name string, metric metrics.Counter) {
    93  	v := exp.getInt(name)
    94  	v.Set(metric.Count())
    95  }
    96  
    97  func (exp *exp) publishGauge(name string, metric metrics.Gauge) {
    98  	v := exp.getInt(name)
    99  	v.Set(metric.Value())
   100  }
   101  func (exp *exp) publishGaugeFloat64(name string, metric metrics.GaugeFloat64) {
   102  	exp.getFloat(name).Set(metric.Value())
   103  }
   104  
   105  func (exp *exp) publishHistogram(name string, metric metrics.Histogram) {
   106  	h := metric.Snapshot()
   107  	ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
   108  	exp.getInt(name + ".count").Set(h.Count())
   109  	exp.getFloat(name + ".min").Set(float64(h.Min()))
   110  	exp.getFloat(name + ".max").Set(float64(h.Max()))
   111  	exp.getFloat(name + ".mean").Set(h.Mean())
   112  	exp.getFloat(name + ".std-dev").Set(h.StdDev())
   113  	exp.getFloat(name + ".50-percentile").Set(ps[0])
   114  	exp.getFloat(name + ".75-percentile").Set(ps[1])
   115  	exp.getFloat(name + ".95-percentile").Set(ps[2])
   116  	exp.getFloat(name + ".99-percentile").Set(ps[3])
   117  	exp.getFloat(name + ".999-percentile").Set(ps[4])
   118  }
   119  
   120  func (exp *exp) publishMeter(name string, metric metrics.Meter) {
   121  	m := metric.Snapshot()
   122  	exp.getInt(name + ".count").Set(m.Count())
   123  	exp.getFloat(name + ".one-minute").Set(m.Rate1())
   124  	exp.getFloat(name + ".five-minute").Set(m.Rate5())
   125  	exp.getFloat(name + ".fifteen-minute").Set((m.Rate15()))
   126  	exp.getFloat(name + ".mean").Set(m.RateMean())
   127  }
   128  
   129  func (exp *exp) publishTimer(name string, metric metrics.Timer) {
   130  	t := metric.Snapshot()
   131  	ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
   132  	exp.getInt(name + ".count").Set(t.Count())
   133  	exp.getFloat(name + ".min").Set(float64(t.Min()))
   134  	exp.getFloat(name + ".max").Set(float64(t.Max()))
   135  	exp.getFloat(name + ".mean").Set(t.Mean())
   136  	exp.getFloat(name + ".std-dev").Set(t.StdDev())
   137  	exp.getFloat(name + ".50-percentile").Set(ps[0])
   138  	exp.getFloat(name + ".75-percentile").Set(ps[1])
   139  	exp.getFloat(name + ".95-percentile").Set(ps[2])
   140  	exp.getFloat(name + ".99-percentile").Set(ps[3])
   141  	exp.getFloat(name + ".999-percentile").Set(ps[4])
   142  	exp.getFloat(name + ".one-minute").Set(t.Rate1())
   143  	exp.getFloat(name + ".five-minute").Set(t.Rate5())
   144  	exp.getFloat(name + ".fifteen-minute").Set(t.Rate15())
   145  	exp.getFloat(name + ".mean-rate").Set(t.RateMean())
   146  }
   147  
   148  func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) {
   149  	t := metric.Snapshot()
   150  	ps := t.Percentiles([]float64{50, 75, 95, 99})
   151  	exp.getInt(name + ".count").Set(int64(len(t.Values())))
   152  	exp.getFloat(name + ".mean").Set(t.Mean())
   153  	exp.getInt(name + ".50-percentile").Set(ps[0])
   154  	exp.getInt(name + ".75-percentile").Set(ps[1])
   155  	exp.getInt(name + ".95-percentile").Set(ps[2])
   156  	exp.getInt(name + ".99-percentile").Set(ps[3])
   157  }
   158  
   159  func (exp *exp) syncToExpvar() {
   160  	exp.registry.Each(func(name string, i interface{}) {
   161  		switch i := i.(type) {
   162  		case metrics.Counter:
   163  			exp.publishCounter(name, i)
   164  		case metrics.Gauge:
   165  			exp.publishGauge(name, i)
   166  		case metrics.GaugeFloat64:
   167  			exp.publishGaugeFloat64(name, i)
   168  		case metrics.Histogram:
   169  			exp.publishHistogram(name, i)
   170  		case metrics.Meter:
   171  			exp.publishMeter(name, i)
   172  		case metrics.Timer:
   173  			exp.publishTimer(name, i)
   174  		case metrics.ResettingTimer:
   175  			exp.publishResettingTimer(name, i)
   176  		default:
   177  			panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
   178  		}
   179  	})
   180  }
   181