github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/logentry/metric/gauges.go (about) 1 package metric 2 3 import ( 4 "strings" 5 "time" 6 7 "github.com/mitchellh/mapstructure" 8 "github.com/pkg/errors" 9 "github.com/prometheus/client_golang/prometheus" 10 "github.com/prometheus/common/model" 11 ) 12 13 const ( 14 GaugeSet = "set" 15 GaugeInc = "inc" 16 GaugeDec = "dec" 17 GaugeAdd = "add" 18 GaugeSub = "sub" 19 20 ErrGaugeActionRequired = "gauge action must be defined as `set`, `inc`, `dec`, `add`, or `sub`" 21 ErrGaugeInvalidAction = "action %s is not valid, action must be `set`, `inc`, `dec`, `add`, or `sub`" 22 ) 23 24 type GaugeConfig struct { 25 Value *string `mapstructure:"value"` 26 Action string `mapstructure:"action"` 27 } 28 29 func validateGaugeConfig(config *GaugeConfig) error { 30 if config.Action == "" { 31 return errors.New(ErrGaugeActionRequired) 32 } 33 config.Action = strings.ToLower(config.Action) 34 if config.Action != GaugeSet && 35 config.Action != GaugeInc && 36 config.Action != GaugeDec && 37 config.Action != GaugeAdd && 38 config.Action != GaugeSub { 39 return errors.Errorf(ErrGaugeInvalidAction, config.Action) 40 } 41 return nil 42 } 43 44 func parseGaugeConfig(config interface{}) (*GaugeConfig, error) { 45 cfg := &GaugeConfig{} 46 err := mapstructure.Decode(config, cfg) 47 if err != nil { 48 return nil, err 49 } 50 return cfg, nil 51 } 52 53 // Gauges is a vector of gauges for a each log stream. 54 type Gauges struct { 55 *metricVec 56 Cfg *GaugeConfig 57 } 58 59 // NewGauges creates a new gauge vec. 60 func NewGauges(name, help string, config interface{}, maxIdleSec int64) (*Gauges, error) { 61 cfg, err := parseGaugeConfig(config) 62 if err != nil { 63 return nil, err 64 } 65 err = validateGaugeConfig(cfg) 66 if err != nil { 67 return nil, err 68 } 69 return &Gauges{ 70 metricVec: newMetricVec(func(labels map[string]string) prometheus.Metric { 71 return &expiringGauge{prometheus.NewGauge(prometheus.GaugeOpts{ 72 Help: help, 73 Name: name, 74 ConstLabels: labels, 75 }), 76 0, 77 } 78 }, maxIdleSec), 79 Cfg: cfg, 80 }, nil 81 } 82 83 // With returns the gauge associated with a stream labelset. 84 func (g *Gauges) With(labels model.LabelSet) prometheus.Gauge { 85 return g.metricVec.With(labels).(prometheus.Gauge) 86 } 87 88 type expiringGauge struct { 89 prometheus.Gauge 90 lastModSec int64 91 } 92 93 // Set sets the Gauge to an arbitrary value. 94 func (g *expiringGauge) Set(val float64) { 95 g.Gauge.Set(val) 96 g.lastModSec = time.Now().Unix() 97 } 98 99 // Inc increments the Gauge by 1. Use Add to increment it by arbitrary 100 // values. 101 func (g *expiringGauge) Inc() { 102 g.Gauge.Inc() 103 g.lastModSec = time.Now().Unix() 104 } 105 106 // Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary 107 // values. 108 func (g *expiringGauge) Dec() { 109 g.Gauge.Dec() 110 g.lastModSec = time.Now().Unix() 111 } 112 113 // Add adds the given value to the Gauge. (The value can be negative, 114 // resulting in a decrease of the Gauge.) 115 func (g *expiringGauge) Add(val float64) { 116 g.Gauge.Add(val) 117 g.lastModSec = time.Now().Unix() 118 } 119 120 // Sub subtracts the given value from the Gauge. (The value can be 121 // negative, resulting in an increase of the Gauge.) 122 func (g *expiringGauge) Sub(val float64) { 123 g.Gauge.Sub(val) 124 g.lastModSec = time.Now().Unix() 125 } 126 127 // SetToCurrentTime sets the Gauge to the current Unix time in seconds. 128 func (g *expiringGauge) SetToCurrentTime() { 129 g.Gauge.SetToCurrentTime() 130 g.lastModSec = time.Now().Unix() 131 } 132 133 // HasExpired implements Expirable 134 func (g *expiringGauge) HasExpired(currentTimeSec int64, maxAgeSec int64) bool { 135 return currentTimeSec-g.lastModSec >= maxAgeSec 136 }