github.com/klaytn/klaytn@v1.12.1/metrics/prometheus/prometheusmetrics.go (about)

     1  // Copyright 2018 The klaytn Authors
     2  //
     3  // This file is derived from metrics/prometheus/prometheusmetrics.go (2018/06/04).
     4  // See LICENSE in the top directory for the original copyright and license.
     5  
     6  package prometheusmetrics
     7  
     8  import (
     9  	"fmt"
    10  	"strings"
    11  	"time"
    12  
    13  	klaytnmetrics "github.com/klaytn/klaytn/metrics"
    14  
    15  	"github.com/prometheus/client_golang/prometheus"
    16  	"github.com/rcrowley/go-metrics"
    17  )
    18  
    19  // PrometheusConfig provides a container with config parameters for the Prometheus Exporter
    20  
    21  type PrometheusConfig struct {
    22  	namespace     string
    23  	Registry      metrics.Registry // Registry to be exported
    24  	subsystem     string
    25  	promRegistry  prometheus.Registerer // Prometheus registry
    26  	FlushInterval time.Duration         // interval to update prom metrics
    27  	gauges        map[string]prometheus.Gauge
    28  }
    29  
    30  // NewPrometheusProvider returns a Provider that produces Prometheus metrics.
    31  // Namespace and subsystem are applied to all produced metrics.
    32  func NewPrometheusProvider(r metrics.Registry, namespace string, subsystem string, promRegistry prometheus.Registerer,
    33  	FlushInterval time.Duration,
    34  ) *PrometheusConfig {
    35  	return &PrometheusConfig{
    36  		namespace:     namespace,
    37  		subsystem:     subsystem,
    38  		Registry:      r,
    39  		promRegistry:  promRegistry,
    40  		FlushInterval: FlushInterval,
    41  		gauges:        make(map[string]prometheus.Gauge),
    42  	}
    43  }
    44  
    45  func (c *PrometheusConfig) flattenKey(key string) string {
    46  	key = strings.Replace(key, " ", "_", -1)
    47  	key = strings.Replace(key, ".", "_", -1)
    48  	key = strings.Replace(key, "-", "_", -1)
    49  	key = strings.Replace(key, "=", "_", -1)
    50  	key = strings.Replace(key, "/", "_", -1)
    51  	return key
    52  }
    53  
    54  func (c *PrometheusConfig) gaugeFromNameAndValue(name string, val float64) {
    55  	key := fmt.Sprintf("%s_%s_%s", c.namespace, c.subsystem, name)
    56  	g, ok := c.gauges[key]
    57  	if !ok {
    58  		g = prometheus.NewGauge(prometheus.GaugeOpts{
    59  			Namespace: c.flattenKey(c.namespace),
    60  			Subsystem: c.flattenKey(c.subsystem),
    61  			Name:      c.flattenKey(name),
    62  			Help:      name,
    63  		})
    64  		c.promRegistry.MustRegister(g)
    65  		c.gauges[key] = g
    66  	}
    67  	g.Set(val)
    68  }
    69  
    70  func (c *PrometheusConfig) UpdatePrometheusMetrics() {
    71  	for range time.Tick(c.FlushInterval) {
    72  		c.UpdatePrometheusMetricsOnce()
    73  		klaytnmetrics.ResetMaxGauges()
    74  	}
    75  }
    76  
    77  var (
    78  	pv     = []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
    79  	pv_str = []string{"_0_5", "_0_75", "_0_95", "_0_99", "_0_999", "_0_9999"}
    80  )
    81  
    82  func (c *PrometheusConfig) UpdatePrometheusMetricsOnce() error {
    83  	c.Registry.Each(func(name string, i interface{}) {
    84  		switch metric := i.(type) {
    85  		case metrics.Counter:
    86  			c.gaugeFromNameAndValue(name, float64(metric.Count()))
    87  		case metrics.Gauge:
    88  			c.gaugeFromNameAndValue(name, float64(metric.Value()))
    89  		case metrics.GaugeFloat64:
    90  			c.gaugeFromNameAndValue(name, float64(metric.Value()))
    91  		case metrics.Histogram:
    92  			samples := metric.Snapshot().Sample().Values()
    93  			if len(samples) > 0 {
    94  				lastSample := samples[len(samples)-1]
    95  				c.gaugeFromNameAndValue(name, float64(lastSample))
    96  			}
    97  		case metrics.Meter:
    98  			lastSample := metric.Snapshot().Rate1()
    99  			c.gaugeFromNameAndValue(name, float64(lastSample))
   100  		case metrics.Timer:
   101  			// use mean as a default export value of metrics.Timer
   102  			c.gaugeFromNameAndValue(name, metric.Mean())
   103  			// also retrieve and export percentiles
   104  			ps := metric.Percentiles(pv)
   105  			for i := range pv {
   106  				c.gaugeFromNameAndValue(name+pv_str[i], ps[i])
   107  			}
   108  		}
   109  	})
   110  	return nil
   111  }