timer: Added support for exemplars. (#1233)
Signed-off-by: bwplotka <bwplotka@gmail.com>
This commit is contained in:
parent
232b949d1f
commit
e79d7e71ce
|
@ -23,7 +23,9 @@ type Timer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTimer creates a new Timer. The provided Observer is used to observe a
|
// NewTimer creates a new Timer. The provided Observer is used to observe a
|
||||||
// duration in seconds. Timer is usually used to time a function call in the
|
// duration in seconds. If the Observer implements ExemplarObserver, passing exemplar
|
||||||
|
// later on will be also supported.
|
||||||
|
// Timer is usually used to time a function call in the
|
||||||
// following way:
|
// following way:
|
||||||
//
|
//
|
||||||
// func TimeMe() {
|
// func TimeMe() {
|
||||||
|
@ -31,6 +33,14 @@ type Timer struct {
|
||||||
// defer timer.ObserveDuration()
|
// defer timer.ObserveDuration()
|
||||||
// // Do actual work.
|
// // Do actual work.
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
|
// or
|
||||||
|
//
|
||||||
|
// func TimeMeWithExemplar() {
|
||||||
|
// timer := NewTimer(myHistogram)
|
||||||
|
// defer timer.ObserveDurationWithExemplar(exemplar)
|
||||||
|
// // Do actual work.
|
||||||
|
// }
|
||||||
func NewTimer(o Observer) *Timer {
|
func NewTimer(o Observer) *Timer {
|
||||||
return &Timer{
|
return &Timer{
|
||||||
begin: time.Now(),
|
begin: time.Now(),
|
||||||
|
@ -53,3 +63,19 @@ func (t *Timer) ObserveDuration() time.Duration {
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ObserveDurationWithExemplar is like ObserveDuration, but it will also
|
||||||
|
// observe exemplar with the duration unless exemplar is nil or provided Observer can't
|
||||||
|
// be casted to ExemplarObserver.
|
||||||
|
func (t *Timer) ObserveDurationWithExemplar(exemplar Labels) time.Duration {
|
||||||
|
d := time.Since(t.begin)
|
||||||
|
eo, ok := t.observer.(ExemplarObserver)
|
||||||
|
if ok && exemplar != nil {
|
||||||
|
eo.ObserveWithExemplar(d.Seconds(), exemplar)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
if t.observer != nil {
|
||||||
|
t.observer.Observe(d.Seconds())
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
|
@ -14,8 +14,11 @@
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,6 +55,54 @@ func TestTimerObserve(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTimerObserveWithExemplar(t *testing.T) {
|
||||||
|
var (
|
||||||
|
exemplar = Labels{"foo": "bar"}
|
||||||
|
his = NewHistogram(HistogramOpts{Name: "test_histogram"})
|
||||||
|
sum = NewSummary(SummaryOpts{Name: "test_summary"})
|
||||||
|
gauge = NewGauge(GaugeOpts{Name: "test_gauge"})
|
||||||
|
)
|
||||||
|
|
||||||
|
func() {
|
||||||
|
hisTimer := NewTimer(his)
|
||||||
|
sumTimer := NewTimer(sum)
|
||||||
|
gaugeTimer := NewTimer(ObserverFunc(gauge.Set))
|
||||||
|
defer hisTimer.ObserveDurationWithExemplar(exemplar)
|
||||||
|
// Gauges and summaries does not implement ExemplarObserver, so we expect them to ignore exemplar.
|
||||||
|
defer sumTimer.ObserveDurationWithExemplar(exemplar)
|
||||||
|
defer gaugeTimer.ObserveDurationWithExemplar(exemplar)
|
||||||
|
}()
|
||||||
|
|
||||||
|
m := &dto.Metric{}
|
||||||
|
his.Write(m)
|
||||||
|
if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got {
|
||||||
|
t.Errorf("want %d observations for histogram, got %d", want, got)
|
||||||
|
}
|
||||||
|
var got []*dto.LabelPair
|
||||||
|
for _, b := range m.GetHistogram().GetBucket() {
|
||||||
|
if b.Exemplar != nil {
|
||||||
|
got = b.Exemplar.GetLabel()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
want := []*dto.LabelPair{{Name: proto.String("foo"), Value: proto.String("bar")}}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("expected %v exemplar labels, got %v", want, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Reset()
|
||||||
|
sum.Write(m)
|
||||||
|
if want, got := uint64(1), m.GetSummary().GetSampleCount(); want != got {
|
||||||
|
t.Errorf("want %d observations for summary, got %d", want, got)
|
||||||
|
}
|
||||||
|
m.Reset()
|
||||||
|
gauge.Write(m)
|
||||||
|
if got := m.GetGauge().GetValue(); got <= 0 {
|
||||||
|
t.Errorf("want value > 0 for gauge, got %f", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTimerEmpty(t *testing.T) {
|
func TestTimerEmpty(t *testing.T) {
|
||||||
emptyTimer := NewTimer(nil)
|
emptyTimer := NewTimer(nil)
|
||||||
emptyTimer.ObserveDuration()
|
emptyTimer.ObserveDuration()
|
||||||
|
|
Loading…
Reference in New Issue