mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 08:05:43 -06:00
Prometheus: Transform NaN values from matrix response to null on backend (#40757)
* avoid duplicate allocations * set labels * Replace NaN in matrix with null * Refactor and add test * Update test * Append response only if no error Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
967721068e
commit
ba90b57b66
@ -181,9 +181,9 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
|
||||
if err != nil {
|
||||
plog.Error("Exemplar query", query.Expr, "failed with", err)
|
||||
result.Responses[query.RefId] = backend.DataResponse{Error: err}
|
||||
continue
|
||||
} else {
|
||||
response[ExemplarQueryType] = exemplarResponse
|
||||
}
|
||||
response[ExemplarQueryType] = exemplarResponse
|
||||
}
|
||||
|
||||
frames, err := parseResponse(response, query)
|
||||
@ -403,19 +403,28 @@ func matrixToDataFrames(matrix model.Matrix, query *PrometheusQuery) data.Frames
|
||||
|
||||
for _, v := range matrix {
|
||||
tags := make(map[string]string, len(v.Metric))
|
||||
timeVector := make([]time.Time, 0, len(v.Values))
|
||||
values := make([]float64, 0, len(v.Values))
|
||||
for k, v := range v.Metric {
|
||||
tags[string(k)] = string(v)
|
||||
}
|
||||
for _, k := range v.Values {
|
||||
timeVector = append(timeVector, time.Unix(k.Timestamp.Unix(), 0).UTC())
|
||||
values = append(values, float64(k.Value))
|
||||
|
||||
timeField := data.NewFieldFromFieldType(data.FieldTypeTime, len(v.Values))
|
||||
valueField := data.NewFieldFromFieldType(data.FieldTypeNullableFloat64, len(v.Values))
|
||||
|
||||
for i, k := range v.Values {
|
||||
timeField.Set(i, time.Unix(k.Timestamp.Unix(), 0).UTC())
|
||||
value := float64(k.Value)
|
||||
if !math.IsNaN(value) {
|
||||
valueField.Set(i, &value)
|
||||
}
|
||||
}
|
||||
|
||||
name := formatLegend(v.Metric, query)
|
||||
frame := data.NewFrame(name,
|
||||
data.NewField("Time", nil, timeVector),
|
||||
data.NewField("Value", tags, values).SetConfig(&data.FieldConfig{DisplayNameFromDS: name}))
|
||||
timeField.Name = data.TimeSeriesTimeFieldName
|
||||
valueField.Name = data.TimeSeriesValueFieldName
|
||||
valueField.Config = &data.FieldConfig{DisplayNameFromDS: name}
|
||||
valueField.Labels = tags
|
||||
|
||||
frame := data.NewFrame(name, timeField, valueField)
|
||||
frame.Meta = &data.FrameMeta{
|
||||
Custom: map[string]string{
|
||||
"resultType": "matrix",
|
||||
|
@ -1,6 +1,7 @@
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -440,6 +441,27 @@ func TestPrometheus_parseResponse(t *testing.T) {
|
||||
require.Equal(t, "UTC", testValue.(time.Time).Location().String())
|
||||
})
|
||||
|
||||
t.Run("matrix response with NaN value should be changed to null", func(t *testing.T) {
|
||||
value := make(map[PrometheusQueryType]interface{})
|
||||
value[RangeQueryType] = p.Matrix{
|
||||
&p.SampleStream{
|
||||
Metric: p.Metric{"app": "Application"},
|
||||
Values: []p.SamplePair{
|
||||
{Value: p.SampleValue(math.NaN()), Timestamp: 1000},
|
||||
},
|
||||
},
|
||||
}
|
||||
query := &PrometheusQuery{
|
||||
LegendFormat: "",
|
||||
}
|
||||
res, err := parseResponse(value, query)
|
||||
require.NoError(t, err)
|
||||
|
||||
var nilPointer *float64
|
||||
require.Equal(t, res[0].Fields[1].Name, "Value")
|
||||
require.Equal(t, res[0].Fields[1].At(0), nilPointer)
|
||||
})
|
||||
|
||||
t.Run("vector response should be parsed normally", func(t *testing.T) {
|
||||
value := make(map[PrometheusQueryType]interface{})
|
||||
value[RangeQueryType] = p.Vector{
|
||||
|
Loading…
Reference in New Issue
Block a user