github.com/theQRL/go-zond@v0.1.1/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/theQRL/go-zond/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  	ps := m.Percentiles([]float64{0.50, 0.95, 0.99})
   129  	c.writeSummaryCounter(name, m.Count())
   130  	c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
   131  	c.writeSummaryPercentile(name, "0.50", ps[0])
   132  	c.writeSummaryPercentile(name, "0.95", ps[1])
   133  	c.writeSummaryPercentile(name, "0.99", ps[2])
   134  	c.buff.WriteRune('\n')
   135  }
   136  
   137  func (c *collector) writeGaugeInfo(name string, value metrics.GaugeInfoValue) {
   138  	name = mutateKey(name)
   139  	c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
   140  	c.buff.WriteString(name)
   141  	c.buff.WriteString(" ")
   142  	var kvs []string
   143  	for k, v := range value {
   144  		kvs = append(kvs, fmt.Sprintf("%v=%q", k, v))
   145  	}
   146  	sort.Strings(kvs)
   147  	c.buff.WriteString(fmt.Sprintf("{%v} 1\n\n", strings.Join(kvs, ", ")))
   148  }
   149  
   150  func (c *collector) writeGaugeCounter(name string, value interface{}) {
   151  	name = mutateKey(name)
   152  	c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
   153  	c.buff.WriteString(fmt.Sprintf(keyValueTpl, name, value))
   154  }
   155  
   156  func (c *collector) writeSummaryCounter(name string, value interface{}) {
   157  	name = mutateKey(name + "_count")
   158  	c.buff.WriteString(fmt.Sprintf(typeCounterTpl, name))
   159  	c.buff.WriteString(fmt.Sprintf(keyValueTpl, name, value))
   160  }
   161  
   162  func (c *collector) writeSummaryPercentile(name, p string, value interface{}) {
   163  	name = mutateKey(name)
   164  	c.buff.WriteString(fmt.Sprintf(keyQuantileTagValueTpl, name, p, value))
   165  }
   166  
   167  func mutateKey(key string) string {
   168  	return strings.ReplaceAll(key, "/", "_")
   169  }