From 715be73ac98ad410f2c0de560cacdfdd413b1384 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Sun, 15 Mar 2015 13:58:14 +0100 Subject: [PATCH] Return NaN when summaries have no observations yet. Also, properly handle decay upon Write(). This fixes https://github.com/prometheus/client_golang/issues/85 . --- prometheus/summary.go | 15 ++++++++++----- prometheus/summary_test.go | 11 +++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/prometheus/summary.go b/prometheus/summary.go index a731f4e..dd336c5 100644 --- a/prometheus/summary.go +++ b/prometheus/summary.go @@ -16,6 +16,7 @@ package prometheus import ( "fmt" "hash/fnv" + "math" "sort" "sync" "time" @@ -277,10 +278,8 @@ func (s *summary) Write(out *dto.Metric) error { s.bufMtx.Lock() s.mtx.Lock() - - if len(s.hotBuf) != 0 { - s.swapBufs(time.Now()) - } + // Swap bufs even if hotBuf is empty to set new hotBufExpTime. + s.swapBufs(time.Now()) s.bufMtx.Unlock() s.flushColdBuf() @@ -288,9 +287,15 @@ func (s *summary) Write(out *dto.Metric) error { sum.SampleSum = proto.Float64(s.sum) for _, rank := range s.sortedObjectives { + var q float64 + if s.headStream.Count() == 0 { + q = math.NaN() + } else { + q = s.headStream.Query(rank) + } qs = append(qs, &dto.Quantile{ Quantile: proto.Float64(rank), - Value: proto.Float64(s.headStream.Query(rank)), + Value: proto.Float64(q), }) } diff --git a/prometheus/summary_test.go b/prometheus/summary_test.go index 40d05fa..0790cdf 100644 --- a/prometheus/summary_test.go +++ b/prometheus/summary_test.go @@ -289,6 +289,11 @@ func TestSummaryVecConcurrency(t *testing.T) { } func TestSummaryDecay(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + // More because it depends on timing than because it is particularly long... + } + sum := NewSummary(SummaryOpts{ Name: "test_summary", Help: "helpless", @@ -315,6 +320,12 @@ func TestSummaryDecay(t *testing.T) { } } tick.Stop() + // Wait for MaxAge without observations and make sure quantiles are NaN. + time.Sleep(100 * time.Millisecond) + sum.Write(m) + if got := *m.Summary.Quantile[0].Value; !math.IsNaN(got) { + t.Errorf("got %f, want NaN after expiration", got) + } } func getBounds(vars []float64, q, ε float64) (min, max float64) {