mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
app/vmselect/promql: remove NaNs from /api/v1/query_range
output like Prometheus does
Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/153
This commit is contained in:
parent
a0d480fbf3
commit
7b5168adfb
2 changed files with 72 additions and 0 deletions
|
@ -574,12 +574,47 @@ func QueryRangeHandler(w http.ResponseWriter, r *http.Request) error {
|
||||||
result = adjustLastPoints(result)
|
result = adjustLastPoints(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove NaN values as Prometheus does.
|
||||||
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/153
|
||||||
|
removeNaNValuesInplace(result)
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
WriteQueryRangeResponse(w, result)
|
WriteQueryRangeResponse(w, result)
|
||||||
queryRangeDuration.UpdateDuration(startTime)
|
queryRangeDuration.UpdateDuration(startTime)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeNaNValuesInplace(tss []netstorage.Result) {
|
||||||
|
for i := range tss {
|
||||||
|
ts := &tss[i]
|
||||||
|
hasNaNs := false
|
||||||
|
for _, v := range ts.Values {
|
||||||
|
if math.IsNaN(v) {
|
||||||
|
hasNaNs = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasNaNs {
|
||||||
|
// Fast path: nothing to remove.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slow path: remove NaNs.
|
||||||
|
srcTimestamps := ts.Timestamps
|
||||||
|
dstValues := ts.Values[:0]
|
||||||
|
dstTimestamps := ts.Timestamps[:0]
|
||||||
|
for j, v := range ts.Values {
|
||||||
|
if math.IsNaN(v) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dstValues = append(dstValues, v)
|
||||||
|
dstTimestamps = append(dstTimestamps, srcTimestamps[j])
|
||||||
|
}
|
||||||
|
ts.Values = dstValues
|
||||||
|
ts.Timestamps = dstTimestamps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var queryRangeDuration = metrics.NewSummary(`vm_request_duration_seconds{path="/api/v1/query_range"}`)
|
var queryRangeDuration = metrics.NewSummary(`vm_request_duration_seconds{path="/api/v1/query_range"}`)
|
||||||
|
|
||||||
// adjustLastPoints substitutes the last point values with the previous
|
// adjustLastPoints substitutes the last point values with the previous
|
||||||
|
|
|
@ -2,11 +2,48 @@ package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/netstorage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestRemoveNaNValuesInplace(t *testing.T) {
|
||||||
|
f := func(tss []netstorage.Result, tssExpected []netstorage.Result) {
|
||||||
|
t.Helper()
|
||||||
|
removeNaNValuesInplace(tss)
|
||||||
|
if !reflect.DeepEqual(tss, tssExpected) {
|
||||||
|
t.Fatalf("unexpected result; got %v; want %v", tss, tssExpected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nan := math.NaN()
|
||||||
|
|
||||||
|
f(nil, nil)
|
||||||
|
f([]netstorage.Result{
|
||||||
|
{
|
||||||
|
Timestamps: []int64{100, 200, 300},
|
||||||
|
Values: []float64{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Timestamps: []int64{100, 200, 300, 400},
|
||||||
|
Values: []float64{nan, nan, 3, nan},
|
||||||
|
},
|
||||||
|
}, []netstorage.Result{
|
||||||
|
{
|
||||||
|
Timestamps: []int64{100, 200, 300},
|
||||||
|
Values: []float64{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Timestamps: []int64{300},
|
||||||
|
Values: []float64{3},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetTimeSuccess(t *testing.T) {
|
func TestGetTimeSuccess(t *testing.T) {
|
||||||
f := func(s string, timestampExpected int64) {
|
f := func(s string, timestampExpected int64) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
Loading…
Reference in a new issue