diff --git a/pkg/value/value.go b/pkg/value/value.go new file mode 100644 index 0000000000..2f43ecdf2d --- /dev/null +++ b/pkg/value/value.go @@ -0,0 +1,19 @@ +// Copyright 2016 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package value + +var ( + normalNaN uint64 = 0x7ff8000000000001 // A quiet NaN. This is also math.NaN(). + staleNaN uint64 = 0x7ff4000000000000 // A signalling NaN, starting 01 to allow for expansion. +) diff --git a/retrieval/helpers_test.go b/retrieval/helpers_test.go index 2f1cb6001c..32f5cb68f1 100644 --- a/retrieval/helpers_test.go +++ b/retrieval/helpers_test.go @@ -33,31 +33,21 @@ func (a nopAppender) Commit() error { return func (a nopAppender) Rollback() error { return nil } type collectResultAppender struct { - refs map[uint64]labels.Labels result []sample } -func (a *collectResultAppender) SetSeries(l labels.Labels) (uint64, error) { - if a.refs == nil { - a.refs = map[uint64]labels.Labels{} - } - ref := uint64(len(a.refs)) - a.refs[ref] = l - return ref, nil +func (a *collectResultAppender) AddFast(ref uint64, t int64, v float64) error { + // Not implemented. + return nil } -func (a *collectResultAppender) Add(ref uint64, t int64, v float64) error { - // for ln, lv := range s.Metric { - // if len(lv) == 0 { - // delete(s.Metric, ln) - // } - // } +func (a *collectResultAppender) Add(m labels.Labels, t int64, v float64) (uint64, error) { a.result = append(a.result, sample{ - metric: a.refs[ref], + metric: m, t: t, v: v, }) - return nil + return 0, nil } func (a *collectResultAppender) Commit() error { return nil } diff --git a/retrieval/scrape.go b/retrieval/scrape.go index 8258892b87..0d152df85a 100644 --- a/retrieval/scrape.go +++ b/retrieval/scrape.go @@ -19,6 +19,7 @@ import ( "compress/gzip" "fmt" "io" + "math" "net/http" "sync" "time" @@ -46,6 +47,11 @@ const ( samplesPostRelabelMetricName = "scrape_samples_post_metric_relabeling" ) +var ( + normalNaN uint64 = 0x7ff8000000000001 // A quiet NaN. This is also math.NaN(). + staleNaN uint64 = 0x7ff4000000000000 // A signalling NaN, starting 01 to allow for expansion. +) + var ( targetIntervalLength = prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -536,6 +542,10 @@ loop: t := defTime met, tp, v := p.At() + // Normalise actual NaNs to one bit representation. + if math.IsNaN(v) { + v = math.Float64frombits(normalNaN) + } if tp != nil { t = *tp } diff --git a/retrieval/scrape_test.go b/retrieval/scrape_test.go index 634b4dd2bc..0c06e4b2e3 100644 --- a/retrieval/scrape_test.go +++ b/retrieval/scrape_test.go @@ -18,6 +18,7 @@ import ( "fmt" "io" "io/ioutil" + "math" "net/http" "net/http/httptest" "net/url" @@ -33,6 +34,7 @@ import ( "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/pkg/labels" + "github.com/prometheus/prometheus/pkg/timestamp" "github.com/prometheus/prometheus/storage" ) @@ -434,6 +436,45 @@ func TestScrapeLoopRun(t *testing.T) { } } +func TestScrapeLoopAppend(t *testing.T) { + app := &collectResultAppender{} + sl := &scrapeLoop{ + appender: func() storage.Appender { return app }, + reportAppender: func() storage.Appender { return nopAppender{} }, + cache: map[string]uint64{}, + } + + now := time.Now() + _, _, err := sl.append([]byte("metric_a 1\nmetric_b NaN\n"), now) + if err != nil { + t.Fatalf("Unexpected append error: %s", err) + } + + ingestedNaN := math.Float64bits(app.result[1].v) + if ingestedNaN != normalNaN { + t.Fatalf("Appended NaN samples wasn't as expected. Wanted: %x Got: %x", normalNaN, ingestedNaN) + } + + // DeepEqual will report NaNs as being different, so replace with a different value. + app.result[1].v = 42 + want := []sample{ + { + metric: labels.FromStrings(model.MetricNameLabel, "metric_a"), + t: timestamp.FromTime(now), + v: 1, + }, + { + metric: labels.FromStrings(model.MetricNameLabel, "metric_b"), + t: timestamp.FromTime(now), + v: 42, + }, + } + if !reflect.DeepEqual(want, app.result) { + t.Fatalf("Appended samples not as expected. Wanted: %+v Got: %+v", want, app.result) + } + +} + func TestTargetScraperScrapeOK(t *testing.T) { const ( configTimeout = 1500 * time.Millisecond