CloudWatch: Static labels should use label name (#84611)

CloudWatch: static labels should use label name
This commit is contained in:
Isabella Siu 2024-03-18 17:30:59 -04:00 committed by GitHub
parent 2d1cd82a98
commit 0606a8e413
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 89 additions and 2 deletions

View File

@ -2,6 +2,7 @@ package cloudwatch
import ( import (
"fmt" "fmt"
"regexp"
"sort" "sort"
"strings" "strings"
"time" "time"
@ -12,6 +13,9 @@ import (
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
) )
// matches a dynamic label
var dynamicLabel = regexp.MustCompile(`\$\{.+\}`)
func (e *cloudWatchExecutor) parseResponse(startTime time.Time, endTime time.Time, metricDataOutputs []*cloudwatch.GetMetricDataOutput, func (e *cloudWatchExecutor) parseResponse(startTime time.Time, endTime time.Time, metricDataOutputs []*cloudwatch.GetMetricDataOutput,
queries []*models.CloudWatchQuery) ([]*responseWrapper, error) { queries []*models.CloudWatchQuery) ([]*responseWrapper, error) {
aggregatedResponse := aggregateResponse(metricDataOutputs) aggregatedResponse := aggregateResponse(metricDataOutputs)
@ -110,6 +114,8 @@ func getLabels(cloudwatchLabel string, query *models.CloudWatchQuery) data.Label
func buildDataFrames(startTime time.Time, endTime time.Time, aggregatedResponse models.QueryRowResponse, func buildDataFrames(startTime time.Time, endTime time.Time, aggregatedResponse models.QueryRowResponse,
query *models.CloudWatchQuery) (data.Frames, error) { query *models.CloudWatchQuery) (data.Frames, error) {
frames := data.Frames{} frames := data.Frames{}
hasStaticLabel := query.Label != "" && !dynamicLabel.MatchString(query.Label)
for _, metric := range aggregatedResponse.Metrics { for _, metric := range aggregatedResponse.Metrics {
label := *metric.Label label := *metric.Label
@ -169,10 +175,15 @@ func buildDataFrames(startTime time.Time, endTime time.Time, aggregatedResponse
timeField := data.NewField(data.TimeSeriesTimeFieldName, nil, timestamps) timeField := data.NewField(data.TimeSeriesTimeFieldName, nil, timestamps)
valueField := data.NewField(data.TimeSeriesValueFieldName, labels, points) valueField := data.NewField(data.TimeSeriesValueFieldName, labels, points)
valueField.SetConfig(&data.FieldConfig{DisplayNameFromDS: label, Links: createDataLinks(deepLink)}) name := label
// CloudWatch appends the dimensions to the returned label if the query label is not dynamic, so static labels need to be set
if hasStaticLabel {
name = query.Label
}
valueField.SetConfig(&data.FieldConfig{DisplayNameFromDS: name, Links: createDataLinks(deepLink)})
frame := data.Frame{ frame := data.Frame{
Name: label, Name: name,
Fields: []*data.Field{ Fields: []*data.Field{
timeField, timeField,
valueField, valueField,

View File

@ -376,6 +376,82 @@ func Test_buildDataFrames_uses_response_label_as_frame_name(t *testing.T) {
assert.Equal(t, "some label", frames[0].Name) assert.Equal(t, "some label", frames[0].Name)
}) })
t.Run("when non-static label set on query", func(t *testing.T) {
timestamp := time.Unix(0, 0)
response := &models.QueryRowResponse{
Metrics: []*cloudwatch.MetricDataResult{
{
Id: aws.String("lb3"),
Label: aws.String("some label"),
Timestamps: []*time.Time{
aws.Time(timestamp),
},
Values: []*float64{aws.Float64(23)},
StatusCode: aws.String("Complete"),
},
},
}
query := &models.CloudWatchQuery{
RefId: "refId1",
Region: "us-east-1",
Namespace: "AWS/ApplicationELB",
MetricName: "TargetResponseTime",
Dimensions: map[string][]string{
"LoadBalancer": {"lb1"},
"InstanceType": {"micro"},
"Resource": {"res"},
},
Statistic: "Average",
Period: 60,
MetricQueryType: models.MetricQueryTypeQuery,
MetricEditorMode: models.MetricEditorModeBuilder,
Label: "set ${AVG} label",
}
frames, err := buildDataFrames(startTime, endTime, *response, query)
require.NoError(t, err)
assert.Equal(t, "some label", frames[0].Name)
})
t.Run("unless static label set on query", func(t *testing.T) {
timestamp := time.Unix(0, 0)
response := &models.QueryRowResponse{
Metrics: []*cloudwatch.MetricDataResult{
{
Id: aws.String("lb3"),
Label: aws.String("some label"),
Timestamps: []*time.Time{
aws.Time(timestamp),
},
Values: []*float64{aws.Float64(23)},
StatusCode: aws.String("Complete"),
},
},
}
query := &models.CloudWatchQuery{
RefId: "refId1",
Region: "us-east-1",
Namespace: "AWS/ApplicationELB",
MetricName: "TargetResponseTime",
Dimensions: map[string][]string{
"LoadBalancer": {"lb1"},
"InstanceType": {"micro"},
"Resource": {"res"},
},
Statistic: "Average",
Period: 60,
MetricQueryType: models.MetricQueryTypeQuery,
MetricEditorMode: models.MetricEditorModeBuilder,
Label: "actual",
}
frames, err := buildDataFrames(startTime, endTime, *response, query)
require.NoError(t, err)
assert.Equal(t, "actual", frames[0].Name)
})
t.Run("Parse cloudwatch response", func(t *testing.T) { t.Run("Parse cloudwatch response", func(t *testing.T) {
timestamp := time.Unix(0, 0) timestamp := time.Unix(0, 0)
response := &models.QueryRowResponse{ response := &models.QueryRowResponse{