2019-04-11 12:59:53 +03:00
|
|
|
package metrics
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
|
|
|
// NewGauge registers and returns gauge with the given name, which calls f
|
|
|
|
// to obtain gauge value.
|
|
|
|
//
|
|
|
|
// name must be valid Prometheus-compatible metric with possible labels.
|
|
|
|
// For instance,
|
|
|
|
//
|
|
|
|
// * foo
|
|
|
|
// * foo{bar="baz"}
|
|
|
|
// * foo{bar="baz",aaa="b"}
|
|
|
|
//
|
|
|
|
// f must be safe for concurrent calls.
|
|
|
|
//
|
|
|
|
// The returned gauge is safe to use from concurrent goroutines.
|
|
|
|
func NewGauge(name string, f func() float64) *Gauge {
|
2019-04-15 15:34:02 +03:00
|
|
|
if f == nil {
|
|
|
|
panic(fmt.Errorf("BUG: f cannot be nil"))
|
|
|
|
}
|
2019-04-11 12:59:53 +03:00
|
|
|
g := &Gauge{
|
|
|
|
f: f,
|
|
|
|
}
|
|
|
|
registerMetric(name, g)
|
|
|
|
return g
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gauge is a float64 gauge.
|
2019-04-15 15:22:58 +03:00
|
|
|
//
|
|
|
|
// See also Counter, which could be used as a gauge with Set and Dec calls.
|
2019-04-11 12:59:53 +03:00
|
|
|
type Gauge struct {
|
|
|
|
f func() float64
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get returns the current value for g.
|
|
|
|
func (g *Gauge) Get() float64 {
|
|
|
|
return g.f()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *Gauge) marshalTo(prefix string, w io.Writer) {
|
|
|
|
v := g.f()
|
|
|
|
if float64(int64(v)) == v {
|
|
|
|
// Marshal integer values without scientific notations
|
|
|
|
fmt.Fprintf(w, "%s %d\n", prefix, int64(v))
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, "%s %g\n", prefix, v)
|
|
|
|
}
|
|
|
|
}
|
2019-04-15 15:34:02 +03:00
|
|
|
|
|
|
|
// GetOrCreateGauge returns registered gauge with the given name
|
|
|
|
// or creates new gauge if the registry doesn't contain gauge with
|
|
|
|
// the given name.
|
|
|
|
//
|
|
|
|
// name must be valid Prometheus-compatible metric with possible lables.
|
|
|
|
// For instance,
|
|
|
|
//
|
|
|
|
// * foo
|
|
|
|
// * foo{bar="baz"}
|
|
|
|
// * foo{bar="baz",aaa="b"}
|
|
|
|
//
|
|
|
|
// The returned gauge is safe to use from concurrent goroutines.
|
|
|
|
//
|
|
|
|
// Performance tip: prefer NewGauge instead of GetOrCreateGauge.
|
|
|
|
func GetOrCreateGauge(name string, f func() float64) *Gauge {
|
|
|
|
metricsMapLock.Lock()
|
|
|
|
nm := metricsMap[name]
|
|
|
|
metricsMapLock.Unlock()
|
|
|
|
if nm == nil {
|
|
|
|
// Slow path - create and register missing gauge.
|
|
|
|
if f == nil {
|
|
|
|
panic(fmt.Errorf("BUG: f cannot be nil"))
|
|
|
|
}
|
|
|
|
if err := validateMetric(name); err != nil {
|
|
|
|
panic(fmt.Errorf("BUG: invalid metric name %q: %s", name, err))
|
|
|
|
}
|
|
|
|
nmNew := &namedMetric{
|
|
|
|
name: name,
|
|
|
|
metric: &Gauge{
|
|
|
|
f: f,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
metricsMapLock.Lock()
|
|
|
|
nm = metricsMap[name]
|
|
|
|
if nm == nil {
|
|
|
|
nm = nmNew
|
|
|
|
metricsMap[name] = nm
|
|
|
|
metricsList = append(metricsList, nm)
|
|
|
|
}
|
|
|
|
metricsMapLock.Unlock()
|
|
|
|
}
|
|
|
|
g, ok := nm.metric.(*Gauge)
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Errorf("BUG: metric %q isn't a Gauge. It is %T", name, nm.metric))
|
|
|
|
}
|
|
|
|
return g
|
|
|
|
}
|