From 7e6f1a6869c50ddf2c1559464acb199eccd5cb7e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 31 Aug 2023 09:06:06 +0200 Subject: [PATCH] metrics: separate updatable/readonly meter, timer and histogram --- metrics/histogram.go | 91 ++++++-------------- metrics/meter.go | 61 +++---------- metrics/prometheus/collector.go | 6 +- metrics/runtimehistogram.go | 4 +- metrics/timer.go | 146 +++++++------------------------- 5 files changed, 74 insertions(+), 234 deletions(-) diff --git a/metrics/histogram.go b/metrics/histogram.go index 2c54ce8b40..db294a9d3e 100644 --- a/metrics/histogram.go +++ b/metrics/histogram.go @@ -1,8 +1,6 @@ package metrics -// Histograms calculate distribution statistics from a series of int64 values. -type Histogram interface { - Clear() +type HistogramSnapshot interface { Count() int64 Max() int64 Mean() float64 @@ -10,13 +8,18 @@ type Histogram interface { Percentile(float64) float64 Percentiles([]float64) []float64 Sample() Sample - Snapshot() Histogram StdDev() float64 Sum() int64 - Update(int64) Variance() float64 } +// Histograms calculate distribution statistics from a series of int64 values. +type Histogram interface { + Clear() + Update(int64) + Snapshot() HistogramSnapshot +} + // GetOrRegisterHistogram returns an existing Histogram or constructs and // registers a new StandardHistogram. func GetOrRegisterHistogram(name string, r Registry, s Sample) Histogram { @@ -54,64 +57,54 @@ func NewRegisteredHistogram(name string, r Registry, s Sample) Histogram { return c } -// HistogramSnapshot is a read-only copy of another Histogram. -type HistogramSnapshot struct { +// histogramSnapshot is a read-only copy of another Histogram. +type histogramSnapshot struct { sample *SampleSnapshot } -// Clear panics. -func (*HistogramSnapshot) Clear() { - panic("Clear called on a HistogramSnapshot") -} - // Count returns the number of samples recorded at the time the snapshot was // taken. -func (h *HistogramSnapshot) Count() int64 { return h.sample.Count() } +func (h *histogramSnapshot) Count() int64 { return h.sample.Count() } // Max returns the maximum value in the sample at the time the snapshot was // taken. -func (h *HistogramSnapshot) Max() int64 { return h.sample.Max() } +func (h *histogramSnapshot) Max() int64 { return h.sample.Max() } // Mean returns the mean of the values in the sample at the time the snapshot // was taken. -func (h *HistogramSnapshot) Mean() float64 { return h.sample.Mean() } +func (h *histogramSnapshot) Mean() float64 { return h.sample.Mean() } // Min returns the minimum value in the sample at the time the snapshot was // taken. -func (h *HistogramSnapshot) Min() int64 { return h.sample.Min() } +func (h *histogramSnapshot) Min() int64 { return h.sample.Min() } // Percentile returns an arbitrary percentile of values in the sample at the // time the snapshot was taken. -func (h *HistogramSnapshot) Percentile(p float64) float64 { +func (h *histogramSnapshot) Percentile(p float64) float64 { return h.sample.Percentile(p) } // Percentiles returns a slice of arbitrary percentiles of values in the sample // at the time the snapshot was taken. -func (h *HistogramSnapshot) Percentiles(ps []float64) []float64 { +func (h *histogramSnapshot) Percentiles(ps []float64) []float64 { return h.sample.Percentiles(ps) } // Sample returns the Sample underlying the histogram. -func (h *HistogramSnapshot) Sample() Sample { return h.sample } +func (h *histogramSnapshot) Sample() Sample { return h.sample } // Snapshot returns the snapshot. -func (h *HistogramSnapshot) Snapshot() Histogram { return h } +func (h *histogramSnapshot) Snapshot() HistogramSnapshot { return h } // StdDev returns the standard deviation of the values in the sample at the // time the snapshot was taken. -func (h *HistogramSnapshot) StdDev() float64 { return h.sample.StdDev() } +func (h *histogramSnapshot) StdDev() float64 { return h.sample.StdDev() } // Sum returns the sum in the sample at the time the snapshot was taken. -func (h *HistogramSnapshot) Sum() int64 { return h.sample.Sum() } - -// Update panics. -func (*HistogramSnapshot) Update(int64) { - panic("Update called on a HistogramSnapshot") -} +func (h *histogramSnapshot) Sum() int64 { return h.sample.Sum() } // Variance returns the variance of inputs at the time the snapshot was taken. -func (h *HistogramSnapshot) Variance() float64 { return h.sample.Variance() } +func (h *histogramSnapshot) Variance() float64 { return h.sample.Variance() } // NilHistogram is a no-op Histogram. type NilHistogram struct{} @@ -143,7 +136,7 @@ func (NilHistogram) Percentiles(ps []float64) []float64 { func (NilHistogram) Sample() Sample { return NilSample{} } // Snapshot is a no-op. -func (NilHistogram) Snapshot() Histogram { return NilHistogram{} } +func (NilHistogram) Snapshot() HistogramSnapshot { return NilHistogram{} } // StdDev is a no-op. func (NilHistogram) StdDev() float64 { return 0.0 } @@ -166,46 +159,10 @@ type StandardHistogram struct { // Clear clears the histogram and its sample. func (h *StandardHistogram) Clear() { h.sample.Clear() } -// Count returns the number of samples recorded since the histogram was last -// cleared. -func (h *StandardHistogram) Count() int64 { return h.sample.Count() } - -// Max returns the maximum value in the sample. -func (h *StandardHistogram) Max() int64 { return h.sample.Max() } - -// Mean returns the mean of the values in the sample. -func (h *StandardHistogram) Mean() float64 { return h.sample.Mean() } - -// Min returns the minimum value in the sample. -func (h *StandardHistogram) Min() int64 { return h.sample.Min() } - -// Percentile returns an arbitrary percentile of the values in the sample. -func (h *StandardHistogram) Percentile(p float64) float64 { - return h.sample.Percentile(p) -} - -// Percentiles returns a slice of arbitrary percentiles of the values in the -// sample. -func (h *StandardHistogram) Percentiles(ps []float64) []float64 { - return h.sample.Percentiles(ps) -} - -// Sample returns the Sample underlying the histogram. -func (h *StandardHistogram) Sample() Sample { return h.sample } - // Snapshot returns a read-only copy of the histogram. -func (h *StandardHistogram) Snapshot() Histogram { - return &HistogramSnapshot{sample: h.sample.Snapshot().(*SampleSnapshot)} +func (h *StandardHistogram) Snapshot() HistogramSnapshot { + return &histogramSnapshot{sample: h.sample.Snapshot().(*SampleSnapshot)} } -// StdDev returns the standard deviation of the values in the sample. -func (h *StandardHistogram) StdDev() float64 { return h.sample.StdDev() } - -// Sum returns the sum in the sample. -func (h *StandardHistogram) Sum() int64 { return h.sample.Sum() } - // Update samples a new value. func (h *StandardHistogram) Update(v int64) { h.sample.Update(v) } - -// Variance returns the variance of the values in the sample. -func (h *StandardHistogram) Variance() float64 { return h.sample.Variance() } diff --git a/metrics/meter.go b/metrics/meter.go index 25e08d3629..6eff96e675 100644 --- a/metrics/meter.go +++ b/metrics/meter.go @@ -7,16 +7,19 @@ import ( "time" ) -// Meters count events to produce exponentially-weighted moving average rates -// at one-, five-, and fifteen-minutes and a mean rate. -type Meter interface { +type MeterSnapshot interface { Count() int64 - Mark(int64) Rate1() float64 Rate5() float64 Rate15() float64 RateMean() float64 - Snapshot() Meter +} + +// Meters count events to produce exponentially-weighted moving average rates +// at one-, five-, and fifteen-minutes and a mean rate. +type Meter interface { + Mark(int64) + Snapshot() MeterSnapshot Stop() } @@ -75,11 +78,6 @@ type meterSnapshot struct { // Count returns the count of events at the time the snapshot was taken. func (m *meterSnapshot) Count() int64 { return m.count } -// Mark panics. -func (*meterSnapshot) Mark(n int64) { - panic("Mark called on a meterSnapshot") -} - // Rate1 returns the one-minute moving average rate of events per second at the // time the snapshot was taken. func (m *meterSnapshot) Rate1() float64 { return m.rate1 } @@ -96,12 +94,6 @@ func (m *meterSnapshot) Rate15() float64 { return m.rate15 } // snapshot was taken. func (m *meterSnapshot) RateMean() float64 { return m.rateMean } -// Snapshot returns the snapshot. -func (m *meterSnapshot) Snapshot() Meter { return m } - -// Stop is a no-op. -func (m *meterSnapshot) Stop() {} - // NilMeter is a no-op Meter. type NilMeter struct{} @@ -124,7 +116,7 @@ func (NilMeter) Rate15() float64 { return 0.0 } func (NilMeter) RateMean() float64 { return 0.0 } // Snapshot is a no-op. -func (NilMeter) Snapshot() Meter { return NilMeter{} } +func (NilMeter) Snapshot() MeterSnapshot { return NilMeter{} } // Stop is a no-op. func (NilMeter) Stop() {} @@ -158,44 +150,19 @@ func (m *StandardMeter) Stop() { } } -// Count returns the number of events recorded. -func (m *StandardMeter) Count() int64 { - return m.count.Load() + m.temp.Load() -} - // Mark records the occurrence of n events. func (m *StandardMeter) Mark(n int64) { m.temp.Add(n) } -// Rate1 returns the one-minute moving average rate of events per second. -func (m *StandardMeter) Rate1() float64 { - return m.a1.Rate() -} - -// Rate5 returns the five-minute moving average rate of events per second. -func (m *StandardMeter) Rate5() float64 { - return m.a5.Rate() -} - -// Rate15 returns the fifteen-minute moving average rate of events per second. -func (m *StandardMeter) Rate15() float64 { - return m.a15.Rate() -} - -// RateMean returns the meter's mean rate of events per second. -func (m *StandardMeter) RateMean() float64 { - return math.Float64frombits(m.rateMean.Load()) -} - // Snapshot returns a read-only copy of the meter. -func (m *StandardMeter) Snapshot() Meter { +func (m *StandardMeter) Snapshot() MeterSnapshot { return &meterSnapshot{ count: m.count.Load(), - rate1: m.Rate1(), - rate5: m.Rate5(), - rate15: m.Rate15(), - rateMean: m.RateMean(), + rate1: m.a1.Rate(), + rate5: m.a5.Rate(), + rate15: m.a15.Rate(), + rateMean: math.Float64frombits(m.rateMean.Load()), } } diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index 8624311c4b..90aa37f338 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -95,7 +95,7 @@ func (c *collector) addGaugeInfo(name string, m metrics.GaugeInfo) { c.writeGaugeInfo(name, m.Value()) } -func (c *collector) addHistogram(name string, m metrics.Histogram) { +func (c *collector) addHistogram(name string, m metrics.HistogramSnapshot) { pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999} ps := m.Percentiles(pv) c.writeSummaryCounter(name, m.Count()) @@ -106,11 +106,11 @@ func (c *collector) addHistogram(name string, m metrics.Histogram) { c.buff.WriteRune('\n') } -func (c *collector) addMeter(name string, m metrics.Meter) { +func (c *collector) addMeter(name string, m metrics.MeterSnapshot) { c.writeGaugeCounter(name, m.Count()) } -func (c *collector) addTimer(name string, m metrics.Timer) { +func (c *collector) addTimer(name string, m metrics.TimerSnapshot) { pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999} ps := m.Percentiles(pv) c.writeSummaryCounter(name, m.Count()) diff --git a/metrics/runtimehistogram.go b/metrics/runtimehistogram.go index c68939af1e..f93a7188d9 100644 --- a/metrics/runtimehistogram.go +++ b/metrics/runtimehistogram.go @@ -62,7 +62,7 @@ func (h *runtimeHistogram) Sample() Sample { } // Snapshot returns a non-changing cop of the histogram. -func (h *runtimeHistogram) Snapshot() Histogram { +func (h *runtimeHistogram) Snapshot() HistogramSnapshot { return h.load() } @@ -123,7 +123,7 @@ func (h *runtimeHistogramSnapshot) Sample() Sample { return NilSample{} } -func (h *runtimeHistogramSnapshot) Snapshot() Histogram { +func (h *runtimeHistogramSnapshot) Snapshot() HistogramSnapshot { return h } diff --git a/metrics/timer.go b/metrics/timer.go index ac88e24ad1..c35bbc01b4 100644 --- a/metrics/timer.go +++ b/metrics/timer.go @@ -5,8 +5,7 @@ import ( "time" ) -// Timers capture the duration and rate of events. -type Timer interface { +type TimerSnapshot interface { Count() int64 Max() int64 Mean() float64 @@ -17,14 +16,18 @@ type Timer interface { Rate5() float64 Rate15() float64 RateMean() float64 - Snapshot() Timer - StdDev() float64 - Stop() Sum() int64 - Time(func()) - Update(time.Duration) - UpdateSince(time.Time) Variance() float64 + StdDev() float64 +} + +// Timers 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 @@ -111,7 +114,7 @@ func (NilTimer) Rate15() float64 { return 0.0 } func (NilTimer) RateMean() float64 { return 0.0 } // Snapshot is a no-op. -func (NilTimer) Snapshot() Timer { return NilTimer{} } +func (NilTimer) Snapshot() TimerSnapshot { return NilTimer{} } // StdDev is a no-op. func (NilTimer) StdDev() float64 { return 0.0 } @@ -142,82 +145,21 @@ type StandardTimer struct { mutex sync.Mutex } -// Count returns the number of events recorded. -func (t *StandardTimer) Count() int64 { - return t.histogram.Count() -} - -// Max returns the maximum value in the sample. -func (t *StandardTimer) Max() int64 { - return t.histogram.Max() -} - -// Mean returns the mean of the values in the sample. -func (t *StandardTimer) Mean() float64 { - return t.histogram.Mean() -} - -// Min returns the minimum value in the sample. -func (t *StandardTimer) Min() int64 { - return t.histogram.Min() -} - -// Percentile returns an arbitrary percentile of the values in the sample. -func (t *StandardTimer) Percentile(p float64) float64 { - return t.histogram.Percentile(p) -} - -// Percentiles returns a slice of arbitrary percentiles of the values in the -// sample. -func (t *StandardTimer) Percentiles(ps []float64) []float64 { - return t.histogram.Percentiles(ps) -} - -// Rate1 returns the one-minute moving average rate of events per second. -func (t *StandardTimer) Rate1() float64 { - return t.meter.Rate1() -} - -// Rate5 returns the five-minute moving average rate of events per second. -func (t *StandardTimer) Rate5() float64 { - return t.meter.Rate5() -} - -// Rate15 returns the fifteen-minute moving average rate of events per second. -func (t *StandardTimer) Rate15() float64 { - return t.meter.Rate15() -} - -// RateMean returns the meter's mean rate of events per second. -func (t *StandardTimer) RateMean() float64 { - return t.meter.RateMean() -} - // Snapshot returns a read-only copy of the timer. -func (t *StandardTimer) Snapshot() Timer { +func (t *StandardTimer) Snapshot() TimerSnapshot { t.mutex.Lock() defer t.mutex.Unlock() - return &TimerSnapshot{ - histogram: t.histogram.Snapshot().(*HistogramSnapshot), + return &timerSnapshot{ + histogram: t.histogram.Snapshot().(*histogramSnapshot), meter: t.meter.Snapshot().(*meterSnapshot), } } -// StdDev returns the standard deviation of the values in the sample. -func (t *StandardTimer) StdDev() float64 { - return t.histogram.StdDev() -} - // Stop stops the meter. func (t *StandardTimer) Stop() { t.meter.Stop() } -// Sum returns the sum in the sample. -func (t *StandardTimer) Sum() int64 { - return t.histogram.Sum() -} - // Record the duration of the execution of the given function. func (t *StandardTimer) Time(f func()) { ts := time.Now() @@ -241,86 +183,60 @@ func (t *StandardTimer) UpdateSince(ts time.Time) { t.meter.Mark(1) } -// Variance returns the variance of the values in the sample. -func (t *StandardTimer) Variance() float64 { - return t.histogram.Variance() -} - -// TimerSnapshot is a read-only copy of another Timer. -type TimerSnapshot struct { - histogram *HistogramSnapshot +// timerSnapshot is a read-only copy of another Timer. +type timerSnapshot struct { + histogram *histogramSnapshot meter *meterSnapshot } // Count returns the number of events recorded at the time the snapshot was // 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. -func (t *TimerSnapshot) Max() int64 { return t.histogram.Max() } +func (t *timerSnapshot) Max() int64 { return t.histogram.Max() } // 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. -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 // snapshot was taken. -func (t *TimerSnapshot) Percentile(p float64) float64 { +func (t *timerSnapshot) Percentile(p float64) float64 { return t.histogram.Percentile(p) } // Percentiles returns a slice of arbitrary percentiles of sampled values at // 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) } // Rate1 returns the one-minute moving average rate of events per second at the // 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 // 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 // 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 // snapshot was taken. -func (t *TimerSnapshot) RateMean() float64 { return t.meter.RateMean() } - -// Snapshot returns the snapshot. -func (t *TimerSnapshot) Snapshot() Timer { return t } +func (t *timerSnapshot) RateMean() float64 { return t.meter.RateMean() } // StdDev returns the standard deviation of the values at the time the snapshot // was taken. -func (t *TimerSnapshot) StdDev() float64 { return t.histogram.StdDev() } - -// Stop is a no-op. -func (t *TimerSnapshot) Stop() {} +func (t *timerSnapshot) StdDev() float64 { return t.histogram.StdDev() } // Sum returns the sum at the time the snapshot was taken. -func (t *TimerSnapshot) Sum() int64 { return t.histogram.Sum() } - -// Time panics. -func (*TimerSnapshot) Time(func()) { - panic("Time called on a TimerSnapshot") -} - -// Update panics. -func (*TimerSnapshot) Update(time.Duration) { - panic("Update called on a TimerSnapshot") -} - -// UpdateSince panics. -func (*TimerSnapshot) UpdateSince(time.Time) { - panic("UpdateSince called on a TimerSnapshot") -} +func (t *timerSnapshot) Sum() int64 { return t.histogram.Sum() } // Variance returns the variance of the values at the time the snapshot was // taken. -func (t *TimerSnapshot) Variance() float64 { return t.histogram.Variance() } +func (t *timerSnapshot) Variance() float64 { return t.histogram.Variance() }