Align metric names with Prometheus naming conventions
Use base units, export cumulative values as _total counters, update docs, dashboards and rules.
This commit is contained in:
+119
-2
@@ -23,6 +23,7 @@ type TTLMetric interface {
|
||||
// it is automatically removed from the underlying GaugeVec.
|
||||
type TTLGaugeVec struct {
|
||||
gaugeVec *prometheus.GaugeVec // Underlying Prometheus GaugeVec.
|
||||
labelNames []string // Label names of the underlying GaugeVec.
|
||||
ttl time.Duration // Duration after which an unused label set is considered stale.
|
||||
lastUpdate sync.Map // Map storing last update time for each label set (key is a sorted labels string).
|
||||
}
|
||||
@@ -31,8 +32,9 @@ type TTLGaugeVec struct {
|
||||
// The underlying GaugeVec is registered using promauto.
|
||||
func NewTTLGaugeVec(opts prometheus.GaugeOpts, labelNames []string, ttl time.Duration) *TTLGaugeVec {
|
||||
return &TTLGaugeVec{
|
||||
gaugeVec: promauto.NewGaugeVec(opts, labelNames),
|
||||
ttl: ttl,
|
||||
gaugeVec: promauto.NewGaugeVec(opts, labelNames),
|
||||
labelNames: labelNames,
|
||||
ttl: ttl,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,3 +139,118 @@ func (r *TTLRegistry) StartCleanupLoop(interval time.Duration) {
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// TTLCounterVec exposes cumulative values as Prometheus counters while keeping
|
||||
// the same "set an absolute value" usage as TTLGaugeVec. The PVE API reports
|
||||
// counters as absolute totals, which prometheus.CounterVec cannot express
|
||||
// (it only supports Inc/Add), so the metrics are emitted as constant metrics
|
||||
// of type counter. Label sets not updated within the TTL are dropped.
|
||||
type TTLCounterVec struct {
|
||||
desc *prometheus.Desc // Metric descriptor.
|
||||
labelNames []string // Label names in exposition order.
|
||||
ttl time.Duration // Duration after which an unused label set is considered stale.
|
||||
mu sync.RWMutex // Guards values.
|
||||
values map[string]*ttlCounterEntry // Current value per label set.
|
||||
}
|
||||
|
||||
// ttlCounterEntry holds the current value of a single label set.
|
||||
type ttlCounterEntry struct {
|
||||
labelValues []string // Label values in exposition order.
|
||||
value float64 // Current counter value.
|
||||
lastUpdate time.Time // Time of the last update.
|
||||
}
|
||||
|
||||
// TTLCounter is a handle to a single label set of a TTLCounterVec.
|
||||
type TTLCounter struct {
|
||||
vec *TTLCounterVec
|
||||
entry *ttlCounterEntry
|
||||
}
|
||||
|
||||
// Set stores the current absolute value of the counter.
|
||||
func (c *TTLCounter) Set(value float64) {
|
||||
c.vec.mu.Lock()
|
||||
defer c.vec.mu.Unlock()
|
||||
c.entry.value = value
|
||||
}
|
||||
|
||||
// NewTTLCounterVec creates a new TTLCounterVec and registers it using promauto.
|
||||
func NewTTLCounterVec(opts prometheus.CounterOpts, labelNames []string, ttl time.Duration) *TTLCounterVec {
|
||||
c := &TTLCounterVec{
|
||||
desc: prometheus.NewDesc(
|
||||
prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.ConstLabels,
|
||||
),
|
||||
labelNames: labelNames,
|
||||
ttl: ttl,
|
||||
values: make(map[string]*ttlCounterEntry),
|
||||
}
|
||||
prometheus.MustRegister(c)
|
||||
return c
|
||||
}
|
||||
|
||||
// With returns the counter handle for the given label set and records the current
|
||||
// time as the last update for those labels.
|
||||
func (t *TTLCounterVec) With(labels prometheus.Labels) *TTLCounter {
|
||||
key := labelsKey(labels)
|
||||
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
entry, ok := t.values[key]
|
||||
if !ok {
|
||||
labelValues := make([]string, len(t.labelNames))
|
||||
for i, name := range t.labelNames {
|
||||
labelValues[i] = labels[name]
|
||||
}
|
||||
entry = &ttlCounterEntry{labelValues: labelValues}
|
||||
t.values[key] = entry
|
||||
}
|
||||
entry.lastUpdate = time.Now()
|
||||
|
||||
return &TTLCounter{vec: t, entry: entry}
|
||||
}
|
||||
|
||||
// Delete removes the metric associated with the given label set.
|
||||
func (t *TTLCounterVec) Delete(labels prometheus.Labels) bool {
|
||||
key := labelsKey(labels)
|
||||
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if _, ok := t.values[key]; !ok {
|
||||
return false
|
||||
}
|
||||
delete(t.values, key)
|
||||
return true
|
||||
}
|
||||
|
||||
// Cleanup deletes all label sets that have not been updated within the TTL duration.
|
||||
func (t *TTLCounterVec) Cleanup() {
|
||||
now := time.Now()
|
||||
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
for key, entry := range t.values {
|
||||
if now.Sub(entry.lastUpdate) > t.ttl {
|
||||
delete(t.values, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Describe implements prometheus.Collector.
|
||||
func (t *TTLCounterVec) Describe(ch chan<- *prometheus.Desc) {
|
||||
ch <- t.desc
|
||||
}
|
||||
|
||||
// Collect implements prometheus.Collector.
|
||||
func (t *TTLCounterVec) Collect(ch chan<- prometheus.Metric) {
|
||||
t.mu.RLock()
|
||||
defer t.mu.RUnlock()
|
||||
|
||||
for _, entry := range t.values {
|
||||
ch <- prometheus.MustNewConstMetric(t.desc, prometheus.CounterValue, entry.value, entry.labelValues...)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user