diff --git a/pkg/tsdb/influxdb/influxql/util/util.go b/pkg/tsdb/influxdb/influxql/util/util.go index b4ecc095b6b..b0179f3b2b5 100644 --- a/pkg/tsdb/influxdb/influxql/util/util.go +++ b/pkg/tsdb/influxdb/influxql/util/util.go @@ -8,13 +8,14 @@ import ( "strings" "time" + "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana/pkg/tsdb/influxdb/models" ) var ( - legendFormat = regexp.MustCompile(`\[\[([\@\/\w-]+)(\.[\@\/\w-]+)*\]\]*|\$([\@\w-]+?)*`) + legendFormat = regexp.MustCompile(`\[\[([\@\/\w-]+)(\.[\@\/\w-]+)*\]\]*|\$([\@\w]+?)*`) ) const ( @@ -28,6 +29,8 @@ func FormatFrameName(rowName, column string, tags map[string]string, query model return BuildFrameNameFromQuery(rowName, column, tags, frameName, query.ResultFormat) } nameSegment := strings.Split(rowName, ".") + intervalText := gtime.FormatInterval(query.Interval) + intervalMs := int64(query.Interval / time.Millisecond) result := legendFormat.ReplaceAllFunc([]byte(query.Alias), func(in []byte) []byte { aliasFormat := string(in) @@ -41,6 +44,12 @@ func FormatFrameName(rowName, column string, tags map[string]string, query model if aliasFormat == "col" { return []byte(column) } + if aliasFormat == "__interval" { + return []byte(intervalText) + } + if aliasFormat == "__interval_ms" { + return []byte(strconv.FormatInt(intervalMs, 10)) + } pos, err := strconv.Atoi(aliasFormat) if err == nil && len(nameSegment) > pos { diff --git a/pkg/tsdb/influxdb/influxql/util/util_test.go b/pkg/tsdb/influxdb/influxql/util/util_test.go index a535cc54026..12809575a82 100644 --- a/pkg/tsdb/influxdb/influxql/util/util_test.go +++ b/pkg/tsdb/influxdb/influxql/util/util_test.go @@ -2,8 +2,11 @@ package util import ( "testing" + "time" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/tsdb/influxdb/models" ) func TestParseString(t *testing.T) { @@ -21,3 +24,44 @@ func TestParseString(t *testing.T) { require.Equal(t, expected, result) }) } + +func TestFormatFrameName(t *testing.T) { + testcases := []struct { + name string + rowName string + column string + tags map[string]string + query models.Query + expected string + }{ + {name: "no alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "", ResultFormat: "time_series"}, expected: "rowName.colName { key: value }"}, + {name: "simple alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "alias", ResultFormat: "time_series"}, expected: "alias"}, + {name: "segmented name", rowName: "rowName.other.one", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "zero: $0 - one: $1 - second: $2", ResultFormat: "time_series"}, expected: "zero: rowName - one: other - second: one"}, + {name: "[[m]] measurement alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "[[m]]", ResultFormat: "time_series"}, expected: "rowName"}, + {name: "$m measurement alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "$m", ResultFormat: "time_series"}, expected: "rowName"}, + {name: "[[measurement]] measurement alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "[[measurement]]", ResultFormat: "time_series"}, expected: "rowName"}, + {name: "[[col]] column alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "[[col]]", ResultFormat: "time_series"}, expected: "colName"}, + {name: "$col column alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "$col", ResultFormat: "time_series"}, expected: "colName"}, + {name: "[[tag_key]] tag alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "[[tag_key]]", ResultFormat: "time_series"}, expected: "value"}, + {name: "$tag_key tag alias", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "$tag_key", ResultFormat: "time_series"}, expected: "value"}, + {name: "[[m]] with additional text", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "[[m]] - something", ResultFormat: "time_series"}, expected: "rowName - something"}, + {name: "$m with additional text", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "$m - something", ResultFormat: "time_series"}, expected: "rowName - something"}, + {name: "[[measurement]] with additional text", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "[[measurement]] - something", ResultFormat: "time_series"}, expected: "rowName - something"}, + {name: "[[col]] with additional text", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "[[col]] - something", ResultFormat: "time_series"}, expected: "colName - something"}, + {name: "$col with additional text", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "$col - something", ResultFormat: "time_series"}, expected: "colName - something"}, + {name: "[[tag_key]] with additional text", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "[[tag_key]] - something", ResultFormat: "time_series"}, expected: "value - something"}, + {name: "$tag_key with additional text", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value"}, query: models.Query{Alias: "$tag_key - something", ResultFormat: "time_series"}, expected: "value - something"}, + {name: "$tag_key complex", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value", "key2": "value2"}, query: models.Query{Alias: "L:$tag_key-$tag_key2", ResultFormat: "time_series"}, expected: "L:value-value2"}, + {name: "$__interval", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value", "key2": "value2"}, query: models.Query{Alias: "Interval: $__interval", Interval: time.Millisecond * 10}, expected: "Interval: 10ms"}, + {name: "$__interval_ms", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value", "key2": "value2"}, query: models.Query{Alias: "Interval: $__interval_ms", Interval: time.Millisecond * 10}, expected: "Interval: 10"}, + {name: "Complex alias with $__interval and $tag_key", rowName: "rowName", column: "colName", tags: map[string]string{"key": "value", "key2": "value2"}, query: models.Query{Alias: "Interval: $__interval_ms for tag: $tag_key", Interval: time.Millisecond * 10}, expected: "Interval: 10 for tag: value"}, + } + + frameName := make([]byte, 0, 128) + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + result := string(FormatFrameName(tc.rowName, tc.column, tc.tags, tc.query, frameName[:])) + require.Equal(t, tc.expected, result) + }) + } +}