diff --git a/pkg/tsdb/testdatasource/scenarios.go b/pkg/tsdb/testdatasource/scenarios.go
index 20d91acace9..b6b1bab0f2f 100644
--- a/pkg/tsdb/testdatasource/scenarios.go
+++ b/pkg/tsdb/testdatasource/scenarios.go
@@ -652,7 +652,7 @@ func (s *Service) handleLogsScenario(ctx context.Context, req *backend.QueryData
}
func RandomWalk(query backend.DataQuery, model *simplejson.Json, index int) *data.Frame {
- rand := rand.New(rand.NewSource(time.Now().UnixNano()))
+ rand := rand.New(rand.NewSource(time.Now().UnixNano() + int64(index)))
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
startValue := model.Get("startValue").MustFloat64(rand.Float64() * 100)
@@ -700,7 +700,7 @@ func RandomWalk(query backend.DataQuery, model *simplejson.Json, index int) *dat
SetConfig(&data.FieldConfig{
Interval: float64(query.Interval.Milliseconds()),
}),
- data.NewField(frameNameForQuery(query, model, index), parseLabels(model), floatVec),
+ data.NewField(frameNameForQuery(query, model, index), parseLabels(model, index), floatVec),
)
}
@@ -843,7 +843,7 @@ func predictableCSVWave(query backend.DataQuery, model *simplejson.Json) ([]*dat
frame := newSeriesForQuery(query, model, 0)
frame.Fields = fields
- frame.Fields[1].Labels = parseLabelsString(subQ.Labels)
+ frame.Fields[1].Labels = parseLabelsString(subQ.Labels, 0)
if subQ.Name != "" {
frame.Name = subQ.Name
}
@@ -929,7 +929,7 @@ func predictablePulse(query backend.DataQuery, model *simplejson.Json) (*data.Fr
frame := newSeriesForQuery(query, model, 0)
frame.Fields = fields
- frame.Fields[1].Labels = parseLabels(model)
+ frame.Fields[1].Labels = parseLabels(model, 0)
return frame, nil
}
@@ -998,12 +998,12 @@ func newSeriesForQuery(query backend.DataQuery, model *simplejson.Json, index in
*
* '{job="foo", instance="bar"} => {job: "foo", instance: "bar"}`
*/
-func parseLabels(model *simplejson.Json) data.Labels {
+func parseLabels(model *simplejson.Json, seriesIndex int) data.Labels {
labelText := model.Get("labels").MustString("")
- return parseLabelsString(labelText)
+ return parseLabelsString(labelText, seriesIndex)
}
-func parseLabelsString(labelText string) data.Labels {
+func parseLabelsString(labelText string, seriesIndex int) data.Labels {
if labelText == "" {
return data.Labels{}
}
@@ -1020,6 +1020,7 @@ func parseLabelsString(labelText string) data.Labels {
key := strings.TrimSpace(keyval[:idx])
val := strings.TrimSpace(keyval[idx+1:])
val = strings.Trim(val, "\"")
+ val = strings.ReplaceAll(val, "$seriesIndex", strconv.Itoa(seriesIndex))
tags[key] = val
}
diff --git a/pkg/tsdb/testdatasource/scenarios_test.go b/pkg/tsdb/testdatasource/scenarios_test.go
index 64da99d41b1..95f3b8e509c 100644
--- a/pkg/tsdb/testdatasource/scenarios_test.go
+++ b/pkg/tsdb/testdatasource/scenarios_test.go
@@ -3,15 +3,17 @@ package testdatasource
import (
"context"
"fmt"
+ "math/rand"
"testing"
"time"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
- "github.com/grafana/grafana/pkg/components/simplejson"
- "github.com/grafana/grafana/pkg/tsdb/legacydata"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/grafana/grafana/pkg/components/simplejson"
+ "github.com/grafana/grafana/pkg/tsdb/legacydata"
)
func TestTestdataScenarios(t *testing.T) {
@@ -193,23 +195,47 @@ func TestParseLabels(t *testing.T) {
"job": "foo",
"instance": "bar",
}
+ seriesIndex := rand.Int()
- tcs := []struct {
- model map[string]interface{}
+ tests := []struct {
+ name string
+ model map[string]interface{}
+ expected data.Labels
}{
- {model: map[string]interface{}{
- "labels": `{job="foo", instance="bar"}`,
- }},
- {model: map[string]interface{}{
- "labels": `job=foo, instance=bar`,
- }},
- {model: map[string]interface{}{
- "labels": `job = foo,instance = bar`,
- }},
+ {
+ name: "wrapped in {} and quoted value ",
+ model: map[string]interface{}{"labels": `{job="foo", instance="bar"}`},
+ expected: expectedTags,
+ },
+ {
+ name: "comma-separated non-quoted",
+ model: map[string]interface{}{"labels": `job=foo, instance=bar`},
+ expected: expectedTags,
+ },
+ {
+ name: "comma-separated quoted",
+ model: map[string]interface{}{"labels": `job="foo"", instance="bar"`},
+ expected: expectedTags,
+ },
+ {
+ name: "comma-separated with spaces, non quoted",
+ model: map[string]interface{}{"labels": `job = foo,instance = bar`},
+ expected: expectedTags,
+ },
+ {
+ name: "expands $seriesIndex",
+ model: map[string]interface{}{"labels": `job=series-$seriesIndex,instance=bar`},
+ expected: data.Labels{
+ "job": fmt.Sprintf("series-%d", seriesIndex),
+ "instance": "bar",
+ },
+ },
}
- for i, tc := range tcs {
- model := simplejson.NewFromAny(tc.model)
- assert.Equal(t, expectedTags, parseLabels(model), fmt.Sprintf("Actual tags in test case %d doesn't match expected tags", i+1))
+ for i, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ model := simplejson.NewFromAny(tc.model)
+ assert.Equal(t, tc.expected, parseLabels(model, seriesIndex), fmt.Sprintf("Actual tags in test case %d doesn't match expected tags", i+1))
+ })
}
}
diff --git a/public/app/plugins/datasource/testdata/QueryEditor.tsx b/public/app/plugins/datasource/testdata/QueryEditor.tsx
index 1fb08b1aad6..666affe9f19 100644
--- a/public/app/plugins/datasource/testdata/QueryEditor.tsx
+++ b/public/app/plugins/datasource/testdata/QueryEditor.tsx
@@ -231,6 +231,9 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
key=value, key2=value
+ Value can contain templates:
+
+ $seriesIndex - replaced with index of the series
>
}
>