mirror of https://github.com/coder/coder.git
95 lines
2.3 KiB
Go
95 lines
2.3 KiB
Go
package prometheusmetrics
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
// CachedGaugeVec is a wrapper for the prometheus.GaugeVec which allows
|
|
// for staging changes in the metrics vector. Calling "WithLabelValues(...)"
|
|
// will update the internal gauge value, but it will not be returned by
|
|
// "Collect(...)" until the "Commit()" method is called. The "Commit()" method
|
|
// resets the internal gauge and applies all staged changes to it.
|
|
//
|
|
// The Use of CachedGaugeVec is recommended for use cases when there is a risk
|
|
// that the Prometheus collector receives incomplete metrics, collected
|
|
// in the middle of metrics recalculation, between "Reset()" and the last
|
|
// "WithLabelValues()" call.
|
|
type CachedGaugeVec struct {
|
|
m sync.Mutex
|
|
|
|
gaugeVec *prometheus.GaugeVec
|
|
records []vectorRecord
|
|
}
|
|
|
|
var _ prometheus.Collector = new(CachedGaugeVec)
|
|
|
|
type VectorOperation int
|
|
|
|
const (
|
|
VectorOperationAdd VectorOperation = iota
|
|
VectorOperationSet
|
|
)
|
|
|
|
type vectorRecord struct {
|
|
operation VectorOperation
|
|
value float64
|
|
labelValues []string
|
|
}
|
|
|
|
func NewCachedGaugeVec(gaugeVec *prometheus.GaugeVec) *CachedGaugeVec {
|
|
return &CachedGaugeVec{
|
|
gaugeVec: gaugeVec,
|
|
}
|
|
}
|
|
|
|
func (v *CachedGaugeVec) Describe(desc chan<- *prometheus.Desc) {
|
|
v.gaugeVec.Describe(desc)
|
|
}
|
|
|
|
func (v *CachedGaugeVec) Collect(ch chan<- prometheus.Metric) {
|
|
v.m.Lock()
|
|
defer v.m.Unlock()
|
|
|
|
v.gaugeVec.Collect(ch)
|
|
}
|
|
|
|
func (v *CachedGaugeVec) WithLabelValues(operation VectorOperation, value float64, labelValues ...string) {
|
|
switch operation {
|
|
case VectorOperationAdd, VectorOperationSet:
|
|
default:
|
|
panic("unsupported vector operation")
|
|
}
|
|
|
|
v.m.Lock()
|
|
defer v.m.Unlock()
|
|
|
|
v.records = append(v.records, vectorRecord{
|
|
operation: operation,
|
|
value: value,
|
|
labelValues: labelValues,
|
|
})
|
|
}
|
|
|
|
// Commit will set the internal value as the cached value to return from "Collect()".
|
|
// The internal metric value is completely reset, so the caller should expect
|
|
// the gauge to be empty for the next 'WithLabelValues' values.
|
|
func (v *CachedGaugeVec) Commit() {
|
|
v.m.Lock()
|
|
defer v.m.Unlock()
|
|
|
|
v.gaugeVec.Reset()
|
|
for _, record := range v.records {
|
|
g := v.gaugeVec.WithLabelValues(record.labelValues...)
|
|
switch record.operation {
|
|
case VectorOperationAdd:
|
|
g.Add(record.value)
|
|
case VectorOperationSet:
|
|
g.Set(record.value)
|
|
}
|
|
}
|
|
|
|
v.records = nil
|
|
}
|