mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-26 13:11:11 -08:00
Ensure all the NaNs we ingest have the same bit pattern.
This commit is contained in:
parent
73e7ff1edd
commit
76acf7b9b1
19
pkg/value/value.go
Normal file
19
pkg/value/value.go
Normal file
|
@ -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.
|
||||
)
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue