diff --git a/pkg/tsdb/elasticsearch/response_parser.go b/pkg/tsdb/elasticsearch/response_parser.go index 2737602aa0f..661a832341e 100644 --- a/pkg/tsdb/elasticsearch/response_parser.go +++ b/pkg/tsdb/elasticsearch/response_parser.go @@ -140,6 +140,16 @@ func processBuckets(aggs map[string]interface{}, target *Query, return nil } +func newTimeSeriesFrame(timeData []time.Time, tags map[string]string, values []*float64) *data.Frame { + frame := data.NewFrame("", + data.NewField("time", nil, timeData), + data.NewField("value", tags, values)) + frame.Meta = &data.FrameMeta{ + Type: data.FrameTypeTimeSeriesMulti, + } + return frame +} + // nolint:gocyclo func processMetrics(esAgg *simplejson.Json, target *Query, query *backend.DataResponse, props map[string]string) error { @@ -169,9 +179,7 @@ func processMetrics(esAgg *simplejson.Json, target *Query, query *backend.DataRe tags[k] = v } tags["metric"] = countType - frames = append(frames, data.NewFrame("", - data.NewField("time", nil, timeVector), - data.NewField("value", tags, values))) + frames = append(frames, newTimeSeriesFrame(timeVector, tags, values)) case percentilesType: buckets := esAggBuckets if len(buckets) == 0 { @@ -203,9 +211,7 @@ func processMetrics(esAgg *simplejson.Json, target *Query, query *backend.DataRe timeVector = append(timeVector, time.Unix(int64(*key)/1000, 0).UTC()) values = append(values, value) } - frames = append(frames, data.NewFrame("", - data.NewField("time", nil, timeVector), - data.NewField("value", tags, values))) + frames = append(frames, newTimeSeriesFrame(timeVector, tags, values)) } case topMetricsType: buckets := esAggBuckets @@ -245,10 +251,7 @@ func processMetrics(esAgg *simplejson.Json, target *Query, query *backend.DataRe } } - frames = append(frames, data.NewFrame("", - data.NewField("time", nil, timeVector), - data.NewField("value", tags, values), - )) + frames = append(frames, newTimeSeriesFrame(timeVector, tags, values)) } case extendedStatsType: @@ -292,9 +295,7 @@ func processMetrics(esAgg *simplejson.Json, target *Query, query *backend.DataRe values = append(values, value) } labels := tags - frames = append(frames, data.NewFrame("", - data.NewField("time", nil, timeVector), - data.NewField("value", labels, values))) + frames = append(frames, newTimeSeriesFrame(timeVector, labels, values)) } default: for k, v := range props { @@ -320,9 +321,7 @@ func processMetrics(esAgg *simplejson.Json, target *Query, query *backend.DataRe timeVector = append(timeVector, time.Unix(int64(*key)/1000, 0).UTC()) values = append(values, value) } - frames = append(frames, data.NewFrame("", - data.NewField("time", nil, timeVector), - data.NewField("value", tags, values))) + frames = append(frames, newTimeSeriesFrame(timeVector, tags, values)) } } if query.Frames != nil { @@ -534,10 +533,15 @@ func nameFields(queryResult backend.DataResponse, target *Query) { } } metricTypeCount := len(set) - for i := range frames { - fieldName := getFieldName(*frames[i].Fields[1], target, metricTypeCount) - for _, field := range frames[i].Fields { - field.SetConfig(&data.FieldConfig{DisplayNameFromDS: fieldName}) + for _, frame := range frames { + if frame.Meta != nil && frame.Meta.Type == data.FrameTypeTimeSeriesMulti { + // if it is a time-series-multi, it means it has two columns, one is "time", + // another is "number" + valueField := frame.Fields[1] + fieldName := getFieldName(*valueField, target, metricTypeCount) + if fieldName != "" { + valueField.SetConfig(&data.FieldConfig{DisplayNameFromDS: fieldName}) + } } } } diff --git a/pkg/tsdb/elasticsearch/response_parser_frontend_test.go b/pkg/tsdb/elasticsearch/response_parser_frontend_test.go index 5105548f16b..79cb107ad11 100644 --- a/pkg/tsdb/elasticsearch/response_parser_frontend_test.go +++ b/pkg/tsdb/elasticsearch/response_parser_frontend_test.go @@ -59,6 +59,21 @@ func requireFloatAt(t *testing.T, expected float64, field *data.Field, index int require.Equal(t, expected, *v, fmt.Sprintf("wrong flaot at index %v", index)) } +func requireTimeSeriesName(t *testing.T, expected string, frame *data.Frame) { + getField := func() *data.Field { + for _, field := range frame.Fields { + if field.Type() != data.FieldTypeTime { + return field + } + } + return nil + } + + field := getField() + require.NotNil(t, expected, field.Config) + require.Equal(t, expected, field.Config.DisplayNameFromDS) +} + func TestRefIdMatching(t *testing.T) { require.NoError(t, nil) query := []byte(` @@ -286,7 +301,7 @@ func TestSimpleQueryReturns1Frame(t *testing.T) { frames := result.response.Responses["A"].Frames require.Len(t, frames, 1, "frame-count wrong") frame := frames[0] - // require.Equal(t, "Count", frame.Name) // FIXME + requireTimeSeriesName(t, "Count", frame) requireFrameLength(t, frame, 2) requireTimeValue(t, 1000, frame, 0) @@ -343,7 +358,7 @@ func TestSimpleQueryCountAndAvg(t *testing.T) { requireTimeValue(t, 1000, frame1, 0) requireNumberValue(t, 10, frame1, 0) - // require.Equal(t, "average value", frame2.Name) // FIXME + requireTimeSeriesName(t, "Average value", frame2) requireNumberValue(t, 88, frame2, 0) requireNumberValue(t, 99, frame2, 1) @@ -407,8 +422,8 @@ func TestSimpleGroupBy1Metric2Frames(t *testing.T) { require.Len(t, frames, 2) requireFrameLength(t, frames[0], 2) - // require.Equal(t, "server1", frames[0].Name) // FIXME - // require.Equal(t, "server2", frames[1].Name) // FIXME + requireTimeSeriesName(t, "server1", frames[0]) + requireTimeSeriesName(t, "server2", frames[1]) } func TestSimpleGroupBy2Metrics4Frames(t *testing.T) { @@ -471,10 +486,10 @@ func TestSimpleGroupBy2Metrics4Frames(t *testing.T) { frames := result.response.Responses["A"].Frames require.Len(t, frames, 4) requireFrameLength(t, frames[0], 2) - // require.Equal(t, "server1 Count", frames[0].Name) // FIXME - // require.Equal(t, "server1 Average @value", frames[1].Name) // FIXME - // require.Equal(t, "server2 Count", frames[2].Name) // FIXME - // require.Equal(t, "server2 Average @value", frames[3].Name) // FIXME + requireTimeSeriesName(t, "server1 Count", frames[0]) + requireTimeSeriesName(t, "server1 Average @value", frames[1]) + requireTimeSeriesName(t, "server2 Count", frames[2]) + requireTimeSeriesName(t, "server2 Average @value", frames[3]) } func TestPercentiles2Frames(t *testing.T) { @@ -531,8 +546,8 @@ func TestPercentiles2Frames(t *testing.T) { require.Len(t, frames, 2) requireFrameLength(t, frames[0], 2) - // require.Equal(t, "p75 @value", frames[0].Name) // FIXME - // require.Equal(t, "p90 @value", frames[1].Name) // FIXME + requireTimeSeriesName(t, "p75 @value", frames[0]) + requireTimeSeriesName(t, "p90 @value", frames[1]) requireNumberValue(t, 3.3, frames[0], 0) requireTimeValue(t, 1000, frames[0], 0) @@ -615,8 +630,8 @@ func TestExtendedStats4Frames(t *testing.T) { frames := result.response.Responses["A"].Frames require.Len(t, frames, 4) requireFrameLength(t, frames[0], 1) - // require.Equal(t, "server1 Max @value", frames[0].Name) // FIXME - // require.Equal(t, "server1 Std Dev Upper @value", frames[1].Name) // FIXME + requireTimeSeriesName(t, "server1 Max @value", frames[0]) + requireTimeSeriesName(t, "server1 Std Dev Upper @value", frames[1]) requireNumberValue(t, 10.2, frames[0], 0) requireNumberValue(t, 3, frames[1], 0) @@ -698,14 +713,14 @@ func TestTopMetrics2Frames(t *testing.T) { frame1 := frames[0] frame2 := frames[1] - // require.Equal(t, "Top Metrics Value", frame1.Name) // FIXME + requireTimeSeriesName(t, "Top Metrics @value", frame1) requireFrameLength(t, frame1, 2) requireTimeValue(t, time1.UTC().UnixMilli(), frame1, 0) requireTimeValue(t, time2.UTC().UnixMilli(), frame1, 1) requireNumberValue(t, 1, frame1, 0) requireNumberValue(t, 1, frame1, 1) - // require.Equal(t, "Top Metrics @anotherValue", frame2.Name) // FIXME + requireTimeSeriesName(t, "Top Metrics @anotherValue", frame2) requireFrameLength(t, frame2, 2) requireTimeValue(t, time1.UTC().UnixMilli(), frame2, 0) requireTimeValue(t, time2.UTC().UnixMilli(), frame2, 1) @@ -782,9 +797,9 @@ func TestSingleGroupWithAliasPattern3Frames(t *testing.T) { require.Len(t, frames, 3) requireFrameLength(t, frames[0], 2) - // require.Equal(t, "server1 Count and {{not_exist}} server1", frames[0].Name) // FIXME - // require.Equal(t, "server2 Count and {{not_exist}} server2", frames[1].Name) // FIXME - // require.Equal(t, "0 Count and {{not_exist}} 0", frames[2].Name) // FIXME + requireTimeSeriesName(t, "server1 Count and {{not_exist}} server1", frames[0]) + requireTimeSeriesName(t, "server2 Count and {{not_exist}} server2", frames[1]) + requireTimeSeriesName(t, "0 Count and {{not_exist}} 0", frames[2]) } func TestHistogramSimple(t *testing.T) { @@ -841,7 +856,7 @@ func TestHistogramSimple(t *testing.T) { require.Equal(t, "Count", field2.Name) // we need to test that the fieldConfig is "empty" - require.Equal(t, data.FieldConfig{}, *field2.Config) + require.Nil(t, field2.Config) } func TestHistogramWith2FiltersAgg(t *testing.T) { diff --git a/pkg/tsdb/elasticsearch/response_parser_test.go b/pkg/tsdb/elasticsearch/response_parser_test.go index 6b5984eae0a..bd73c946a7e 100644 --- a/pkg/tsdb/elasticsearch/response_parser_test.go +++ b/pkg/tsdb/elasticsearch/response_parser_test.go @@ -853,7 +853,7 @@ func TestResponseParser(t *testing.T) { require.Equal(t, frame.Fields[1].Len(), 2) require.Equal(t, frame.Fields[2].Name, "Count") require.Equal(t, frame.Fields[2].Len(), 2) - assert.Equal(t, frame.Fields[1].Config.DisplayNameFromDS, "") + require.Nil(t, frame.Fields[1].Config) }) t.Run("Multiple metrics of same type", func(t *testing.T) { @@ -900,7 +900,7 @@ func TestResponseParser(t *testing.T) { require.Equal(t, frame.Fields[1].Len(), 1) require.Equal(t, frame.Fields[2].Name, "Average test2") require.Equal(t, frame.Fields[2].Len(), 1) - assert.Equal(t, frame.Fields[1].Config.DisplayNameFromDS, "") + require.Nil(t, frame.Fields[1].Config) }) t.Run("With bucket_script", func(t *testing.T) { @@ -1057,7 +1057,7 @@ func TestResponseParser(t *testing.T) { require.Equal(t, frame.Fields[3].Len(), 2) require.Equal(t, frame.Fields[4].Name, "params.var1 * params.var2 * 2") require.Equal(t, frame.Fields[4].Len(), 2) - assert.Equal(t, frame.Fields[1].Config.DisplayNameFromDS, "") + require.Nil(t, frame.Fields[1].Config) }) }) diff --git a/pkg/tsdb/elasticsearch/testdata/trimedges_string.golden.jsonc b/pkg/tsdb/elasticsearch/testdata/trimedges_string.golden.jsonc index 5a291e0032f..d88ad4e863e 100644 --- a/pkg/tsdb/elasticsearch/testdata/trimedges_string.golden.jsonc +++ b/pkg/tsdb/elasticsearch/testdata/trimedges_string.golden.jsonc @@ -1,6 +1,8 @@ // 🌟 This was machine generated. Do not edit. 🌟 // -// Frame[0] +// Frame[0] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+------------------+ @@ -20,15 +22,15 @@ "frames": [ { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "Count" } }, { diff --git a/pkg/tsdb/elasticsearch/testdata_response/metric_complex.a.golden.jsonc b/pkg/tsdb/elasticsearch/testdata_response/metric_complex.a.golden.jsonc index 9773eb42a43..f776f75d846 100644 --- a/pkg/tsdb/elasticsearch/testdata_response/metric_complex.a.golden.jsonc +++ b/pkg/tsdb/elasticsearch/testdata_response/metric_complex.a.golden.jsonc @@ -1,6 +1,8 @@ // 🌟 This was machine generated. Do not edit. 🌟 // -// Frame[0] +// Frame[0] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+--------------------+ @@ -15,7 +17,9 @@ // // // -// Frame[1] +// Frame[1] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+--------------------+ @@ -30,7 +34,9 @@ // // // -// Frame[2] +// Frame[2] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+--------------------+ @@ -45,7 +51,9 @@ // // // -// Frame[3] +// Frame[3] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+--------------------+ @@ -60,7 +68,9 @@ // // // -// Frame[4] +// Frame[4] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+--------------------+ @@ -75,7 +85,9 @@ // // // -// Frame[5] +// Frame[5] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+--------------------+ @@ -95,15 +107,15 @@ "frames": [ { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val3 Max float" } }, { @@ -139,15 +151,15 @@ }, { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val3 Min float" } }, { @@ -183,15 +195,15 @@ }, { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val2 Max float" } }, { @@ -227,15 +239,15 @@ }, { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val2 Min float" } }, { @@ -271,15 +283,15 @@ }, { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val1 Max float" } }, { @@ -315,15 +327,15 @@ }, { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val1 Min float" } }, { diff --git a/pkg/tsdb/elasticsearch/testdata_response/metric_multi.a.golden.jsonc b/pkg/tsdb/elasticsearch/testdata_response/metric_multi.a.golden.jsonc index 12397e6ab6b..a08325ebf22 100644 --- a/pkg/tsdb/elasticsearch/testdata_response/metric_multi.a.golden.jsonc +++ b/pkg/tsdb/elasticsearch/testdata_response/metric_multi.a.golden.jsonc @@ -1,6 +1,8 @@ // 🌟 This was machine generated. Do not edit. 🌟 // -// Frame[0] +// Frame[0] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+-------------------+ @@ -20,15 +22,15 @@ "frames": [ { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "Max float" } }, { diff --git a/pkg/tsdb/elasticsearch/testdata_response/metric_multi.b.golden.jsonc b/pkg/tsdb/elasticsearch/testdata_response/metric_multi.b.golden.jsonc index 5f4f6120512..60e387d12aa 100644 --- a/pkg/tsdb/elasticsearch/testdata_response/metric_multi.b.golden.jsonc +++ b/pkg/tsdb/elasticsearch/testdata_response/metric_multi.b.golden.jsonc @@ -1,6 +1,8 @@ // 🌟 This was machine generated. Do not edit. 🌟 // -// Frame[0] +// Frame[0] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 3 Rows // +-------------------------------+---------------------+ @@ -20,15 +22,15 @@ "frames": [ { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "Min float" } }, { diff --git a/pkg/tsdb/elasticsearch/testdata_response/metric_simple.a.golden.jsonc b/pkg/tsdb/elasticsearch/testdata_response/metric_simple.a.golden.jsonc index c3a8094ac85..b4294e20db5 100644 --- a/pkg/tsdb/elasticsearch/testdata_response/metric_simple.a.golden.jsonc +++ b/pkg/tsdb/elasticsearch/testdata_response/metric_simple.a.golden.jsonc @@ -1,6 +1,8 @@ // 🌟 This was machine generated. Do not edit. 🌟 // -// Frame[0] +// Frame[0] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 4 Rows // +-------------------------------+--------------------+ @@ -16,7 +18,9 @@ // // // -// Frame[1] +// Frame[1] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 4 Rows // +-------------------------------+--------------------+ @@ -32,7 +36,9 @@ // // // -// Frame[2] +// Frame[2] { +// "type": "timeseries-multi" +// } // Name: // Dimensions: 2 Fields by 4 Rows // +-------------------------------+--------------------+ @@ -53,15 +59,15 @@ "frames": [ { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val3" } }, { @@ -99,15 +105,15 @@ }, { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val2" } }, { @@ -145,15 +151,15 @@ }, { "schema": { + "meta": { + "type": "timeseries-multi" + }, "fields": [ { "name": "time", "type": "time", "typeInfo": { "frame": "time.Time" - }, - "config": { - "displayNameFromDS": "val1" } }, {