Merge pull request #1672 from imorph/fix_summary_decay2

fix: use injected now() instead of time.Now() in summary methods
This commit is contained in:
Arthur Silva Sens 2024-11-03 11:02:21 -03:00 committed by GitHub
commit 0c73c1c554
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 17 additions and 17 deletions

View File

@ -243,6 +243,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
s := &summary{ s := &summary{
desc: desc, desc: desc,
now: opts.now,
objectives: opts.Objectives, objectives: opts.Objectives,
sortedObjectives: make([]float64, 0, len(opts.Objectives)), sortedObjectives: make([]float64, 0, len(opts.Objectives)),
@ -280,6 +281,8 @@ type summary struct {
desc *Desc desc *Desc
now func() time.Time
objectives map[float64]float64 objectives map[float64]float64
sortedObjectives []float64 sortedObjectives []float64
@ -307,7 +310,7 @@ func (s *summary) Observe(v float64) {
s.bufMtx.Lock() s.bufMtx.Lock()
defer s.bufMtx.Unlock() defer s.bufMtx.Unlock()
now := time.Now() now := s.now()
if now.After(s.hotBufExpTime) { if now.After(s.hotBufExpTime) {
s.asyncFlush(now) s.asyncFlush(now)
} }
@ -326,7 +329,7 @@ func (s *summary) Write(out *dto.Metric) error {
s.bufMtx.Lock() s.bufMtx.Lock()
s.mtx.Lock() s.mtx.Lock()
// Swap bufs even if hotBuf is empty to set new hotBufExpTime. // Swap bufs even if hotBuf is empty to set new hotBufExpTime.
s.swapBufs(time.Now()) s.swapBufs(s.now())
s.bufMtx.Unlock() s.bufMtx.Unlock()
s.flushColdBuf() s.flushColdBuf()

View File

@ -371,10 +371,7 @@ func TestSummaryVecConcurrency(t *testing.T) {
} }
func TestSummaryDecay(t *testing.T) { func TestSummaryDecay(t *testing.T) {
if testing.Short() { now := time.Now()
t.Skip("Skipping test in short mode.")
// More because it depends on timing than because it is particularly long...
}
sum := NewSummary(SummaryOpts{ sum := NewSummary(SummaryOpts{
Name: "test_summary", Name: "test_summary",
@ -382,28 +379,28 @@ func TestSummaryDecay(t *testing.T) {
MaxAge: 100 * time.Millisecond, MaxAge: 100 * time.Millisecond,
Objectives: map[float64]float64{0.1: 0.001}, Objectives: map[float64]float64{0.1: 0.001},
AgeBuckets: 10, AgeBuckets: 10,
now: func() time.Time {
return now
},
}) })
m := &dto.Metric{} m := &dto.Metric{}
i := 0 for i := 1; i <= 1000; i++ {
tick := time.NewTicker(time.Millisecond) now = now.Add(time.Millisecond)
for range tick.C {
i++
sum.Observe(float64(i)) sum.Observe(float64(i))
if i%10 == 0 { if i%10 == 0 {
sum.Write(m) sum.Write(m)
if got, want := *m.Summary.Quantile[0].Value, math.Max(float64(i)/10, float64(i-90)); math.Abs(got-want) > 20 { got := *m.Summary.Quantile[0].Value
want := math.Max(float64(i)/10, float64(i-90))
if math.Abs(got-want) > 20 {
t.Errorf("%d. got %f, want %f", i, got, want) t.Errorf("%d. got %f, want %f", i, got, want)
} }
m.Reset() m.Reset()
} }
if i >= 1000 {
break
}
} }
tick.Stop()
// Wait for MaxAge without observations and make sure quantiles are NaN. // Simulate waiting for MaxAge without observations
time.Sleep(100 * time.Millisecond) now = now.Add(100 * time.Millisecond)
sum.Write(m) sum.Write(m)
if got := *m.Summary.Quantile[0].Value; !math.IsNaN(got) { if got := *m.Summary.Quantile[0].Value; !math.IsNaN(got) {
t.Errorf("got %f, want NaN after expiration", got) t.Errorf("got %f, want NaN after expiration", got)