Added "callback" metrics, e.g. GaugeFunc.
Change-Id: I449b558207963ce60572bd04c8102f1db684dd4c
This commit is contained in:
parent
5122dc6cc0
commit
f9401ffab9
|
@ -147,3 +147,29 @@ func (m *CounterVec) WithLabelValues(lvs ...string) Counter {
|
||||||
func (m *CounterVec) With(labels Labels) Counter {
|
func (m *CounterVec) With(labels Labels) Counter {
|
||||||
return m.MetricVec.With(labels).(Counter)
|
return m.MetricVec.With(labels).(Counter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CounterFunc is a Counter whose value is determined at collect time by calling a
|
||||||
|
// provided function.
|
||||||
|
//
|
||||||
|
// To create CounterFunc instances, use NewCounterFunc.
|
||||||
|
type CounterFunc interface {
|
||||||
|
Metric
|
||||||
|
Collector
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCounterFunc creates a new CounterFunc based on the provided
|
||||||
|
// CounterOpts. The value reported is determined by calling the given function
|
||||||
|
// from within the Write method. Take into account that metric collection may
|
||||||
|
// happen concurrently. If that results in concurrent calls to Write, like in
|
||||||
|
// the case where a CounterFunc is directly registered with Prometheus, the
|
||||||
|
// provided function must be concurrency-safe. The function should also honor
|
||||||
|
// the contract for a Counter (values only go up, not down), but compliance will
|
||||||
|
// not be checked.
|
||||||
|
func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
|
||||||
|
return newValueFunc(NewDesc(
|
||||||
|
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||||
|
opts.Help,
|
||||||
|
nil,
|
||||||
|
opts.ConstLabels,
|
||||||
|
), CounterValue, function)
|
||||||
|
}
|
||||||
|
|
|
@ -29,14 +29,15 @@ func NewCallbackMetric(desc *prometheus.Desc, callback func() float64) *Callback
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Come up with a better example.
|
||||||
|
|
||||||
// CallbackMetric is an example for a user-defined Metric that exports the
|
// CallbackMetric is an example for a user-defined Metric that exports the
|
||||||
// result of a function call as a metric of type "untyped" without any
|
// result of a function call as a metric of type "untyped" without any
|
||||||
// labels. It uses SelfCollector to turn the Metric into a Collector so that it
|
// labels. It uses SelfCollector to turn the Metric into a Collector so that it
|
||||||
// can be registered with Prometheus.
|
// can be registered with Prometheus.
|
||||||
//
|
//
|
||||||
// Note that this is a pretty low-level approach. A more high-level approach is
|
// Note that this example is pretty much academic as the prometheus package
|
||||||
// to implement a Collector directly and not an individual Metric, see the
|
// already provides an UntypedFunc type.
|
||||||
// Collector examples.
|
|
||||||
type CallbackMetric struct {
|
type CallbackMetric struct {
|
||||||
prometheus.SelfCollector
|
prometheus.SelfCollector
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
@ -72,6 +73,24 @@ func ExampleGaugeVec() {
|
||||||
opsQueued.With(prometheus.Labels{"type": "delete", "user": "alice"}).Inc()
|
opsQueued.With(prometheus.Labels{"type": "delete", "user": "alice"}).Inc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleGaugeFunc() {
|
||||||
|
if _, err := prometheus.Register(prometheus.NewGaugeFunc(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Subsystem: "runtime",
|
||||||
|
Name: "goroutines_count",
|
||||||
|
Help: "Number of goroutines that currently exist.",
|
||||||
|
},
|
||||||
|
func() float64 { return float64(runtime.NumGoroutine()) },
|
||||||
|
)); err == nil {
|
||||||
|
fmt.Println("GaugeFunc 'goroutines_count' registered.\n")
|
||||||
|
}
|
||||||
|
// Note that the count of goroutines is a gauge (and not a counter) as
|
||||||
|
// it can go up and down.
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// GaugeFunc 'goroutines_count' registered.
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleCounter() {
|
func ExampleCounter() {
|
||||||
pushCounter := prometheus.NewCounter(prometheus.CounterOpts{
|
pushCounter := prometheus.NewCounter(prometheus.CounterOpts{
|
||||||
Name: "repository_pushes", // Note: No help string...
|
Name: "repository_pushes", // Note: No help string...
|
||||||
|
|
|
@ -121,3 +121,27 @@ func (m *GaugeVec) WithLabelValues(lvs ...string) Gauge {
|
||||||
func (m *GaugeVec) With(labels Labels) Gauge {
|
func (m *GaugeVec) With(labels Labels) Gauge {
|
||||||
return m.MetricVec.With(labels).(Gauge)
|
return m.MetricVec.With(labels).(Gauge)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GaugeFunc is a Gauge whose value is determined at collect time by calling a
|
||||||
|
// provided function.
|
||||||
|
//
|
||||||
|
// To create GaugeFunc instances, use NewGaugeFunc.
|
||||||
|
type GaugeFunc interface {
|
||||||
|
Metric
|
||||||
|
Collector
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGaugeFunc creates a new GaugeFunc based on the provided GaugeOpts. The
|
||||||
|
// value reported is determined by calling the given function from within the
|
||||||
|
// Write method. Take into account that metric collection may happen
|
||||||
|
// concurrently. If that results in concurrent calls to Write, like in the case
|
||||||
|
// where a GaugeFunc is directly registered with Prometheus, the provided
|
||||||
|
// function must be concurrency-safe.
|
||||||
|
func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc {
|
||||||
|
return newValueFunc(NewDesc(
|
||||||
|
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||||
|
opts.Help,
|
||||||
|
nil,
|
||||||
|
opts.ConstLabels,
|
||||||
|
), GaugeValue, function)
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"testing/quick"
|
"testing/quick"
|
||||||
|
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func listenGaugeStream(vals, result chan float64, done chan struct{}) {
|
func listenGaugeStream(vals, result chan float64, done chan struct{}) {
|
||||||
|
@ -156,3 +158,25 @@ func TestGaugeVecConcurrency(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGaugeFunc(t *testing.T) {
|
||||||
|
gf := NewGaugeFunc(
|
||||||
|
GaugeOpts{
|
||||||
|
Name: "test_name",
|
||||||
|
Help: "test help",
|
||||||
|
ConstLabels: Labels{"a": "1", "b": "2"},
|
||||||
|
},
|
||||||
|
func() float64 { return 3.1415 },
|
||||||
|
)
|
||||||
|
|
||||||
|
if expected, got := `Desc{fqName: "test_name", help: "test help", constLabels: {a="1",b="2"}, variableLabels: []}`, gf.Desc().String(); expected != got {
|
||||||
|
t.Errorf("expected %q, got %q", expected, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &dto.Metric{}
|
||||||
|
gf.Write(m)
|
||||||
|
|
||||||
|
if expected, got := `label:<name:"a" value:"1" > label:<name:"b" value:"2" > gauge:<value:3.1415 > `, m.String(); expected != got {
|
||||||
|
t.Errorf("expected %q, got %q", expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -119,3 +119,27 @@ func (m *UntypedVec) WithLabelValues(lvs ...string) Untyped {
|
||||||
func (m *UntypedVec) With(labels Labels) Untyped {
|
func (m *UntypedVec) With(labels Labels) Untyped {
|
||||||
return m.MetricVec.With(labels).(Untyped)
|
return m.MetricVec.With(labels).(Untyped)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UntypedFunc is an Untyped whose value is determined at collect time by
|
||||||
|
// calling a provided function.
|
||||||
|
//
|
||||||
|
// To create UntypedFunc instances, use NewUntypedFunc.
|
||||||
|
type UntypedFunc interface {
|
||||||
|
Metric
|
||||||
|
Collector
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUntypedFunc creates a new UntypedFunc based on the provided
|
||||||
|
// UntypedOpts. The value reported is determined by calling the given function
|
||||||
|
// from within the Write method. Take into account that metric collection may
|
||||||
|
// happen concurrently. If that results in concurrent calls to Write, like in
|
||||||
|
// the case where an UntypedFunc is directly registered with Prometheus, the
|
||||||
|
// provided function must be concurrency-safe.
|
||||||
|
func NewUntypedFunc(opts UntypedOpts, function func() float64) UntypedFunc {
|
||||||
|
return newValueFunc(NewDesc(
|
||||||
|
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||||
|
opts.Help,
|
||||||
|
nil,
|
||||||
|
opts.ConstLabels,
|
||||||
|
), UntypedValue, function)
|
||||||
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ type value struct {
|
||||||
labelPairs []*dto.LabelPair
|
labelPairs []*dto.LabelPair
|
||||||
}
|
}
|
||||||
|
|
||||||
// newValue returns a newly allocated Value with the given Desc, ValueType,
|
// newValue returns a newly allocated value with the given Desc, ValueType,
|
||||||
// sample value and label values. It panics if the number of label
|
// sample value and label values. It panics if the number of label
|
||||||
// values is different from the number of variable labels in Desc.
|
// values is different from the number of variable labels in Desc.
|
||||||
func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...string) *value {
|
func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...string) *value {
|
||||||
|
@ -106,6 +106,45 @@ func (v *value) Write(out *dto.Metric) {
|
||||||
populateMetric(v.valType, val, v.labelPairs, out)
|
populateMetric(v.valType, val, v.labelPairs, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// valueFunc is a generic metric for simple values retrieved on collect time
|
||||||
|
// from a function. It implements Metric and Collector. Its effective type is
|
||||||
|
// determined by ValueType. This is a low-level building block used by the
|
||||||
|
// library to back the implementations of CounterFunc, GaugeFunc, and
|
||||||
|
// UntypedFunc.
|
||||||
|
type valueFunc struct {
|
||||||
|
SelfCollector
|
||||||
|
|
||||||
|
desc *Desc
|
||||||
|
valType ValueType
|
||||||
|
function func() float64
|
||||||
|
labelPairs []*dto.LabelPair
|
||||||
|
}
|
||||||
|
|
||||||
|
// newValueFunc returns a newly allocated valueFunc with the given Desc and
|
||||||
|
// ValueType. The value reported is determined by calling the given function
|
||||||
|
// from within the Write method. Take into account that metric collection may
|
||||||
|
// happen concurrently. If that results in concurrent calls to Write, like in
|
||||||
|
// the case where a valueFunc is directly registered with Prometheus, the
|
||||||
|
// provided function must be concurrency-safe.
|
||||||
|
func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc {
|
||||||
|
result := &valueFunc{
|
||||||
|
desc: desc,
|
||||||
|
valType: valueType,
|
||||||
|
function: function,
|
||||||
|
labelPairs: makeLabelPairs(desc, nil),
|
||||||
|
}
|
||||||
|
result.Init(result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *valueFunc) Desc() *Desc {
|
||||||
|
return v.desc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *valueFunc) Write(out *dto.Metric) {
|
||||||
|
populateMetric(v.valType, v.function(), v.labelPairs, out)
|
||||||
|
}
|
||||||
|
|
||||||
// NewConstMetric returns a metric with one fixed value that cannot be
|
// NewConstMetric returns a metric with one fixed value that cannot be
|
||||||
// changed. Users of this package will not have much use for it in regular
|
// changed. Users of this package will not have much use for it in regular
|
||||||
// operations. However, when implementing custom Collectors, it is useful as a
|
// operations. However, when implementing custom Collectors, it is useful as a
|
||||||
|
|
Loading…
Reference in New Issue