metrics: fix timer, remove interfaces and nil-implementations

This commit is contained in:
Martin Holst Swende 2024-11-27 02:50:56 +01:00
parent 01cfef29ef
commit a6038c67e7
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
13 changed files with 49 additions and 84 deletions

View file

@ -881,7 +881,7 @@ func (q *queue) DeliverReceipts(id string, receiptList [][]*types.Receipt, recei
// to access the queue, so they already need a lock anyway. // to access the queue, so they already need a lock anyway.
func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header,
taskQueue *prque.Prque[int64, *types.Header], pendPool map[string]*fetchRequest, taskQueue *prque.Prque[int64, *types.Header], pendPool map[string]*fetchRequest,
reqTimer metrics.Timer, resInMeter, resDropMeter *metrics.Meter, reqTimer *metrics.Timer, resInMeter, resDropMeter *metrics.Meter,
results int, validate func(index int, header *types.Header) error, results int, validate func(index int, header *types.Header) error,
reconstruct func(index int, result *fetchResult)) (int, error) { reconstruct func(index int, result *fetchResult)) (int, error) {
// Short circuit if the data was never requested // Short circuit if the data was never requested

View file

@ -14,7 +14,7 @@ var (
//PauseQuantiles Histogram //PauseQuantiles Histogram
PauseTotal *Gauge PauseTotal *Gauge
} }
ReadGCStats Timer ReadGCStats *Timer
} }
gcStats debug.GCStats gcStats debug.GCStats
) )

View file

@ -155,7 +155,7 @@ func (exp *exp) publishMeter(name string, metric *metrics.Meter) {
exp.getFloat(name + ".mean").Set(m.RateMean()) exp.getFloat(name + ".mean").Set(m.RateMean())
} }
func (exp *exp) publishTimer(name string, metric metrics.Timer) { func (exp *exp) publishTimer(name string, metric *metrics.Timer) {
t := metric.Snapshot() t := metric.Snapshot()
ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
exp.getInt(name + ".count").Set(t.Count()) exp.getInt(name + ".count").Set(t.Count())
@ -202,7 +202,7 @@ func (exp *exp) syncToExpvar() {
exp.publishHistogram(name, i) exp.publishHistogram(name, i)
case *metrics.Meter: case *metrics.Meter:
exp.publishMeter(name, i) exp.publishMeter(name, i)
case metrics.Timer: case *metrics.Timer:
exp.publishTimer(name, i) exp.publishTimer(name, i)
case metrics.ResettingTimer: case metrics.ResettingTimer:
exp.publishResettingTimer(name, i) exp.publishResettingTimer(name, i)

View file

@ -94,7 +94,7 @@ func graphite(c *GraphiteConfig) error {
fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, m.Rate5(), now) fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, m.Rate5(), now)
fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, m.Rate15(), now) fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, m.Rate15(), now)
fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, m.RateMean(), now) fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, m.RateMean(), now)
case Timer: case *Timer:
t := metric.Snapshot() t := metric.Snapshot()
ps := t.Percentiles(c.Percentiles) ps := t.Percentiles(c.Percentiles)
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, t.Count(), now) fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, t.Count(), now)

View file

@ -19,7 +19,6 @@ package metrics
// compile-time checks that interfaces are implemented. // compile-time checks that interfaces are implemented.
var ( var (
_ HistogramSnapshot = (*emptySnapshot)(nil) _ HistogramSnapshot = (*emptySnapshot)(nil)
_ TimerSnapshot = (*emptySnapshot)(nil)
) )
type emptySnapshot struct{} type emptySnapshot struct{}

View file

@ -73,7 +73,7 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf
"mean": ms.RateMean(), "mean": ms.RateMean(),
} }
return measurement, fields return measurement, fields
case metrics.Timer: case *metrics.Timer:
ms := metric.Snapshot() ms := metric.Snapshot()
ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999})

View file

