github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/metrics/prometheus/collector.go (about)

     1  // Copyright 2019 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package prometheus
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"sort"
    23  	"strconv"
    24  	"strings"
    25  
    26  	"github.com/ethereum/go-ethereum/metrics"
    27  )
    28  
    29  var (
    30  	typeGaugeTpl           = "# TYPE %s gauge\n"
    31  	typeCounterTpl         = "# TYPE %s counter\n"
    32  	typeSummaryTpl         = "# TYPE %s summary\n"
    33  	keyValueTpl            = "%s %v\n\n"
    34  	keyQuantileTagValueTpl = "%s {quantile=\"%s\"} %v\n"
    35  )
    36  
    37  // collector is a collection of byte buffers that aggregate Prometheus reports
    38  // for different metric types.
    39  type collector struct {
    40  	buff *bytes.Buffer
    41  }
    42  
    43  // newCollector creates a new Prometheus metric aggregator.
    44  func newCollector() *collector {
    45  	return &collector{
    46  		buff: &bytes.Buffer{},
    47  	}
    48  }
    49  
    50  // Add adds the metric i to the collector. This method returns an error if the
    51  // metric type is not supported/known.
    52  func (c *collector) Add(name string, i any) error {
    53  	switch m := i.(type) {
    54  	case metrics.Counter:
    55  		c.addCounter(name, m.Snapshot())
    56  	case metrics.CounterFloat64:
    57  		c.addCounterFloat64(name, m.Snapshot())
    58  	case metrics.Gauge:
    59  		c.addGauge(name, m.Snapshot())
    60  	case metrics.GaugeFloat64:
    61  		c.addGaugeFloat64(name, m.Snapshot())
    62  	case metrics.GaugeInfo:
    63  		c.addGaugeInfo(name, m.Snapshot())
    64  	case metrics.Histogram:
    65  		c.addHistogram(name, m.Snapshot())
    66  	case metrics.Meter:
    67  		c.addMeter(name, m.Snapshot())
    68  	case metrics.Timer:
    69  		c.addTimer(name, m.Snapshot())
    70  	case metrics.ResettingTimer:
    71  		c.addResettingTimer(name, m.Snapshot())
    72  	default:
    73  		return fmt.Errorf("unknown prometheus metric type %T", i)
    74  	}
    75  	return nil
    76  }
    77  
    78  func (c *collector) addCounter(name string, m metrics.CounterSnapshot) {
    79  	c.writeGaugeCounter(name, m.Count())
    80  }
    81  
    82  func (c *collector) addCounterFloat64(name string, m metrics.CounterFloat64Snapshot) {
    83  	c.writeGaugeCounter(name, m.Count())
    84  }
    85  
    86  func (c *collector) addGauge(name string, m metrics.GaugeSnapshot) {
    87  	c.writeGaugeCounter(name, m.Value())
    88  }
    89  
    90  func (c *collector) addGaugeFloat64(name string, m metrics.GaugeFloat64Snapshot) {
    91  	c.writeGaugeCounter(name, m.Value())
    92  }
    93  
    94  func (c *collector) addGaugeInfo(name string, m metrics.GaugeInfoSnapshot) {
    95  	c.writeGaugeInfo(name, m.Value())
    96  }
    97  
    98  func (c *collector) addHistogram(name string, m metrics.HistogramSnapshot) {
    99  	pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
   100  	ps := m.Percentiles(pv)
   101  	c.writeSummaryCounter(name, m.Count())
   102  	c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
   103  	for i := range pv {
   104  		c.writeSummaryPercentile(name, strconv.FormatFloat(pv[i], 'f', -1, 64), ps[i])
   105  	}
   106  	c.buff.WriteRune('\n')
   107  }
   108  
   109  func (c *collector) addMeter(name string, m metrics.MeterSnapshot) {
   110  	c.writeGaugeCounter(name, m.Count())
   111  }
   112  
   113  func (c *collector) addTimer(name string, m metrics.TimerSnapshot) {
   114  	pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
   115  	ps := m.Percentiles(pv)
   116  	c.writeSummaryCounter(name, m.Count())
   117  	c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
   118  	for i := range pv {
   119  		c.writeSummaryPercentile(name, strconv.FormatFloat(pv[i], 'f', -1, 64), ps[i])
   120  	}
   121  	c.buff.WriteRune('\n')
   122  }
   123  
   124  func (c *collector) addResettingTimer(name string, m metrics.ResettingTimerSnapshot) {
   125  	if m.Count() <= 0 {
   126  		return
   127  	}
   128  	pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
   129  	ps := m.Percentiles(pv)
   130  	c.writeSummaryCounter(name, m.Count())
   131  	c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
   132  	for i := range pv {
   133  		c.writeSummaryPercentile(name, strconv.FormatFloat(pv[i], 'f', -1, 64), ps[i])
   134  	}
   135  	c.buff.WriteRune('\n')
   136  }
   137  
   138  func (c *collector) writeGaugeInfo(name string, value metrics.GaugeInfoValue) {
   139  	name = mutateKey(name)
   140  	c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
   141  	c.buff.WriteString(name)
   142  	c.buff.WriteString(" ")
   143  	var kvs []string
   144  	for k, v := range value {
   145  		kvs = append(kvs, fmt.Sprintf("%v=%q", k, v))
   146  	}
   147  	sort.Strings(kvs)
   148  	c.buff.WriteString(fmt.Sprintf("{%v} 1\n\n", strings.Join(kvs, ", ")))
   149  }
   150  
   151  func (c *collector) writeGaugeCounter(name string, value interface{}) {
   152  	name = mutateKey(name)
   153  	c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
   154  	c.buff.WriteString(fmt.Sprintf(keyValueTpl, name, value))
   155  }
   156  
   157  func (c *collector) writeSummaryCounter(name string, value interface{}) {
   158  	name = mutateKey(name + "_count")
   159  	c.buff.WriteString(fmt.Sprintf(typeCounterTpl, name))
   160  	c.buff.WriteString(fmt.Sprintf(keyValueTpl, name, value))
   161  }
   162  
   163  func (c *collector) writeSummaryPercentile(name, p string, value interface{}) {
   164  	name = mutateKey(name)
   165  	c.buff.WriteString(fmt.Sprintf(keyQuantileTagValueTpl, name, p, value))
   166  }
   167  
   168  func mutateKey(key string) string {
   169  	return strings.ReplaceAll(key, "/", "_")
   170  }