Use target as name for aliased queries
This commit is contained in:
@@ -200,8 +200,11 @@ func (s *Service) toDataFrames(response *http.Response, refId string, fromAlert
|
||||
return nil, err
|
||||
}
|
||||
|
||||
aliasRegex := regexp.MustCompile(`(alias\(|aliasByMetric|aliasByNode|aliasByTags|aliasQuery|aliasSub)`)
|
||||
|
||||
frames = data.Frames{}
|
||||
for _, series := range responseData {
|
||||
aliasMatch := aliasRegex.MatchString(series.Target)
|
||||
timeVector := make([]time.Time, 0, len(series.DataPoints))
|
||||
values := make([]*float64, 0, len(series.DataPoints))
|
||||
|
||||
@@ -217,7 +220,9 @@ func (s *Service) toDataFrames(response *http.Response, refId string, fromAlert
|
||||
tags := make(map[string]string)
|
||||
for name, value := range series.Tags {
|
||||
if name == "name" {
|
||||
if fromAlert {
|
||||
// Queries with aliases should use the target as the name
|
||||
// to ensure multi-dimensional queries are distinguishable from each other
|
||||
if fromAlert || aliasMatch {
|
||||
value = series.Target
|
||||
}
|
||||
}
|
||||
|
||||
@@ -738,6 +738,119 @@ Error: Target not found
|
||||
}
|
||||
}
|
||||
|
||||
func TestAliasMatching(t *testing.T) {
|
||||
service := &Service{
|
||||
logger: backend.Logger,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
target string
|
||||
tagsName string
|
||||
fromAlert bool
|
||||
expectedLabelName string
|
||||
}{
|
||||
{
|
||||
name: "alias() function sets name tag to target",
|
||||
target: "alias(stats.counters.web.hits, 'Web Hits')",
|
||||
tagsName: "stats.counters.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "alias(stats.counters.web.hits, 'Web Hits')",
|
||||
},
|
||||
{
|
||||
name: "aliasByNode() function sets name tag to target",
|
||||
target: "aliasByNode(stats.counters.web.hits, 2)",
|
||||
tagsName: "stats.counters.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "aliasByNode(stats.counters.web.hits, 2)",
|
||||
},
|
||||
{
|
||||
name: "aliasByMetric() function sets name tag to target",
|
||||
target: "aliasByMetric(stats.counters.web.hits)",
|
||||
tagsName: "stats.counters.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "aliasByMetric(stats.counters.web.hits)",
|
||||
},
|
||||
{
|
||||
name: "aliasByTags() function sets name tag to target",
|
||||
target: "aliasByTags(stats.counters.web.hits, 'host')",
|
||||
tagsName: "stats.counters.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "aliasByTags(stats.counters.web.hits, 'host')",
|
||||
},
|
||||
{
|
||||
name: "aliasSub() function sets name tag to target",
|
||||
target: "aliasSub(stats.counters.web.hits, 'stats', 'metrics')",
|
||||
tagsName: "stats.counters.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "aliasSub(stats.counters.web.hits, 'stats', 'metrics')",
|
||||
},
|
||||
{
|
||||
name: "aliasQuery() function sets name tag to target",
|
||||
target: "aliasQuery(stats.counters.web.hits, 'SELECT name FROM hosts')",
|
||||
tagsName: "stats.counters.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "aliasQuery(stats.counters.web.hits, 'SELECT name FROM hosts')",
|
||||
},
|
||||
{
|
||||
name: "no alias function keeps original name tag",
|
||||
target: "stats.counters.web.hits",
|
||||
tagsName: "stats.counters.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "stats.counters.web.hits",
|
||||
},
|
||||
{
|
||||
name: "fromAlert overrides name tag even without alias",
|
||||
target: "stats.counters.web.hits",
|
||||
tagsName: "original.name",
|
||||
fromAlert: true,
|
||||
expectedLabelName: "stats.counters.web.hits",
|
||||
},
|
||||
{
|
||||
name: "nested alias function matches",
|
||||
target: "sumSeries(alias(stats.counters.*.hits, 'Hits'))",
|
||||
tagsName: "stats.counters.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "sumSeries(alias(stats.counters.*.hits, 'Hits'))",
|
||||
},
|
||||
{
|
||||
name: "alias in metric path should not match",
|
||||
target: "stats.alias.web.hits",
|
||||
tagsName: "stats.alias.web.hits",
|
||||
fromAlert: false,
|
||||
expectedLabelName: "stats.alias.web.hits",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
body := fmt.Sprintf(`[
|
||||
{
|
||||
"target": %q,
|
||||
"tags": { "name": %q, "host": "server1" },
|
||||
"datapoints": [[100, 1609459200]]
|
||||
}
|
||||
]`, tc.target, tc.tagsName)
|
||||
|
||||
httpResponse := &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body))}
|
||||
dataFrames, err := service.toDataFrames(httpResponse, "A", tc.fromAlert)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, dataFrames, 1)
|
||||
|
||||
frame := dataFrames[0]
|
||||
require.GreaterOrEqual(t, len(frame.Fields), 2)
|
||||
|
||||
valueField := frame.Fields[1]
|
||||
require.NotNil(t, valueField.Labels)
|
||||
|
||||
actualName, ok := valueField.Labels["name"]
|
||||
require.True(t, ok, "name label should exist")
|
||||
assert.Equal(t, tc.expectedLabelName, actualName, "name label should match expected value")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseGraphiteError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user