@ -58,7 +58,7 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) {
l.Printf(" 5-min rate: %12.2f\n", m.Rate5()) l.Printf(" 5-min rate: %12.2f\n", m.Rate5())
l.Printf(" 15-min rate: %12.2f\n", m.Rate15()) l.Printf(" 15-min rate: %12.2f\n", m.Rate15())
l.Printf(" mean rate: %12.2f\n", m.RateMean()) l.Printf(" mean rate: %12.2f\n", m.RateMean())
case Timer: case *Timer:
t := metric.Snapshot() t := metric.Snapshot()
ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
l.Printf("timer %s\n", name) l.Printf("timer %s\n", name)

View file

@ -94,7 +94,7 @@ func (c *OpenTSDBConfig) writeRegistry(w io.Writer, now int64, shortHostname str
fmt.Fprintf(w, "put %s.%s.five-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate5(), shortHostname) fmt.Fprintf(w, "put %s.%s.five-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate5(), shortHostname)
fmt.Fprintf(w, "put %s.%s.fifteen-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate15(), shortHostname) fmt.Fprintf(w, "put %s.%s.fifteen-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate15(), shortHostname)
fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, m.RateMean(), shortHostname) fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, m.RateMean(), shortHostname)
case Timer: case *Timer:
t := metric.Snapshot() t := metric.Snapshot()
ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, t.Count(), shortHostname) fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, t.Count(), shortHostname)

View file

