mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Change templateCaptureValue to support using template functions (#38766)
* Change templateCaptureValue to support using template functions This commit changes templateCaptureValue to use float64 for the value instead of *float64. This change means that annotations and labels can use the float64 value with functions such as printf and avoid having to check for nil. It also means that absent values are now printed as 0. * Use math.NaN() instead of 0 for absent value
This commit is contained in:
@@ -3,6 +3,7 @@ package state
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -110,16 +111,13 @@ func (c *cache) expandRuleLabelsAndAnnotations(alertRule *ngModels.AlertRule, la
|
||||
// and labels template.
|
||||
type templateCaptureValue struct {
|
||||
Labels map[string]string
|
||||
Value *float64
|
||||
Value float64
|
||||
}
|
||||
|
||||
// String implements the Stringer interface to print the value of each RefID
|
||||
// in the template via {{ $values.A }} rather than {{ $values.A.Value }}.
|
||||
func (v templateCaptureValue) String() string {
|
||||
if v.Value != nil {
|
||||
return strconv.FormatFloat(*v.Value, 'f', -1, 64)
|
||||
}
|
||||
return "null"
|
||||
return strconv.FormatFloat(v.Value, 'f', -1, 64)
|
||||
}
|
||||
|
||||
func expandTemplate(name, text string, labels map[string]string, alertInstance eval.Result) (result string, resultErr error) {
|
||||
@@ -148,23 +146,31 @@ func expandTemplate(name, text string, labels map[string]string, alertInstance e
|
||||
Value string
|
||||
}{
|
||||
Labels: labels,
|
||||
Values: func() map[string]templateCaptureValue {
|
||||
m := make(map[string]templateCaptureValue)
|
||||
for k, v := range alertInstance.Values {
|
||||
m[k] = templateCaptureValue{
|
||||
Labels: v.Labels,
|
||||
Value: v.Value,
|
||||
}
|
||||
}
|
||||
return m
|
||||
}(),
|
||||
Value: alertInstance.EvaluationString,
|
||||
Values: newTemplateCaptureValues(alertInstance.Values),
|
||||
Value: alertInstance.EvaluationString,
|
||||
}); err != nil {
|
||||
return "", fmt.Errorf("error executing template %v: %s", name, err.Error())
|
||||
}
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
func newTemplateCaptureValues(values map[string]eval.NumberValueCapture) map[string]templateCaptureValue {
|
||||
m := make(map[string]templateCaptureValue)
|
||||
for k, v := range values {
|
||||
var f float64
|
||||
if v.Value != nil {
|
||||
f = *v.Value
|
||||
} else {
|
||||
f = math.NaN()
|
||||
}
|
||||
m[k] = templateCaptureValue{
|
||||
Labels: v.Labels,
|
||||
Value: f,
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (c *cache) set(entry *State) {
|
||||
c.mtxStates.Lock()
|
||||
defer c.mtxStates.Unlock()
|
||||
|
||||
@@ -17,16 +17,16 @@ func TestTemplateCaptureValueStringer(t *testing.T) {
|
||||
value templateCaptureValue
|
||||
expected string
|
||||
}{{
|
||||
name: "nil value returns null",
|
||||
value: templateCaptureValue{Value: nil},
|
||||
expected: "null",
|
||||
name: "0 is returned as integer value",
|
||||
value: templateCaptureValue{Value: 0},
|
||||
expected: "0",
|
||||
}, {
|
||||
name: "1.0 is returned as integer value",
|
||||
value: templateCaptureValue{Value: ptr.Float64(1.0)},
|
||||
value: templateCaptureValue{Value: 1.0},
|
||||
expected: "1",
|
||||
}, {
|
||||
name: "1.1 is returned as decimal value",
|
||||
value: templateCaptureValue{Value: ptr.Float64(1.1)},
|
||||
value: templateCaptureValue{Value: 1.1},
|
||||
expected: "1.1",
|
||||
}}
|
||||
|
||||
@@ -46,12 +46,12 @@ func TestExpandTemplate(t *testing.T) {
|
||||
expected string
|
||||
expectedError error
|
||||
}{{
|
||||
name: "instance labels are expanded into $labels",
|
||||
name: "labels are expanded into $labels",
|
||||
text: "{{ $labels.instance }} is down",
|
||||
labels: data.Labels{"instance": "foo"},
|
||||
expected: "foo is down",
|
||||
}, {
|
||||
name: "missing instance label returns error",
|
||||
name: "missing label in $labels returns error",
|
||||
text: "{{ $labels.instance }} is down",
|
||||
labels: data.Labels{},
|
||||
expectedError: errors.New("error executing template __alert_test: template: __alert_test:1:86: executing \"__alert_test\" at <$labels.instance>: map has no entry for key \"instance\""),
|
||||
@@ -63,11 +63,24 @@ func TestExpandTemplate(t *testing.T) {
|
||||
"A": {
|
||||
Var: "A",
|
||||
Labels: data.Labels{"instance": "foo"},
|
||||
Value: ptr.Float64(10),
|
||||
Value: ptr.Float64(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "foo has value 10",
|
||||
expected: "foo has value 1",
|
||||
}, {
|
||||
name: "values can be passed to template functions such as printf",
|
||||
text: "{{ $values.A.Labels.instance }} has value {{ $values.A.Value | printf \"%.1f\" }}",
|
||||
alertInstance: eval.Result{
|
||||
Values: map[string]eval.NumberValueCapture{
|
||||
"A": {
|
||||
Var: "A",
|
||||
Labels: data.Labels{"instance": "foo"},
|
||||
Value: ptr.Float64(1.1),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "foo has value 1.1",
|
||||
}, {
|
||||
name: "missing label in $values returns error",
|
||||
text: "{{ $values.A.Labels.instance }} has value {{ $values.A }}",
|
||||
@@ -76,13 +89,26 @@ func TestExpandTemplate(t *testing.T) {
|
||||
"A": {
|
||||
Var: "A",
|
||||
Labels: data.Labels{},
|
||||
Value: ptr.Float64(10),
|
||||
Value: ptr.Float64(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("error executing template __alert_test: template: __alert_test:1:86: executing \"__alert_test\" at <$values.A.Labels.instance>: map has no entry for key \"instance\""),
|
||||
}, {
|
||||
name: "value string is expanded into $value",
|
||||
name: "missing value in $values is returned as NaN",
|
||||
text: "{{ $values.A.Labels.instance }} has value {{ $values.A }}",
|
||||
alertInstance: eval.Result{
|
||||
Values: map[string]eval.NumberValueCapture{
|
||||
"A": {
|
||||
Var: "A",
|
||||
Labels: data.Labels{"instance": "foo"},
|
||||
Value: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "foo has value NaN",
|
||||
}, {
|
||||
name: "assert value string is expanded into $value",
|
||||
text: "{{ $value }}",
|
||||
alertInstance: eval.Result{
|
||||
EvaluationString: "[ var='A' labels={instance=foo} value=10 ]",
|
||||
|
||||
Reference in New Issue
Block a user