From c1f95a27130d26fe941683b41439cecf9e55182c Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Mon, 5 Jan 2026 17:04:17 +0100 Subject: [PATCH] Graphite: Fix series naming convention in backend mode (#115588) Fix series naming convention --- pkg/tsdb/graphite/healthcheck.go | 2 +- pkg/tsdb/graphite/query.go | 10 ++++-- pkg/tsdb/graphite/query_test.go | 52 +++++++++++++++++++++++++++----- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/pkg/tsdb/graphite/healthcheck.go b/pkg/tsdb/graphite/healthcheck.go index e6c3f005095..fd595fee2a1 100644 --- a/pkg/tsdb/graphite/healthcheck.go +++ b/pkg/tsdb/graphite/healthcheck.go @@ -81,7 +81,7 @@ func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthReque } }() - _, err = s.toDataFrames(res, healthCheckQuery.RefID) + _, err = s.toDataFrames(res, healthCheckQuery.RefID, false) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) diff --git a/pkg/tsdb/graphite/query.go b/pkg/tsdb/graphite/query.go index c06c6d5af08..1a3d9b1beb6 100644 --- a/pkg/tsdb/graphite/query.go +++ b/pkg/tsdb/graphite/query.go @@ -27,6 +27,8 @@ func (s *Service) RunQuery(ctx context.Context, req *backend.QueryDataRequest, d req *http.Request formData url.Values }{} + // FromAlert header is defined in pkg/services/ngalert/models/constants.go + fromAlert := req.Headers["FromAlert"] == "true" result := backend.NewQueryDataResponse() for _, query := range req.Queries { @@ -97,7 +99,7 @@ func (s *Service) RunQuery(ctx context.Context, req *backend.QueryDataRequest, d } }() - queryFrames, err := s.toDataFrames(res, refId) + queryFrames, err := s.toDataFrames(res, refId, fromAlert) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) @@ -192,7 +194,7 @@ func (s *Service) createGraphiteRequest(ctx context.Context, query backend.DataQ return graphiteReq, formData, emptyQuery, nil } -func (s *Service) toDataFrames(response *http.Response, refId string) (frames data.Frames, error error) { +func (s *Service) toDataFrames(response *http.Response, refId string, fromAlert bool) (frames data.Frames, error error) { responseData, err := s.parseResponse(response) if err != nil { return nil, err @@ -215,7 +217,9 @@ func (s *Service) toDataFrames(response *http.Response, refId string) (frames da tags := make(map[string]string) for name, value := range series.Tags { if name == "name" { - value = series.Target + if fromAlert { + value = series.Target + } } switch value := value.(type) { case string: diff --git a/pkg/tsdb/graphite/query_test.go b/pkg/tsdb/graphite/query_test.go index 036f5401194..761e62112ba 100644 --- a/pkg/tsdb/graphite/query_test.go +++ b/pkg/tsdb/graphite/query_test.go @@ -182,7 +182,7 @@ func TestConvertResponses(t *testing.T) { expectedFrames := data.Frames{expectedFrame} httpResponse := &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body))} - dataFrames, err := service.toDataFrames(httpResponse, refId) + dataFrames, err := service.toDataFrames(httpResponse, refId, false) require.NoError(t, err) if !reflect.DeepEqual(expectedFrames, dataFrames) { @@ -196,8 +196,8 @@ func TestConvertResponses(t *testing.T) { body := ` [ { - "target": "target", - "tags": { "fooTag": "fooValue", "barTag": "barValue", "int": 100, "float": 3.14 }, + "target": "aliasedTarget(target)", + "tags": { "name": "target", "fooTag": "fooValue", "barTag": "barValue", "int": 100, "float": 3.14 }, "datapoints": [[50, 1], [null, 2], [100, 3]] } ]` @@ -211,18 +211,19 @@ func TestConvertResponses(t *testing.T) { "barTag": "barValue", "int": "100", "float": "3.14", - }, []*float64{&a, nil, &b}).SetConfig(&data.FieldConfig{DisplayNameFromDS: "target"}), + "name": "target", + }, []*float64{&a, nil, &b}).SetConfig(&data.FieldConfig{DisplayNameFromDS: "aliasedTarget(target)"}), ).SetMeta(&data.FrameMeta{Type: data.FrameTypeTimeSeriesMulti}) expectedFrames := data.Frames{expectedFrame} httpResponse := &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body))} - dataFrames, err := service.toDataFrames(httpResponse, refId) + dataFrames, err := service.toDataFrames(httpResponse, refId, false) require.NoError(t, err) if !reflect.DeepEqual(expectedFrames, dataFrames) { expectedFramesJSON, _ := json.Marshal(expectedFrames) dataFramesJSON, _ := json.Marshal(dataFrames) - t.Errorf("Data frames should have been equal but was, expected:\n%s\nactual:\n%s", expectedFramesJSON, dataFramesJSON) + t.Errorf("Data frames should have been equal but were not, expected:\n%s\nactual:\n%s", expectedFramesJSON, dataFramesJSON) } }) @@ -239,7 +240,7 @@ func TestConvertResponses(t *testing.T) { expectedFrames := data.Frames{} httpResponse := &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body))} - dataFrames, err := service.toDataFrames(httpResponse, refId) + dataFrames, err := service.toDataFrames(httpResponse, refId, false) require.NoError(t, err) if !reflect.DeepEqual(expectedFrames, dataFrames) { @@ -280,7 +281,42 @@ func TestConvertResponses(t *testing.T) { expectedFrames := data.Frames{expectedFrame} httpResponse := &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body))} - dataFrames, err := service.toDataFrames(httpResponse, refId) + dataFrames, err := service.toDataFrames(httpResponse, refId, false) + + require.NoError(t, err) + if !reflect.DeepEqual(expectedFrames, dataFrames) { + expectedFramesJSON, _ := json.Marshal(expectedFrames) + dataFramesJSON, _ := json.Marshal(dataFrames) + t.Errorf("Data frames should have been equal but was, expected:\n%s\nactual:\n%s", expectedFramesJSON, dataFramesJSON) + } + }) + + t.Run("Uses target as series name for alerts", func(*testing.T) { + body := ` + [ + { + "target": "aliasedTarget(target)", + "tags": { "name": "target", "fooTag": "fooValue", "barTag": "barValue", "int": 100, "float": 3.14 }, + "datapoints": [[50, 1], [null, 2], [100, 3]] + } + ]` + a := 50.0 + b := 100.0 + refId := "A" + expectedFrame := data.NewFrame("A", + data.NewField("time", nil, []time.Time{time.Unix(1, 0).UTC(), time.Unix(2, 0).UTC(), time.Unix(3, 0).UTC()}), + data.NewField("value", data.Labels{ + "fooTag": "fooValue", + "barTag": "barValue", + "int": "100", + "float": "3.14", + "name": "aliasedTarget(target)", + }, []*float64{&a, nil, &b}).SetConfig(&data.FieldConfig{DisplayNameFromDS: "aliasedTarget(target)"}), + ).SetMeta(&data.FrameMeta{Type: data.FrameTypeTimeSeriesMulti}) + expectedFrames := data.Frames{expectedFrame} + + httpResponse := &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body))} + dataFrames, err := service.toDataFrames(httpResponse, refId, true) require.NoError(t, err) if !reflect.DeepEqual(expectedFrames, dataFrames) {