github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/utilities/metrics/exp/exp.go (about)

     1  package exp
     2  
     3  import (
     4  	"expvar"
     5  	"fmt"
     6  	"net/http"
     7  	"sync"
     8  
     9  	"github.com/neatio-net/neatio/utilities/metrics"
    10  )
    11  
    12  type exp struct {
    13  	expvarLock sync.Mutex
    14  	registry   metrics.Registry
    15  }
    16  
    17  func (exp *exp) expHandler(w http.ResponseWriter, r *http.Request) {
    18  
    19  	exp.syncToExpvar()
    20  
    21  	w.Header().Set("Content-Type", "application/json; charset=utf-8")
    22  	fmt.Fprintf(w, "{\n")
    23  	first := true
    24  	expvar.Do(func(kv expvar.KeyValue) {
    25  		if !first {
    26  			fmt.Fprintf(w, ",\n")
    27  		}
    28  		first = false
    29  		fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
    30  	})
    31  	fmt.Fprintf(w, "\n}\n")
    32  }
    33  
    34  func Exp(r metrics.Registry) {
    35  	h := ExpHandler(r)
    36  
    37  	http.Handle("/debug/metrics", h)
    38  }
    39  
    40  func ExpHandler(r metrics.Registry) http.Handler {
    41  	e := exp{sync.Mutex{}, r}
    42  	return http.HandlerFunc(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(h.Mean())
    93  	exp.getFloat(name + ".std-dev").Set(h.StdDev())
    94  	exp.getFloat(name + ".50-percentile").Set(ps[0])
    95  	exp.getFloat(name + ".75-percentile").Set(ps[1])
    96  	exp.getFloat(name + ".95-percentile").Set(ps[2])
    97  	exp.getFloat(name + ".99-percentile").Set(ps[3])
    98  	exp.getFloat(name + ".999-percentile").Set(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(m.Rate1())
   105  	exp.getFloat(name + ".five-minute").Set(m.Rate5())
   106  	exp.getFloat(name + ".fifteen-minute").Set((m.Rate15()))
   107  	exp.getFloat(name + ".mean").Set(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(t.Mean())
   117  	exp.getFloat(name + ".std-dev").Set(t.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  	exp.getFloat(name + ".one-minute").Set(t.Rate1())
   124  	exp.getFloat(name + ".five-minute").Set(t.Rate5())
   125  	exp.getFloat(name + ".fifteen-minute").Set(t.Rate15())
   126  	exp.getFloat(name + ".mean-rate").Set(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  }