Skip to content

Commit 5842d46

Browse files
craig[bot]Andrew Werner
craig[bot]
and
Andrew Werner
committed
Merge #37248
37248: util/metric: make Rate into a real metric r=ajwerner a=ajwerner The metric package had a Rate type to track an exponential weighted moving average for a Rate but it was unclear how a caller would use it as a metric in a metric struct. This PR makes that Rate type into a real metric in anticipation of using it to track throughputs. Release note: None Co-authored-by: Andrew Werner <[email protected]>
2 parents ff969dd + 68f0bb7 commit 5842d46

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

pkg/server/status/recorder.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,8 @@ func extractValue(mtr interface{}) (float64, error) {
541541
return float64(mtr.Count()), nil
542542
case *metric.Gauge:
543543
return float64(mtr.Value()), nil
544+
case *metric.Rate:
545+
return mtr.Value(), nil
544546
case *metric.GaugeFloat64:
545547
return mtr.Value(), nil
546548
default:

pkg/util/metric/metric.go

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
"github.com/codahale/hdrhistogram"
2828
"github.com/gogo/protobuf/proto"
2929
prometheusgo "github.com/prometheus/client_model/go"
30-
"github.com/rcrowley/go-metrics"
30+
metrics "github.com/rcrowley/go-metrics"
3131
)
3232

3333
const (
@@ -125,16 +125,19 @@ var _ Iterable = &Gauge{}
125125
var _ Iterable = &GaugeFloat64{}
126126
var _ Iterable = &Counter{}
127127
var _ Iterable = &Histogram{}
128+
var _ Iterable = &Rate{}
128129

129130
var _ json.Marshaler = &Gauge{}
130131
var _ json.Marshaler = &GaugeFloat64{}
131132
var _ json.Marshaler = &Counter{}
132133
var _ json.Marshaler = &Registry{}
134+
var _ json.Marshaler = &Rate{}
133135

134136
var _ PrometheusExportable = &Gauge{}
135137
var _ PrometheusExportable = &GaugeFloat64{}
136138
var _ PrometheusExportable = &Counter{}
137139
var _ PrometheusExportable = &Histogram{}
140+
var _ PrometheusExportable = &Rate{}
138141

139142
type periodic interface {
140143
nextTick() time.Time
@@ -453,7 +456,7 @@ func (g *GaugeFloat64) GetType() *prometheusgo.MetricType {
453456
return prometheusgo.MetricType_GAUGE.Enum()
454457
}
455458

456-
// Inspect calls the given closure with the empty string and itself.
459+
// Inspect calls the given closure with itself.
457460
func (g *GaugeFloat64) Inspect(f func(interface{})) { f(g) }
458461

459462
// MarshalJSON marshals to JSON.
@@ -478,6 +481,7 @@ func (g *GaugeFloat64) GetMetadata() Metadata {
478481

479482
// A Rate is a exponential weighted moving average.
480483
type Rate struct {
484+
Metadata
481485
mu syncutil.Mutex // protects fields below
482486
curSum float64
483487
wrapped ewma.MovingAverage
@@ -487,20 +491,48 @@ type Rate struct {
487491

488492
// NewRate creates an EWMA rate on the given timescale. Timescales at
489493
// or below 2s are illegal and will cause a panic.
490-
func NewRate(timescale time.Duration) *Rate {
494+
func NewRate(metadata Metadata, timescale time.Duration) *Rate {
491495
const tickInterval = time.Second
492496
if timescale <= 2*time.Second {
493497
panic(fmt.Sprintf("EWMA with per-second ticks makes no sense on timescale %s", timescale))
494498
}
495499
avgAge := float64(timescale) / float64(2*tickInterval)
496-
497500
return &Rate{
501+
Metadata: metadata,
498502
interval: tickInterval,
499503
nextT: now(),
500504
wrapped: ewma.NewMovingAverage(avgAge),
501505
}
502506
}
503507

508+
// GetType returns the prometheus type enum for this metric.
509+
func (e *Rate) GetType() *prometheusgo.MetricType {
510+
return prometheusgo.MetricType_GAUGE.Enum()
511+
}
512+
513+
// Inspect calls the given closure with itself.
514+
func (e *Rate) Inspect(f func(interface{})) { f(e) }
515+
516+
// MarshalJSON marshals to JSON.
517+
func (e *Rate) MarshalJSON() ([]byte, error) {
518+
return json.Marshal(e.Value())
519+
}
520+
521+
// ToPrometheusMetric returns a filled-in prometheus metric of the right type.
522+
func (e *Rate) ToPrometheusMetric() *prometheusgo.Metric {
523+
return &prometheusgo.Metric{
524+
Gauge: &prometheusgo.Gauge{Value: proto.Float64(e.Value())},
525+
}
526+
}
527+
528+
// GetMetadata returns the metric's metadata including the Prometheus
529+
// MetricType.
530+
func (e *Rate) GetMetadata() Metadata {
531+
baseMetadata := e.Metadata
532+
baseMetadata.MetricType = prometheusgo.MetricType_GAUGE
533+
return baseMetadata
534+
}
535+
504536
// Value returns the current value of the Rate.
505537
func (e *Rate) Value() float64 {
506538
e.mu.Lock()

pkg/util/metric/metric_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ func TestGaugeFloat64(t *testing.T) {
7575
testMarshal(t, g, "10.4")
7676
}
7777

78+
func TestRate(t *testing.T) {
79+
r := NewRate(emptyMetadata, time.Minute)
80+
r.Add(0)
81+
if v := r.Value(); v != 0 {
82+
t.Fatalf("unexpected value: %f", v)
83+
}
84+
testMarshal(t, r, "0")
85+
}
86+
7887
func TestCounter(t *testing.T) {
7988
c := NewCounter(emptyMetadata)
8089
c.Inc(90)
@@ -164,7 +173,7 @@ func TestRateRotate(t *testing.T) {
164173
defer TestingSetNow(nil)()
165174
setNow(0)
166175
const interval = 10 * time.Second
167-
r := NewRate(interval)
176+
r := NewRate(emptyMetadata, interval)
168177

169178
// Skip the warmup phase of the wrapped EWMA for this test.
170179
for i := 0; i < 100; i++ {

0 commit comments

Comments
 (0)