metrics: make resettingtimer not expose internal values

This commit is contained in:
Martin Holst Swende 2023-08-31 13:07:54 +02:00
parent 73687d9a60
commit fb8e300797
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
5 changed files with 53 additions and 41 deletions

View file

@ -177,7 +177,7 @@ func (exp *exp) publishTimer(name string, metric metrics.Timer) {
func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) { func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) {
t := metric.Snapshot() t := metric.Snapshot()
ps := t.Percentiles([]float64{50, 75, 95, 99}) ps := t.Percentiles([]float64{50, 75, 95, 99})
exp.getInt(name + ".count").Set(int64(len(t.Values()))) exp.getInt(name + ".count").Set(int64(t.Count()))
exp.getFloat(name + ".mean").Set(t.Mean()) exp.getFloat(name + ".mean").Set(t.Mean())
exp.getInt(name + ".50-percentile").Set(ps[0]) exp.getInt(name + ".50-percentile").Set(ps[0])
exp.getInt(name + ".75-percentile").Set(ps[1]) exp.getInt(name + ".75-percentile").Set(ps[1])

View file

@ -99,17 +99,16 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf
return measurement, fields return measurement, fields
case metrics.ResettingTimer: case metrics.ResettingTimer:
t := metric.Snapshot() t := metric.Snapshot()
if len(t.Values()) == 0 { if t.Count() == 0 {
break break
} }
ps := t.Percentiles([]float64{50, 95, 99}) ps := t.Percentiles([]float64{50, 95, 99})
val := t.Values()
measurement := fmt.Sprintf("%s%s.span", namespace, name) measurement := fmt.Sprintf("%s%s.span", namespace, name)
fields := map[string]interface{}{ fields := map[string]interface{}{
"count": len(val), "count": t.Count(),
"max": val[len(val)-1], "max": t.Max(),
"mean": t.Mean(), "mean": t.Mean(),
"min": val[0], "min": t.Min(),
"p50": ps[0], "p50": ps[0],
"p95": ps[1], "p95": ps[1],
"p99": ps[2], "p99": ps[2],

View file

@ -122,12 +122,11 @@ func (c *collector) addTimer(name string, m metrics.TimerSnapshot) {
} }
func (c *collector) addResettingTimer(name string, m metrics.ResettingTimerSnapshot) { func (c *collector) addResettingTimer(name string, m metrics.ResettingTimerSnapshot) {
if len(m.Values()) <= 0 { if m.Count() <= 0 {
return return
} }
ps := m.Percentiles([]float64{50, 95, 99}) ps := m.Percentiles([]float64{50, 95, 99})
val := m.Values() c.writeSummaryCounter(name, m.Count())
c.writeSummaryCounter(name, len(val))
c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name))) c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
c.writeSummaryPercentile(name, "0.50", ps[0]) c.writeSummaryPercentile(name, "0.50", ps[0])
c.writeSummaryPercentile(name, "0.95", ps[1]) c.writeSummaryPercentile(name, "0.95", ps[1])

View file

@ -12,8 +12,10 @@ import (
const InitialResettingTimerSliceCap = 10 const InitialResettingTimerSliceCap = 10
type ResettingTimerSnapshot interface { type ResettingTimerSnapshot interface {
Values() []int64 Count() int
Mean() float64 Mean() float64
Max() int64
Min() int64
Percentiles([]float64) []int64 Percentiles([]float64) []int64
} }
@ -63,7 +65,10 @@ func (NilResettingTimer) Time(f func()) { f() }
func (NilResettingTimer) Update(time.Duration) {} func (NilResettingTimer) Update(time.Duration) {}
func (NilResettingTimer) Percentiles([]float64) []int64 { return nil } func (NilResettingTimer) Percentiles([]float64) []int64 { return nil }
func (NilResettingTimer) Mean() float64 { return 0.0 } func (NilResettingTimer) Mean() float64 { return 0.0 }
func (NilResettingTimer) Max() int64 { return 0 }
func (NilResettingTimer) Min() int64 { return 0 }
func (NilResettingTimer) UpdateSince(time.Time) {} func (NilResettingTimer) UpdateSince(time.Time) {}
func (NilResettingTimer) Count() int { return 0 }
// StandardResettingTimer is the standard implementation of a ResettingTimer. // StandardResettingTimer is the standard implementation of a ResettingTimer.
// and Meter. // and Meter.
@ -72,11 +77,6 @@ type StandardResettingTimer struct {
mutex sync.Mutex mutex sync.Mutex
} }
//// Values returns a slice with all measurements.
//func (t *StandardResettingTimer) Values() []int64 {
// return t.values
//}
// Snapshot resets the timer and returns a read-only copy of its contents. // Snapshot resets the timer and returns a read-only copy of its contents.
func (t *StandardResettingTimer) Snapshot() ResettingTimerSnapshot { func (t *StandardResettingTimer) Snapshot() ResettingTimerSnapshot {
t.mutex.Lock() t.mutex.Lock()
@ -114,13 +114,15 @@ func (t *StandardResettingTimer) UpdateSince(ts time.Time) {
type resettingTimerSnapshot struct { type resettingTimerSnapshot struct {
values []int64 values []int64
mean float64 mean float64
max int64
min int64
thresholdBoundaries []int64 thresholdBoundaries []int64
calculated bool calculated bool
} }
// Values returns all values from snapshot. // Count return the length of the values from snapshot.
func (t *resettingTimerSnapshot) Values() []int64 { func (t *resettingTimerSnapshot) Count() int {
return t.values return len(t.values)
} }
// Percentiles returns the boundaries for the input percentiles. // Percentiles returns the boundaries for the input percentiles.
@ -134,12 +136,32 @@ func (t *resettingTimerSnapshot) Percentiles(percentiles []float64) []int64 {
// note: this method is not thread safe // note: this method is not thread safe
func (t *resettingTimerSnapshot) Mean() float64 { func (t *resettingTimerSnapshot) Mean() float64 {
if !t.calculated { if !t.calculated {
t.calc([]float64{}) t.calc(nil)
} }
return t.mean return t.mean
} }
// Max returns the max of the snapshotted values
// note: this method is not thread safe
func (t *resettingTimerSnapshot) Max() int64 {
if !t.calculated {
t.calc(nil)
}
return t.max
}
// Min returns the min of the snapshotted values
// note: this method is not thread safe
func (t *resettingTimerSnapshot) Min() int64 {
if !t.calculated {
t.calc(nil)
}
return t.min
}
func (t *resettingTimerSnapshot) calc(percentiles []float64) { func (t *resettingTimerSnapshot) calc(percentiles []float64) {
slices.Sort(t.values) slices.Sort(t.values)
count := len(t.values) count := len(t.values)
@ -149,18 +171,18 @@ func (t *resettingTimerSnapshot) calc(percentiles []float64) {
t.calculated = true t.calculated = true
return return
} }
min := t.values[0] t.min = t.values[0]
max := t.values[count-1] t.max = t.values[count-1]
cumulativeValues := make([]int64, count) cumulativeValues := make([]int64, count)
cumulativeValues[0] = min cumulativeValues[0] = t.min
for i := 1; i < count; i++ { for i := 1; i < count; i++ {
cumulativeValues[i] = t.values[i] + cumulativeValues[i-1] cumulativeValues[i] = t.values[i] + cumulativeValues[i-1]
} }
t.thresholdBoundaries = make([]int64, len(percentiles)) t.thresholdBoundaries = make([]int64, len(percentiles))
thresholdBoundary := max thresholdBoundary := t.max
for i, pct := range percentiles { for i, pct := range percentiles {
if count > 1 { if count > 1 {

View file

@ -75,16 +75,12 @@ func TestResettingTimer(t *testing.T) {
ps := snap.Percentiles([]float64{50, 95, 99}) ps := snap.Percentiles([]float64{50, 95, 99})
val := snap.Values() if tt.wantMin != snap.Min() {
t.Fatalf("%d: min: got %d, want %d", ind, snap.Min(), tt.wantMin)
if len(val) > 0 {
if tt.wantMin != val[0] {
t.Fatalf("%d: min: got %d, want %d", ind, val[0], tt.wantMin)
} }
if tt.wantMax != val[len(val)-1] { if tt.wantMax != snap.Max() {
t.Fatalf("%d: max: got %d, want %d", ind, val[len(val)-1], tt.wantMax) t.Fatalf("%d: max: got %d, want %d", ind, snap.Max(), tt.wantMax)
}
} }
if tt.wantMean != snap.Mean() { if tt.wantMean != snap.Mean() {
@ -177,16 +173,12 @@ func TestResettingTimerWithFivePercentiles(t *testing.T) {
ps := snap.Percentiles([]float64{5, 20, 50, 95, 99}) ps := snap.Percentiles([]float64{5, 20, 50, 95, 99})
val := snap.Values() if tt.wantMin != snap.Min() {
t.Fatalf("%d: min: got %d, want %d", ind, snap.Min(), tt.wantMin)
if len(val) > 0 {
if tt.wantMin != val[0] {
t.Fatalf("%d: min: got %d, want %d", ind, val[0], tt.wantMin)
} }
if tt.wantMax != val[len(val)-1] { if tt.wantMax != snap.Max() {
t.Fatalf("%d: max: got %d, want %d", ind, val[len(val)-1], tt.wantMax) t.Fatalf("%d: max: got %d, want %d", ind, snap.Max(), tt.wantMax)
}
} }
if tt.wantMean != snap.Mean() { if tt.wantMean != snap.Mean() {