@ -65,7 +65,7 @@ func (c *collector) Add(name string, i any) error {
c.addHistogram(name, m.Snapshot()) c.addHistogram(name, m.Snapshot())
case *metrics.Meter: case *metrics.Meter:
c.addMeter(name, m.Snapshot()) c.addMeter(name, m.Snapshot())
case metrics.Timer: case *metrics.Timer:
c.addTimer(name, m.Snapshot()) c.addTimer(name, m.Snapshot())
case metrics.ResettingTimer: case metrics.ResettingTimer:
c.addResettingTimer(name, m.Snapshot()) c.addResettingTimer(name, m.Snapshot())
@ -110,7 +110,7 @@ func (c *collector) addMeter(name string, m *metrics.MeterSnapshot) {
c.writeGaugeCounter(name, m.Count()) c.writeGaugeCounter(name, m.Count())
} }
func (c *collector) addTimer(name string, m metrics.TimerSnapshot) { func (c *collector) addTimer(name string, m *metrics.TimerSnapshot) {
pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999} pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
ps := m.Percentiles(pv) ps := m.Percentiles(pv)
c.writeSummaryCounter(name, m.Count()) c.writeSummaryCounter(name, m.Count())

View file

@ -183,7 +183,7 @@ func (r *StandardRegistry) GetAll() map[string]map[string]interface{} {
values["5m.rate"] = m.Rate5() values["5m.rate"] = m.Rate5()
values["15m.rate"] = m.Rate15() values["15m.rate"] = m.Rate15()
values["mean.rate"] = m.RateMean() values["mean.rate"] = m.RateMean()
case Timer: case *Timer:
t := metric.Snapshot() t := metric.Snapshot()
ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
values["count"] = t.Count() values["count"] = t.Count()
@ -214,7 +214,7 @@ func (r *StandardRegistry) Unregister(name string) {
func (r *StandardRegistry) loadOrRegister(name string, i interface{}) (interface{}, bool, bool) { func (r *StandardRegistry) loadOrRegister(name string, i interface{}) (interface{}, bool, bool) {
switch i.(type) { switch i.(type) {
case *Counter, *CounterFloat64, *Gauge, *GaugeFloat64, *GaugeInfo, *Healthcheck, Histogram, *Meter, Timer, ResettingTimer: case *Counter, *CounterFloat64, *Gauge, *GaugeFloat64, *GaugeInfo, *Healthcheck, Histogram, *Meter, *Timer, ResettingTimer:
default: default:
return nil, false, false return nil, false, false
} }

View file

@ -56,7 +56,7 @@ func Syslog(r Registry, d time.Duration, w *syslog.Writer) {
m.Rate15(), m.Rate15(),
m.RateMean(), m.RateMean(),
)) ))
case Timer: case *Timer:
t := metric.Snapshot() t := metric.Snapshot()
ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
w.Info(fmt.Sprintf( w.Info(fmt.Sprintf(

View file

@ -5,51 +5,30 @@ import (
"time" "time"
) )
type TimerSnapshot interface {
HistogramSnapshot
Count() int64
Rate1() float64
Rate5() float64
Rate15() float64
RateMean() float64
}
// Timer capture the duration and rate of events.
type Timer interface {
Snapshot() TimerSnapshot
Stop()
Time(func())
UpdateSince(time.Time)
Update(time.Duration)
}
// GetOrRegisterTimer returns an existing Timer or constructs and registers a // GetOrRegisterTimer returns an existing Timer or constructs and registers a
// new StandardTimer. // new Timer.
// Be sure to unregister the meter from the registry once it is of no use to // Be sure to unregister the meter from the registry once it is of no use to
// allow for garbage collection. // allow for garbage collection.
func GetOrRegisterTimer(name string, r Registry) Timer { func GetOrRegisterTimer(name string, r Registry) *Timer {
if nil == r { if nil == r {
r = DefaultRegistry r = DefaultRegistry
} }
return r.GetOrRegister(name, NewTimer).(Timer) return r.GetOrRegister(name, NewTimer).(*Timer)
} }
// NewCustomTimer constructs a new StandardTimer from a Histogram and a Meter. // NewCustomTimer constructs a new Timer from a Histogram and a Meter.
// Be sure to call Stop() once the timer is of no use to allow for garbage collection. // Be sure to call Stop() once the timer is of no use to allow for garbage collection.
func NewCustomTimer(h Histogram, m *Meter) Timer { func NewCustomTimer(h Histogram, m *Meter) *Timer {
if !Enabled { return &Timer{
return NilTimer{}
}
return &StandardTimer{
histogram: h, histogram: h,
meter: m, meter: m,
} }
} }
// NewRegisteredTimer constructs and registers a new StandardTimer. // NewRegisteredTimer constructs and registers a new Timer.
// Be sure to unregister the meter from the registry once it is of no use to // Be sure to unregister the meter from the registry once it is of no use to
// allow for garbage collection. // allow for garbage collection.
func NewRegisteredTimer(name string, r Registry) Timer { func NewRegisteredTimer(name string, r Registry) *Timer {
c := NewTimer() c := NewTimer()
if nil == r { if nil == r {
r = DefaultRegistry r = DefaultRegistry
@ -58,60 +37,47 @@ func NewRegisteredTimer(name string, r Registry) Timer {
return c return c
} }
// NewTimer constructs a new StandardTimer using an exponentially-decaying // NewTimer constructs a new Timer using an exponentially-decaying
// sample with the same reservoir size and alpha as UNIX load averages. // sample with the same reservoir size and alpha as UNIX load averages.
// Be sure to call Stop() once the timer is of no use to allow for garbage collection. // Be sure to call Stop() once the timer is of no use to allow for garbage collection.
func NewTimer() Timer { func NewTimer() *Timer {
if !Enabled { return &Timer{
return NilTimer{}
}
return &StandardTimer{
histogram: NewHistogram(NewExpDecaySample(1028, 0.015)), histogram: NewHistogram(NewExpDecaySample(1028, 0.015)),
meter: NewMeter(), meter: NewMeter(),
} }
} }
// NilTimer is a no-op Timer. // Timer captures the duration and rate of events, using a Histogram and a Meter.
type NilTimer struct{} type Timer struct {
func (NilTimer) Snapshot() TimerSnapshot { return (*emptySnapshot)(nil) }
func (NilTimer) Stop() {}
func (NilTimer) Time(f func()) { f() }
func (NilTimer) Update(time.Duration) {}
func (NilTimer) UpdateSince(time.Time) {}
// StandardTimer is the standard implementation of a Timer and uses a Histogram
// and Meter.
type StandardTimer struct {
histogram Histogram histogram Histogram
meter *Meter meter *Meter
mutex sync.Mutex mutex sync.Mutex
} }
// Snapshot returns a read-only copy of the timer. // Snapshot returns a read-only copy of the timer.
func (t *StandardTimer) Snapshot() TimerSnapshot { func (t *Timer) Snapshot() *TimerSnapshot {
t.mutex.Lock() t.mutex.Lock()
defer t.mutex.Unlock() defer t.mutex.Unlock()
return &timerSnapshot{ return &TimerSnapshot{
histogram: t.histogram.Snapshot(), histogram: t.histogram.Snapshot(),
meter: t.meter.Snapshot(), meter: t.meter.Snapshot(),
} }
} }
// Stop stops the meter. // Stop stops the meter.
func (t *StandardTimer) Stop() { func (t *Timer) Stop() {
t.meter.Stop() t.meter.Stop()
} }
// Time record the duration of the execution of the given function. // Time record the duration of the execution of the given function.
func (t *StandardTimer) Time(f func()) { func (t *Timer) Time(f func()) {
ts := time.Now() ts := time.Now()
f() f()
t.Update(time.Since(ts)) t.Update(time.Since(ts))
} }
// Update the duration of an event, in nanoseconds. // Update the duration of an event, in nanoseconds.
func (t *StandardTimer) Update(d time.Duration) { func (t *Timer) Update(d time.Duration) {
t.mutex.Lock() t.mutex.Lock()
defer t.mutex.Unlock() defer t.mutex.Unlock()
t.histogram.Update(d.Nanoseconds()) t.histogram.Update(d.Nanoseconds())
@ -120,67 +86,67 @@ func (t *StandardTimer) Update(d time.Duration) {
// UpdateSince update the duration of an event that started at a time and ends now. // UpdateSince update the duration of an event that started at a time and ends now.
// The record uses nanoseconds. // The record uses nanoseconds.
func (t *StandardTimer) UpdateSince(ts time.Time) { func (t *Timer) UpdateSince(ts time.Time) {
t.Update(time.Since(ts)) t.Update(time.Since(ts))
} }
// timerSnapshot is a read-only copy of another Timer. // TimerSnapshot is a read-only copy of another Timer.
type timerSnapshot struct { type TimerSnapshot struct {
histogram HistogramSnapshot histogram HistogramSnapshot
meter *MeterSnapshot meter *MeterSnapshot
} }
// Count returns the number of events recorded at the time the snapshot was // Count returns the number of events recorded at the time the snapshot was
// taken. // taken.
func (t *timerSnapshot) Count() int64 { return t.histogram.Count() } func (t *TimerSnapshot) Count() int64 { return t.histogram.Count() }
// Max returns the maximum value at the time the snapshot was taken. // Max returns the maximum value at the time the snapshot was taken.
func (t *timerSnapshot) Max() int64 { return t.histogram.Max() } func (t *TimerSnapshot) Max() int64 { return t.histogram.Max() }
// Size returns the size of the sample at the time the snapshot was taken. // Size returns the size of the sample at the time the snapshot was taken.
func (t *timerSnapshot) Size() int { return t.histogram.Size() } func (t *TimerSnapshot) Size() int { return t.histogram.Size() }
// Mean returns the mean value at the time the snapshot was taken. // Mean returns the mean value at the time the snapshot was taken.
func (t *timerSnapshot) Mean() float64 { return t.histogram.Mean() } func (t *TimerSnapshot) Mean() float64 { return t.histogram.Mean() }
// Min returns the minimum value at the time the snapshot was taken. // Min returns the minimum value at the time the snapshot was taken.
func (t *timerSnapshot) Min() int64 { return t.histogram.Min() } func (t *TimerSnapshot) Min() int64 { return t.histogram.Min() }
// Percentile returns an arbitrary percentile of sampled values at the time the // Percentile returns an arbitrary percentile of sampled values at the time the
// snapshot was taken. // snapshot was taken.
func (t *timerSnapshot) Percentile(p float64) float64 { func (t *TimerSnapshot) Percentile(p float64) float64 {
return t.histogram.Percentile(p) return t.histogram.Percentile(p)
} }
// Percentiles returns a slice of arbitrary percentiles of sampled values at // Percentiles returns a slice of arbitrary percentiles of sampled values at
// the time the snapshot was taken. // the time the snapshot was taken.
func (t *timerSnapshot) Percentiles(ps []float64) []float64 { func (t *TimerSnapshot) Percentiles(ps []float64) []float64 {
return t.histogram.Percentiles(ps) return t.histogram.Percentiles(ps)
} }
// Rate1 returns the one-minute moving average rate of events per second at the // Rate1 returns the one-minute moving average rate of events per second at the
// time the snapshot was taken. // time the snapshot was taken.
func (t *timerSnapshot) Rate1() float64 { return t.meter.Rate1() } func (t *TimerSnapshot) Rate1() float64 { return t.meter.Rate1() }
// Rate5 returns the five-minute moving average rate of events per second at // Rate5 returns the five-minute moving average rate of events per second at
// the time the snapshot was taken. // the time the snapshot was taken.
func (t *timerSnapshot) Rate5() float64 { return t.meter.Rate5() } func (t *TimerSnapshot) Rate5() float64 { return t.meter.Rate5() }
// Rate15 returns the fifteen-minute moving average rate of events per second // Rate15 returns the fifteen-minute moving average rate of events per second
// at the time the snapshot was taken. // at the time the snapshot was taken.
func (t *timerSnapshot) Rate15() float64 { return t.meter.Rate15() } func (t *TimerSnapshot) Rate15() float64 { return t.meter.Rate15() }
// RateMean returns the meter's mean rate of events per second at the time the // RateMean returns the meter's mean rate of events per second at the time the
// snapshot was taken. // snapshot was taken.
func (t *timerSnapshot) RateMean() float64 { return t.meter.RateMean() } func (t *TimerSnapshot) RateMean() float64 { return t.meter.RateMean() }
// StdDev returns the standard deviation of the values at the time the snapshot // StdDev returns the standard deviation of the values at the time the snapshot
// was taken. // was taken.
func (t *timerSnapshot) StdDev() float64 { return t.histogram.StdDev() } func (t *TimerSnapshot) StdDev() float64 { return t.histogram.StdDev() }
// Sum returns the sum at the time the snapshot was taken. // Sum returns the sum at the time the snapshot was taken.
func (t *timerSnapshot) Sum() int64 { return t.histogram.Sum() } func (t *TimerSnapshot) Sum() int64 { return t.histogram.Sum() }
// Variance returns the variance of the values at the time the snapshot was // Variance returns the variance of the values at the time the snapshot was
// taken. // taken.
func (t *timerSnapshot) Variance() float64 { return t.histogram.Variance() } func (t *TimerSnapshot) Variance() float64 { return t.histogram.Variance() }

View file

@ -67,7 +67,7 @@ func WriteOnce(r Registry, w io.Writer) {
fmt.Fprintf(w, " 5-min rate: %12.2f\n", m.Rate5()) fmt.Fprintf(w, " 5-min rate: %12.2f\n", m.Rate5())
fmt.Fprintf(w, " 15-min rate: %12.2f\n", m.Rate15()) fmt.Fprintf(w, " 15-min rate: %12.2f\n", m.Rate15())
fmt.Fprintf(w, " mean rate: %12.2f\n", m.RateMean()) fmt.Fprintf(w, " mean rate: %12.2f\n", m.RateMean())
case Timer: case *Timer:
t := metric.Snapshot() t := metric.Snapshot()
ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
fmt.Fprintf(w, "timer %s\n", namedMetric.name) fmt.Fprintf(w, "timer %s\n", namedMetric.name)