[release-12.0.2] Alerting: Fix $value type when single data source is queried (#106101)
Alerting: Fix $value type when single data source is queried (#106080)
(cherry picked from commit faeddf334a)
Co-authored-by: Alexander Akhmetov <me@alx.cx>
This commit is contained in:
co-authored by
Alexander Akhmetov
parent
22b6da78a8
commit
982238b4bd
@@ -77,18 +77,18 @@ type Data struct {
|
||||
Values map[string]Value
|
||||
|
||||
// Value is the .Value and $value variables in templates.
|
||||
// For single datasource queries, this will be the numeric value of the query.
|
||||
// For multiple datasource queries, this will be the evaluation string.
|
||||
Value string
|
||||
// For single datasource queries, this will be the numeric value of the query (float64).
|
||||
// For multiple datasource queries, this will be the evaluation string (string).
|
||||
Value any
|
||||
}
|
||||
|
||||
func NewData(labels map[string]string, res eval.Result) Data {
|
||||
values := NewValues(res.Values)
|
||||
|
||||
// By default, use the evaluation string as the Value
|
||||
valueStr := res.EvaluationString
|
||||
var value any = res.EvaluationString
|
||||
|
||||
// If there's exactly one datasource node, use its value instead
|
||||
// If there's exactly one datasource node, use its numeric value instead
|
||||
// This makes the $value variable compatible with Prometheus templating
|
||||
// where $value holds the numeric value of the alert query
|
||||
datasourceNodeCount := 0
|
||||
@@ -105,13 +105,13 @@ func NewData(labels map[string]string, res eval.Result) Data {
|
||||
}
|
||||
|
||||
if datasourceNodeCount == 1 {
|
||||
valueStr = datasourceNodeValue.String()
|
||||
value = datasourceNodeValue.Value
|
||||
}
|
||||
|
||||
return Data{
|
||||
Labels: labels,
|
||||
Values: values,
|
||||
Value: valueStr,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package template
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
@@ -109,7 +110,7 @@ func TestNewData(t *testing.T) {
|
||||
}
|
||||
|
||||
data := NewData(map[string]string{}, res)
|
||||
assert.Equal(t, "10", data.Value)
|
||||
assert.Equal(t, 10.0, data.Value)
|
||||
})
|
||||
|
||||
t.Run("uses evaluation string when multiple datasource nodes exist", func(t *testing.T) {
|
||||
@@ -159,7 +160,7 @@ func TestDatasourceValueInTemplating(t *testing.T) {
|
||||
|
||||
data := NewData(map[string]string{}, res)
|
||||
// In Prometheus, a nil value would be rendered as NaN
|
||||
assert.Equal(t, "NaN", data.Value)
|
||||
assert.True(t, math.IsNaN(data.Value.(float64)))
|
||||
})
|
||||
|
||||
t.Run("single datasource node uses query value", func(t *testing.T) {
|
||||
@@ -188,7 +189,7 @@ func TestDatasourceValueInTemplating(t *testing.T) {
|
||||
}
|
||||
|
||||
data := NewData(map[string]string{}, res)
|
||||
assert.Equal(t, "10", data.Value)
|
||||
assert.Equal(t, 10.0, data.Value)
|
||||
})
|
||||
|
||||
t.Run("multiple datasource nodes uses evaluation string", func(t *testing.T) {
|
||||
@@ -636,8 +637,56 @@ func TestExpandTemplate(t *testing.T) {
|
||||
name: "check that safeHtml doesn't error or panic",
|
||||
text: "{{ \"<b>\" | safeHtml }}",
|
||||
expected: "<b>",
|
||||
},
|
||||
}
|
||||
}, {
|
||||
name: "$value numeric comparison with single datasource",
|
||||
text: `{{ if eq $value 1.0 }}equal{{ else }}not equal{{ end }}`,
|
||||
alertInstance: eval.Result{
|
||||
Values: map[string]eval.NumberValueCapture{
|
||||
"A": {
|
||||
Var: "A",
|
||||
IsDatasourceNode: true,
|
||||
Labels: data.Labels{"instance": "foo"},
|
||||
Value: util.Pointer(1.0),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "equal",
|
||||
}, {
|
||||
name: "humanize with string $value (multiple datasources)",
|
||||
text: `{{ humanize $value }}`,
|
||||
alertInstance: eval.Result{
|
||||
EvaluationString: "1234567.0",
|
||||
Values: map[string]eval.NumberValueCapture{
|
||||
"A": {
|
||||
Var: "A",
|
||||
IsDatasourceNode: true,
|
||||
Labels: data.Labels{"instance": "foo"},
|
||||
Value: util.Pointer(10.0),
|
||||
},
|
||||
"B": {
|
||||
Var: "B",
|
||||
IsDatasourceNode: true,
|
||||
Labels: data.Labels{"instance": "bar"},
|
||||
Value: util.Pointer(20.0),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "1.235M",
|
||||
}, {
|
||||
name: "humanize with numeric $value (single datasource)",
|
||||
text: `{{ humanize $value }}`,
|
||||
alertInstance: eval.Result{
|
||||
Values: map[string]eval.NumberValueCapture{
|
||||
"A": {
|
||||
Var: "A",
|
||||
IsDatasourceNode: true,
|
||||
Labels: data.Labels{"instance": "foo"},
|
||||
Value: util.Pointer(1234567.0),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "1.235M",
|
||||
}}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user