From cc6df0ac6b676ea7cc116ee6f893d1a6b7bafa0c Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Mon, 18 May 2020 12:25:58 +0200 Subject: [PATCH] CloudWatch: Clean up code (#24666) Signed-off-by: Arve Knudsen --- pkg/tsdb/cloudwatch/annotation_query.go | 10 +- pkg/tsdb/cloudwatch/cloudwatch.go | 20 +- pkg/tsdb/cloudwatch/cloudwatch_query.go | 1 - .../get_metric_data_executor_test.go | 24 +- pkg/tsdb/cloudwatch/log_actions.go | 9 +- pkg/tsdb/cloudwatch/log_actions_test.go | 10 +- pkg/tsdb/cloudwatch/log_query.go | 10 +- pkg/tsdb/cloudwatch/log_query_test.go | 25 +- pkg/tsdb/cloudwatch/metric_find_query.go | 445 +++++++++--------- pkg/tsdb/cloudwatch/metric_find_query_test.go | 85 ++-- pkg/tsdb/cloudwatch/query_transformer.go | 13 +- pkg/tsdb/cloudwatch/request_parser.go | 17 +- pkg/tsdb/cloudwatch/request_parser_test.go | 12 +- pkg/tsdb/cloudwatch/response_parser.go | 41 +- pkg/tsdb/cloudwatch/time_series_query.go | 139 +++--- pkg/tsdb/cloudwatch/time_series_query_test.go | 23 +- pkg/tsdb/cloudwatch/types.go | 2 +- 17 files changed, 438 insertions(+), 448 deletions(-) diff --git a/pkg/tsdb/cloudwatch/annotation_query.go b/pkg/tsdb/cloudwatch/annotation_query.go index bd99f6377f1..616fa693b23 100644 --- a/pkg/tsdb/cloudwatch/annotation_query.go +++ b/pkg/tsdb/cloudwatch/annotation_query.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/tsdb" + "github.com/grafana/grafana/pkg/util/errutil" ) func (e *CloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) { @@ -49,12 +50,12 @@ func (e *CloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo } resp, err := svc.DescribeAlarms(params) if err != nil { - return nil, errors.New("Failed to call cloudwatch:DescribeAlarms") + return nil, errutil.Wrap("failed to call cloudwatch:DescribeAlarms", err) } alarmNames = filterAlarms(resp, namespace, metricName, dimensions, statistics, period) } else { if region == "" || namespace == "" || metricName == "" || len(statistics) == 0 { - return result, errors.New("Invalid annotations query") + return result, errors.New("invalid annotations query") } var qd []*cloudwatch.Dimension @@ -80,7 +81,7 @@ func (e *CloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo } resp, err := svc.DescribeAlarmsForMetric(params) if err != nil { - return nil, errors.New("Failed to call cloudwatch:DescribeAlarmsForMetric") + return nil, errutil.Wrap("failed to call cloudwatch:DescribeAlarmsForMetric", err) } for _, alarm := range resp.MetricAlarms { alarmNames = append(alarmNames, alarm.AlarmName) @@ -107,7 +108,7 @@ func (e *CloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo } resp, err := svc.DescribeAlarmHistory(params) if err != nil { - return nil, errors.New("Failed to call cloudwatch:DescribeAlarmHistory") + return nil, errutil.Wrap("failed to call cloudwatch:DescribeAlarmHistory", err) } for _, history := range resp.AlarmHistoryItems { annotation := make(map[string]string) @@ -178,6 +179,7 @@ func filterAlarms(alarms *cloudwatch.DescribeAlarmsOutput, namespace string, met for _, s := range statistics { if *alarm.Statistic == s { found = true + break } } if !found { diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 8fa4ddb32d1..1d9b91a517f 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -98,7 +98,6 @@ func (e *CloudWatchExecutor) alertQuery(ctx context.Context, logsClient *cloudwa queryParams := queryContext.Queries[0].Model startQueryOutput, err := e.executeStartQuery(ctx, logsClient, queryParams, queryContext.TimeRange) - if err != nil { return nil, err } @@ -128,7 +127,6 @@ func (e *CloudWatchExecutor) alertQuery(ctx context.Context, logsClient *cloudwa } func (e *CloudWatchExecutor) Query(ctx context.Context, dsInfo *models.DataSource, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) { - var result *tsdb.Response e.DataSource = dsInfo /* @@ -146,8 +144,9 @@ func (e *CloudWatchExecutor) Query(ctx context.Context, dsInfo *models.DataSourc } queryType := queryParams.Get("type").MustString("") - var err error + var err error + var result *tsdb.Response switch queryType { case "metricFindQuery": result, err = e.executeMetricFindQuery(ctx, queryContext) @@ -187,7 +186,7 @@ func (e *CloudWatchExecutor) executeLogAlertQuery(ctx context.Context, queryCont queryParams.Set("queryId", *result.QueryId) - // Get Query Results + // Get query results getQueryResultsOutput, err := e.alertQuery(ctx, logsClient, queryContext) if err != nil { return nil, err @@ -204,14 +203,13 @@ func (e *CloudWatchExecutor) executeLogAlertQuery(ctx context.Context, queryCont } response := &tsdb.Response{ - Results: make(map[string]*tsdb.QueryResult), + Results: map[string]*tsdb.QueryResult{ + "A": { + RefId: "A", + Dataframes: [][]byte{dataframeEnc}, + }, + }, } - - response.Results["A"] = &tsdb.QueryResult{ - RefId: "A", - Dataframes: [][]byte{dataframeEnc}, - } - return response, nil } diff --git a/pkg/tsdb/cloudwatch/cloudwatch_query.go b/pkg/tsdb/cloudwatch/cloudwatch_query.go index 0830f00bfd4..4504eb44bb4 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch_query.go +++ b/pkg/tsdb/cloudwatch/cloudwatch_query.go @@ -37,7 +37,6 @@ func (q *cloudWatchQuery) isInferredSearchExpression() bool { if len(q.Dimensions) == 0 { return !q.MatchExact } - if !q.MatchExact { return true } diff --git a/pkg/tsdb/cloudwatch/get_metric_data_executor_test.go b/pkg/tsdb/cloudwatch/get_metric_data_executor_test.go index 6c3991b11aa..f1fddfbbeb9 100644 --- a/pkg/tsdb/cloudwatch/get_metric_data_executor_test.go +++ b/pkg/tsdb/cloudwatch/get_metric_data_executor_test.go @@ -7,7 +7,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/service/cloudwatch" - . "github.com/smartystreets/goconvey/convey" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var counter = 1 @@ -34,17 +35,12 @@ func (client *cloudWatchFakeClient) GetMetricDataWithContext(ctx aws.Context, in } func TestGetMetricDataExecutorTest(t *testing.T) { - Convey("TestGetMetricDataExecutorTest", t, func() { - Convey("pagination works", func() { - executor := &CloudWatchExecutor{} - inputs := &cloudwatch.GetMetricDataInput{MetricDataQueries: []*cloudwatch.MetricDataQuery{}} - res, err := executor.executeRequest(context.Background(), &cloudWatchFakeClient{}, inputs) - So(err, ShouldBeNil) - So(len(res), ShouldEqual, 2) - So(len(res[0].MetricDataResults[0].Values), ShouldEqual, 2) - So(*res[0].MetricDataResults[0].Values[1], ShouldEqual, 23.5) - So(*res[1].MetricDataResults[0].Values[0], ShouldEqual, 100) - }) - }) - + executor := &CloudWatchExecutor{} + inputs := &cloudwatch.GetMetricDataInput{MetricDataQueries: []*cloudwatch.MetricDataQuery{}} + res, err := executor.executeRequest(context.Background(), &cloudWatchFakeClient{}, inputs) + require.NoError(t, err) + require.Len(t, res, 2) + require.Len(t, res[0].MetricDataResults[0].Values, 2) + assert.Equal(t, 23.5, *res[0].MetricDataResults[0].Values[1]) + assert.Equal(t, 100.0, *res[1].MetricDataResults[0].Values[0]) } diff --git a/pkg/tsdb/cloudwatch/log_actions.go b/pkg/tsdb/cloudwatch/log_actions.go index 62bae34ae35..a6b5caed15f 100644 --- a/pkg/tsdb/cloudwatch/log_actions.go +++ b/pkg/tsdb/cloudwatch/log_actions.go @@ -22,7 +22,6 @@ func (e *CloudWatchExecutor) executeLogActions(ctx context.Context, queryContext for _, query := range queryContext.Queries { query := query - eg.Go(func() error { dataframe, err := e.executeLogAction(ectx, queryContext, query) if err != nil { @@ -66,7 +65,6 @@ func (e *CloudWatchExecutor) executeLogActions(ctx context.Context, queryContext return nil }) } - if err := eg.Wait(); err != nil { return nil, err } @@ -76,7 +74,6 @@ func (e *CloudWatchExecutor) executeLogActions(ctx context.Context, queryContext response := &tsdb.Response{ Results: make(map[string]*tsdb.QueryResult), } - for result := range resultChan { response.Results[result.RefId] = result } @@ -189,9 +186,9 @@ func (e *CloudWatchExecutor) handleGetLogEvents(ctx context.Context, logsClient func (e *CloudWatchExecutor) handleDescribeLogGroups(ctx context.Context, logsClient cloudwatchlogsiface.CloudWatchLogsAPI, parameters *simplejson.Json) (*data.Frame, error) { logGroupNamePrefix := parameters.Get("logGroupNamePrefix").MustString("") + var response *cloudwatchlogs.DescribeLogGroupsOutput = nil var err error - if len(logGroupNamePrefix) < 1 { response, err = logsClient.DescribeLogGroupsWithContext(ctx, &cloudwatchlogs.DescribeLogGroupsInput{ Limit: aws.Int64(parameters.Get("limit").MustInt64(50)), @@ -202,7 +199,6 @@ func (e *CloudWatchExecutor) handleDescribeLogGroups(ctx context.Context, logsCl LogGroupNamePrefix: aws.String(logGroupNamePrefix), }) } - if err != nil || response == nil { return nil, err } @@ -230,7 +226,7 @@ func (e *CloudWatchExecutor) executeStartQuery(ctx context.Context, logsClient c } if !startTime.Before(endTime) { - return nil, fmt.Errorf("invalid time range: Start time must be before end time") + return nil, fmt.Errorf("invalid time range: start time must be before end time") } // The fields @log and @logStream are always included in the results of a user's query @@ -312,7 +308,6 @@ func (e *CloudWatchExecutor) handleGetQueryResults(ctx context.Context, logsClie } dataFrame, err := logsResultsToDataframes(getQueryResultsOutput) - if err != nil { return nil, err } diff --git a/pkg/tsdb/cloudwatch/log_actions_test.go b/pkg/tsdb/cloudwatch/log_actions_test.go index 175e2ae4997..fab556de460 100644 --- a/pkg/tsdb/cloudwatch/log_actions_test.go +++ b/pkg/tsdb/cloudwatch/log_actions_test.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/tsdb" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) //*** @@ -112,7 +113,7 @@ func TestExecuteStartQuery(t *testing.T) { var expectedResponse *cloudwatchlogs.StartQueryOutput = nil assert.Equal(t, expectedResponse, response) - assert.Equal(t, fmt.Errorf("invalid time range: Start time must be before end time"), err) + assert.Equal(t, fmt.Errorf("invalid time range: start time must be before end time"), err) } @@ -187,8 +188,11 @@ func TestHandleGetQueryResults(t *testing.T) { }) frame, err := executor.handleGetQueryResults(context.Background(), logsClient, params, "A") - timeA, _ := time.Parse("2006-01-02 15:04:05.000", "2020-03-20 10:37:23.000") - timeB, _ := time.Parse("2006-01-02 15:04:05.000", "2020-03-20 10:40:43.000") + require.NoError(t, err) + timeA, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-20 10:37:23.000") + require.NoError(t, err) + timeB, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-20 10:40:43.000") + require.NoError(t, err) expectedTimeField := data.NewField("@timestamp", nil, []*time.Time{ aws.Time(timeA), aws.Time(timeB), }) diff --git a/pkg/tsdb/cloudwatch/log_query.go b/pkg/tsdb/cloudwatch/log_query.go index 95d0603baaf..f721ef79d61 100644 --- a/pkg/tsdb/cloudwatch/log_query.go +++ b/pkg/tsdb/cloudwatch/log_query.go @@ -32,7 +32,7 @@ func logsResultsToDataframes(response *cloudwatchlogs.GetQueryResultsOutput) (*d // Maintaining a list of field names in the order returned from CloudWatch // as just iterating over fieldValues would not give a consistent order - fieldNames := make([]*string, 0) + fieldNames := make([]string, 0) for i, row := range nonEmptyRows { for _, resultField := range row { @@ -42,7 +42,7 @@ func logsResultsToDataframes(response *cloudwatchlogs.GetQueryResultsOutput) (*d } if _, exists := fieldValues[*resultField.Field]; !exists { - fieldNames = append(fieldNames, resultField.Field) + fieldNames = append(fieldNames, *resultField.Field) // Check if field is time field if _, err := time.Parse(cloudWatchTSFormat, *resultField.Value); err == nil { @@ -67,11 +67,11 @@ func logsResultsToDataframes(response *cloudwatchlogs.GetQueryResultsOutput) (*d newFields := make([]*data.Field, 0) for _, fieldName := range fieldNames { - newFields = append(newFields, data.NewField(*fieldName, nil, fieldValues[*fieldName])) + newFields = append(newFields, data.NewField(fieldName, nil, fieldValues[fieldName])) - if *fieldName == "@timestamp" { + if fieldName == "@timestamp" { newFields[len(newFields)-1].SetConfig(&data.FieldConfig{Title: "Time"}) - } else if *fieldName == logStreamIdentifierInternal || *fieldName == logIdentifierInternal { + } else if fieldName == logStreamIdentifierInternal || fieldName == logIdentifierInternal { newFields[len(newFields)-1].SetConfig( &data.FieldConfig{ Custom: map[string]interface{}{ diff --git a/pkg/tsdb/cloudwatch/log_query_test.go b/pkg/tsdb/cloudwatch/log_query_test.go index 38a822ee5e8..05086c62c9c 100644 --- a/pkg/tsdb/cloudwatch/log_query_test.go +++ b/pkg/tsdb/cloudwatch/log_query_test.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) //*** @@ -126,10 +127,14 @@ func TestLogsResultsToDataframes(t *testing.T) { }, } - dataframes, _ := logsResultsToDataframes(fakeCloudwatchResponse) - timeA, _ := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 15:04:05.000") - timeB, _ := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 16:04:05.000") - timeC, _ := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 17:04:05.000") + dataframes, err := logsResultsToDataframes(fakeCloudwatchResponse) + require.NoError(t, err) + timeA, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 15:04:05.000") + require.NoError(t, err) + timeB, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 16:04:05.000") + require.NoError(t, err) + timeC, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 17:04:05.000") + require.NoError(t, err) timeVals := []*time.Time{ &timeA, &timeB, &timeC, } @@ -232,9 +237,12 @@ func TestGroupKeyGeneration(t *testing.T) { } func TestGroupingResults(t *testing.T) { - timeA, _ := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 15:04:05.000") - timeB, _ := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 16:04:05.000") - timeC, _ := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 17:04:05.000") + timeA, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 15:04:05.000") + require.NoError(t, err) + timeB, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 16:04:05.000") + require.NoError(t, err) + timeC, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-02 17:04:05.000") + require.NoError(t, err) timeVals := []*time.Time{ &timeA, &timeA, &timeA, &timeB, &timeB, &timeB, &timeC, &timeC, &timeC, } @@ -344,6 +352,7 @@ func TestGroupingResults(t *testing.T) { }, } - groupedResults, _ := groupResults(fakeDataFrame, []string{"@log"}) + groupedResults, err := groupResults(fakeDataFrame, []string{"@log"}) + require.NoError(t, err) assert.ElementsMatch(t, expectedGroupedFrames, groupedResults) } diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index 3cbecf23bf4..bf8ed013d64 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -21,9 +21,6 @@ import ( "github.com/grafana/grafana/pkg/tsdb" ) -var metricsMap map[string][]string -var dimensionsMap map[string][]string - type suggestData struct { Text string Value string @@ -34,197 +31,189 @@ type CustomMetricsCache struct { Cache []string } -var customMetricsMetricsMap map[string]map[string]map[string]*CustomMetricsCache -var customMetricsDimensionsMap map[string]map[string]map[string]*CustomMetricsCache -var regionCache sync.Map - -func init() { - metricsMap = map[string][]string{ - "AWS/ACMPrivateCA": {"CRLGenerated", "Failure", "MisconfiguredCRLBucket", "Success", "Time"}, - "AWS/AmazonMQ": {"ConsumerCount", "CpuCreditBalance", "CpuUtilization", "CurrentConnectionsCount", "DequeueCount", "DispatchCount", "EnqueueCount", "EnqueueTime", "ExpiredCount", "HeapUsage", "InflightCount", "JournalFilesForFastRecovery", "JournalFilesForFullRecovery", "MemoryUsage", "NetworkIn", "NetworkOut", "OpenTransactionsCount", "ProducerCount", "QueueSize", "StorePercentUsage", "TotalConsumerCount", "TotalMessageCount", "TotalProducerCount"}, - "AWS/ApiGateway": {"4XXError", "5XXError", "CacheHitCount", "CacheMissCount", "Count", "IntegrationLatency", "Latency"}, - "AWS/AppStream": {"ActualCapacity", "AvailableCapacity", "CapacityUtilization", "DesiredCapacity", "InUseCapacity", "InsufficientCapacityError", "PendingCapacity", "RunningCapacity"}, - "AWS/AppSync": {"4XXError", "5XXError", "Latency"}, - "AWS/ApplicationELB": {"ActiveConnectionCount", "ClientTLSNegotiationErrorCount", "ConsumedLCUs", "ELBAuthError", "ELBAuthFailure", "ELBAuthLatency", "ELBAuthRefreshTokenSuccess", "ELBAuthSuccess", "ELBAuthUserClaimsSizeExceeded", "HTTPCode_ELB_3XX_Count", "HTTPCode_ELB_4XX_Count", "HTTPCode_ELB_5XX_Count", "HTTPCode_Target_2XX_Count", "HTTPCode_Target_3XX_Count", "HTTPCode_Target_4XX_Count", "HTTPCode_Target_5XX_Count", "HTTP_Fixed_Response_Count", "HTTP_Redirect_Count", "HTTP_Redirect_Url_Limit_Exceeded_Count", "HealthyHostCount", "IPv6ProcessedBytes", "IPv6RequestCount", "LambdaInternalError", "LambdaTargetProcessedBytes", "LambdaUserError", "NewConnectionCount", "NonStickyRequestCount", "ProcessedBytes", "RejectedConnectionCount", "RequestCount", "RequestCountPerTarget", "RuleEvaluations", "StandardProcessedBytes", "TargetConnectionErrorCount", "TargetResponseTime", "TargetTLSNegotiationErrorCount", "UnHealthyHostCount"}, - "AWS/Athena": {"DataScannedInBytes", "EngineExecutionTime", "QueryPlanningTime", "QueryQueueTime", "QueryState", "QueryType", "ServiceProcessingTime", "TotalExecutionTime", "WorkGroup"}, - "AWS/AutoScaling": {"GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"}, - "AWS/Billing": {"EstimatedCharges"}, - "AWS/Chatbot": {"EventsThrottled", "EventsProcessed", "MessageDeliverySuccess", "MessageDeliveryFailure", "UnsupportedEvents"}, - "AWS/CloudFront": {"4xxErrorRate", "5xxErrorRate", "BytesDownloaded", "BytesUploaded", "Requests", "TotalErrorRate"}, - "AWS/CloudHSM": {"HsmKeysSessionOccupied", "HsmKeysTokenOccupied", "HsmSessionCount", "HsmSslCtxsOccupied", "HsmTemperature", "HsmUnhealthy", "HsmUsersAvailable", "HsmUsersMax", "InterfaceEth2OctetsInput", "InterfaceEth2OctetsOutput"}, - "AWS/CloudSearch": {"IndexUtilization", "Partitions", "SearchableDocuments", "SuccessfulRequests"}, - "AWS/CodeBuild": {"BuildDuration", "Builds", "DownloadSourceDuration", "Duration", "FailedBuilds", "FinalizingDuration", "InstallDuration", "PostBuildDuration", "PreBuildDuration", "ProvisioningDuration", "QueuedDuration", "SubmittedDuration", "SucceededBuilds", "UploadArtifactsDuration"}, - "AWS/Cognito": {"AccountTakeOverRisk", "CompromisedCredentialsRisk", "NoRisk", "OverrideBlock", "Risk"}, - "AWS/Connect": {"CallBackNotDialableNumber", "CallRecordingUploadError", "CallsBreachingConcurrencyQuota", "CallsPerInterval", "ConcurrentCalls", "ConcurrentCallsPercentage", "ContactFlowErrors", "ContactFlowFatalErrors", "LongestQueueWaitTime", "MisconfiguredPhoneNumbers", "MissedCalls", "PublicSigningKeyUsage", "QueueCapacityExceededError", "QueueSize", "ThrottledCalls", "ToInstancePacketLossRate"}, - "AWS/DDoSProtection": {"AllowedRequests", "BlockedRequests", "CountedRequests", "DDoSAttackBitsPerSecond", "DDoSAttackPacketsPerSecond", "DDoSAttackRequestsPerSecond", "DDoSDetected", "PassedRequests"}, - "AWS/DMS": {"CDCChangesDiskSource", "CDCChangesDiskTarget", "CDCChangesMemorySource", "CDCChangesMemoryTarget", "CDCIncomingChanges", "CDCLatencySource", "CDCLatencyTarget", "CDCThroughputBandwidthSource", "CDCThroughputBandwidthTarget", "CDCThroughputRowsSource", "CDCThroughputRowsTarget", "CPUUtilization", "FreeStorageSpace", "FreeableMemory", "FullLoadThroughputBandwidthSource", "FullLoadThroughputBandwidthTarget", "FullLoadThroughputRowsSource", "FullLoadThroughputRowsTarget", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "ReadIOPS", "ReadLatency", "ReadThroughput", "SwapUsage", "WriteIOPS", "WriteLatency", "WriteThroughput"}, - "AWS/DocDB": {"BackupRetentionPeriodStorageUsed", "BufferCacheHitRatio", "ChangeStreamLogSize", "CPUUtilization", "DatabaseConnections", "DBInstanceReplicaLag", "DBClusterReplicaLagMaximum", "DBClusterReplicaLagMinimum", "DiskQueueDepth", "EngineUptime", "FreeableMemory", "FreeLocalStorage", "NetworkReceiveThroughput", "NetworkThroughput", "NetworkTransmitThroughput", "ReadIOPS", "ReadLatency", "ReadThroughput", "SnapshotStorageUsed", "SwapUsage", "TotalBackupStorageBilled", "VolumeBytesUsed", "VolumeReadIOPs", "VolumeWriteIOPs", "WriteIOPS", "WriteLatency", "WriteThroughput"}, - "AWS/DX": {"ConnectionBpsEgress", "ConnectionBpsIngress", "ConnectionCRCErrorCount", "ConnectionLightLevelRx", "ConnectionLightLevelTx", "ConnectionPpsEgress", "ConnectionPpsIngress", "ConnectionState"}, - "AWS/DAX": {"CPUUtilization", "NetworkPacketsIn", "NetworkPacketsOut", "GetItemRequestCount", "BatchGetItemRequestCount", "BatchWriteItemRequestCount", "DeleteItemRequestCount", "PutItemRequestCount", "UpdateItemRequestCount", "TransactWriteItemsCount", "TransactGetItemsCount", "ItemCacheHits", "ItemCacheMisses", "QueryCacheHits", "QueryCacheMisses", "ScanCacheHits", "ScanCacheMisses", "TotalRequestCount", "ErrorRequestCount", "FaultRequestCount", "FailedRequestCount", "QueryRequestCount", "ScanRequestCount", "ClientConnections", "EstimatedDbSize", "EvictedSize"}, - "AWS/DynamoDB": {"ConditionalCheckFailedRequests", "ConsumedReadCapacityUnits", "ConsumedWriteCapacityUnits", "OnlineIndexConsumedWriteCapacity", "OnlineIndexPercentageProgress", "OnlineIndexThrottleEvents", "PendingReplicationCount", "ProvisionedReadCapacityUnits", "ProvisionedWriteCapacityUnits", "ReadThrottleEvents", "ReplicationLatency", "ReturnedBytes", "ReturnedItemCount", "ReturnedRecordsCount", "SuccessfulRequestLatency", "SystemErrors", "ThrottledRequests", "TimeToLiveDeletedItemCount", "UserErrors", "WriteThrottleEvents"}, - "AWS/EBS": {"BurstBalance", "VolumeConsumedReadWriteOps", "VolumeIdleTime", "VolumeQueueLength", "VolumeReadBytes", "VolumeReadOps", "VolumeThroughputPercentage", "VolumeTotalReadTime", "VolumeTotalWriteTime", "VolumeWriteBytes", "VolumeWriteOps"}, - "AWS/EC2": {"CPUCreditBalance", "CPUCreditUsage", "CPUSurplusCreditBalance", "CPUSurplusCreditsCharged", "CPUUtilization", "DiskReadBytes", "DiskReadOps", "DiskWriteBytes", "DiskWriteOps", "EBSByteBalance%", "EBSIOBalance%", "EBSReadBytes", "EBSReadOps", "EBSWriteBytes", "EBSWriteOps", "NetworkIn", "NetworkOut", "NetworkPacketsIn", "NetworkPacketsOut", "StatusCheckFailed", "StatusCheckFailed_Instance", "StatusCheckFailed_System"}, - "AWS/EC2/API": {"ClientErrors", "RequestLimitExceeded", "ServerErrors", "SuccessfulCalls"}, - "AWS/EC2Spot": {"AvailableInstancePoolsCount", "BidsSubmittedForCapacity", "EligibleInstancePoolCount", "FulfilledCapacity", "MaxPercentCapacityAllocation", "PendingCapacity", "PercentCapacityAllocation", "TargetCapacity", "TerminatingCapacity"}, - "AWS/ECS": {"CPUReservation", "CPUUtilization", "GPUReservation", "MemoryReservation", "MemoryUtilization"}, - "AWS/EFS": {"BurstCreditBalance", "ClientConnections", "DataReadIOBytes", "DataWriteIOBytes", "MetadataIOBytes", "PercentIOLimit", "PermittedThroughput", "TotalIOBytes"}, - "AWS/ELB": {"BackendConnectionErrors", "EstimatedALBActiveConnectionCount", "EstimatedALBConsumedLCUs", "EstimatedALBNewConnectionCount", "EstimatedProcessedBytes", "HTTPCode_Backend_2XX", "HTTPCode_Backend_3XX", "HTTPCode_Backend_4XX", "HTTPCode_Backend_5XX", "HTTPCode_ELB_4XX", "HTTPCode_ELB_5XX", "HealthyHostCount", "Latency", "RequestCount", "SpilloverCount", "SurgeQueueLength", "UnHealthyHostCount"}, - "AWS/ES": {"AutomatedSnapshotFailure", "CPUCreditBalance", "CPUUtilization", "ClusterIndexWritesBlocked", "ClusterStatus.green", "ClusterStatus.red", "ClusterStatus.yellow", "ClusterUsedSpace", "DeletedDocuments", "DiskQueueDepth", "ElasticsearchRequests", "FreeStorageSpace", "IndexingLatency", "IndexingRate", "InvalidHostHeaderRequests", "JVMGCOldCollectionCount", "JVMGCOldCollectionTime", "JVMGCYoungCollectionCount", "JVMGCYoungCollectionTime", "JVMMemoryPressure", "KMSKeyError", "KMSKeyInaccessible", "KibanaHealthyNodes", "MasterCPUCreditBalance", "MasterCPUUtilization", "MasterFreeStorageSpace", "MasterJVMMemoryPressure", "MasterReachableFromNode", "Nodes", "ReadIOPS", "ReadLatency", "ReadThroughput", "RequestCount", "SearchLatency", "SearchRate", "SearchableDocuments", "SysMemoryUtilization", "ThreadpoolBulkQueue", "ThreadpoolBulkRejected", "ThreadpoolBulkThreads", "ThreadpoolForce_mergeQueue", "ThreadpoolForce_mergeRejected", "ThreadpoolForce_mergeThreads", "ThreadpoolIndexQueue", "ThreadpoolIndexRejected", "ThreadpoolIndexThreads", "ThreadpoolSearchQueue", "ThreadpoolSearchRejected", "ThreadpoolSearchThreads", "WriteIOPS", "WriteLatency", "WriteThroughput"}, - "AWS/ElastiCache": {"ActiveDefragHits", "BytesReadIntoMemcached", "BytesUsedForCache", "BytesUsedForCacheItems", "BytesUsedForHash", "BytesWrittenOutFromMemcached", "CPUUtilization", "CacheHits", "CacheMisses", "CasBadval", "CasHits", "CasMisses", "CmdConfigGet", "CmdConfigSet", "CmdFlush", "CmdGet", "CmdSet", "CmdTouch", "CurrConfig", "CurrConnections", "CurrItems", "DecrHits", "DecrMisses", "DeleteHits", "DeleteMisses", "EngineCPUUtilization", "EvictedUnfetched", "Evictions", "ExpiredUnfetched", "FreeableMemory", "GetHits", "GetMisses", "GetTypeCmds", "HashBasedCmds", "HyperLogLogBasedCmds", "IncrHits", "IncrMisses", "KeyBasedCmds", "ListBasedCmds", "NetworkBytesIn", "NetworkBytesOut", "NewConnections", "NewItems", "Reclaimed", "ReplicationBytes", "ReplicationLag", "SaveInProgress", "SetBasedCmds", "SetTypeCmds", "SlabsMoved", "SortedSetBasedCmds", "StringBasedCmds", "SwapUsage", "TouchHits", "TouchMisses", "UnusedMemory"}, - "AWS/ElasticBeanstalk": {"ApplicationLatencyP10", "ApplicationLatencyP50", "ApplicationLatencyP75", "ApplicationLatencyP85", "ApplicationLatencyP90", "ApplicationLatencyP95", "ApplicationLatencyP99", "ApplicationLatencyP99.9", "ApplicationRequests2xx", "ApplicationRequests3xx", "ApplicationRequests4xx", "ApplicationRequests5xx", "ApplicationRequestsTotal", "CPUIdle", "CPUIowait", "CPUIrq", "CPUNice", "CPUSoftirq", "CPUSystem", "CPUUser", "EnvironmentHealth", "InstanceHealth", "InstancesDegraded", "InstancesInfo", "InstancesNoData", "InstancesOk", "InstancesPending", "InstancesSevere", "InstancesUnknown", "InstancesWarning", "LoadAverage1min", "LoadAverage5min", "RootFilesystemUtil"}, - "AWS/ElasticInference": {"AcceleratorHealthCheckFailed", "AcceleratorMemoryUsage", "ConnectivityCheckFailed"}, - "AWS/ElasticMapReduce": {"AppsCompleted", "AppsFailed", "AppsKilled", "AppsPending", "AppsRunning", "AppsSubmitted", "BackupFailed", "CapacityRemainingGB", "Cluster Status", "ContainerAllocated", "ContainerPending", "ContainerPendingRatio", "ContainerReserved", "CoreNodesPending", "CoreNodesRunning", "CorruptBlocks", "DfsPendingReplicationBlocks", "HBase", "HDFSBytesRead", "HDFSBytesWritten", "HDFSUtilization", "HbaseBackupFailed", "IO", "IsIdle", "JobsFailed", "JobsRunning", "LiveDataNodes", "LiveTaskTrackers", "MRActiveNodes", "MRDecommissionedNodes", "MRLostNodes", "MRRebootedNodes", "MRTotalNodes", "MRUnhealthyNodes", "Map/Reduce", "MapSlotsOpen", "MapTasksRemaining", "MapTasksRunning", "MemoryAllocatedMB", "MemoryAvailableMB", "MemoryReservedMB", "MemoryTotalMB", "MissingBlocks", "MostRecentBackupDuration", "Node Status", "PendingDeletionBlocks", "ReduceSlotsOpen", "ReduceTasksRemaining", "ReduceTasksRunning", "RemainingMapTasksPerSlot", "S3BytesRead", "S3BytesWritten", "TaskNodesPending", "TaskNodesRunning", "TimeSinceLastSuccessfulBackup", "TotalLoad", "UnderReplicatedBlocks", "YARNMemoryAvailablePercentage"}, - "AWS/ElasticTranscoder": {"Billed Audio Output", "Billed HD Output", "Billed SD Output", "Errors", "Jobs Completed", "Jobs Errored", "Outputs per Job", "Standby Time", "Throttles"}, - "AWS/Events": {"DeadLetterInvocations", "FailedInvocations", "Invocations", "MatchedEvents", "ThrottledRules", "TriggeredRules"}, - "AWS/FSx": {"DataReadBytes", "DataReadOperations", "DataWriteBytes", "DataWriteOperations", "FreeDataStorageCapacity", "MetadataOperations"}, - "AWS/Firehose": {"BackupToS3.Bytes", "BackupToS3.DataFreshness", "BackupToS3.Records", "BackupToS3.Success", "DataReadFromKinesisStream.Bytes", "DataReadFromKinesisStream.Records", "DeliveryToElasticsearch.Bytes", "DeliveryToElasticsearch.Records", "DeliveryToElasticsearch.Success", "DeliveryToRedshift.Bytes", "DeliveryToRedshift.Records", "DeliveryToRedshift.Success", "DeliveryToS3.Bytes", "DeliveryToS3.DataFreshness", "DeliveryToS3.Records", "DeliveryToS3.Success", "DeliveryToSplunk.Bytes", "DeliveryToSplunk.DataFreshness", "DeliveryToSplunk.Records", "DeliveryToSplunk.Success", "DescribeDeliveryStream.Latency", "DescribeDeliveryStream.Requests", "ExecuteProcessing.Duration", "ExecuteProcessing.Success", "FailedConversion.Bytes", "FailedConversion.Records", "IncomingBytes", "IncomingRecords", "KinesisMillisBehindLatest", "ListDeliveryStreams.Latency", "ListDeliveryStreams.Requests", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Requests", "PutRecordBatch.Bytes", "PutRecordBatch.Latency", "PutRecordBatch.Records", "PutRecordBatch.Requests", "SucceedConversion.Bytes", "SucceedConversion.Records", "SucceedProcessing.Bytes", "SucceedProcessing.Records", "ThrottledDescribeStream", "ThrottledGetRecords", "ThrottledGetShardIterator", "UpdateDeliveryStream.Latency", "UpdateDeliveryStream.Requests"}, - "AWS/GameLift": {"ActivatingGameSessions", "ActiveGameSessions", "ActiveInstances", "ActiveServerProcesses", "AvailableGameSessions", "AverageWaitTime", "CurrentPlayerSessions", "CurrentTickets", "DesiredInstances", "FirstChoiceNotViable", "FirstChoiceOutOfCapacity", "GameSessionInterruptions", "HealthyServerProcesses", "IdleInstances", "InstanceInterruptions", "LowestLatencyPlacement", "LowestPricePlacement", "MatchAcceptancesTimedOut", "MatchesAccepted", "MatchesCreated", "MatchesPlaced", "MatchesRejected", "MaxInstances", "MinInstances", "PercentAvailableGameSessions", "PercentHealthyServerProcesses", "PercentIdleInstances", "Placement", "PlacementsCanceled", "PlacementsFailed", "PlacementsStarted", "PlacementsSucceeded", "PlacementsTimedOut", "PlayerSessionActivations", "PlayersStarted", "QueueDepth", "RuleEvaluationsFailed", "RuleEvaluationsPassed", "ServerProcessAbnormalTerminations", "ServerProcessActivations", "ServerProcessTerminations", "TicketsFailed", "TicketsStarted", "TicketsTimedOut", "TimeToMatch", "TimeToTicketSuccess"}, - "AWS/Glue": {"glue.driver.BlockManager.disk.diskSpaceUsed_MB", "glue.driver.ExecutorAllocationManager.executors.numberAllExecutors", "glue.driver.ExecutorAllocationManager.executors.numberMaxNeededExecutors", "glue.driver.aggregate.bytesRead", "glue.driver.aggregate.elapsedTime", "glue.driver.aggregate.numCompletedStages", "glue.driver.aggregate.numCompletedTasks", "glue.driver.aggregate.numFailedTasks", "glue.driver.aggregate.numKilledTasks", "glue.driver.aggregate.recordsRead", "glue.driver.aggregate.shuffleBytesWritten", "glue.driver.aggregate.shuffleLocalBytesRead", "glue.driver.jvm.heap.usage glue.executorId.jvm.heap.usage glue.ALL.jvm.heap.usage", "glue.driver.jvm.heap.used glue.executorId.jvm.heap.used glue.ALL.jvm.heap.used", "glue.driver.s3.filesystem.read_bytes glue.executorId.s3.filesystem.read_bytes glue.ALL.s3.filesystem.read_bytes", "glue.driver.s3.filesystem.write_bytes glue.executorId.s3.filesystem.write_bytes glue.ALL.s3.filesystem.write_bytes", "glue.driver.system.cpuSystemLoad glue.executorId.system.cpuSystemLoad glue.ALL.system.cpuSystemLoad"}, - "AWS/Inspector": {"TotalAssessmentRunFindings", "TotalAssessmentRuns", "TotalHealthyAgents", "TotalMatchingAgents"}, - "AWS/IoT": {"CanceledJobExecutionCount", "CanceledJobExecutionTotalCount", "ClientError", "Connect.AuthError", "Connect.ClientError", "Connect.ServerError", "Connect.Success", "Connect.Throttle", "DeleteThingShadow.Accepted", "FailedJobExecutionCount", "FailedJobExecutionTotalCount", "Failure", "GetThingShadow.Accepted", "InProgressJobExecutionCount", "InProgressJobExecutionTotalCount", "NonCompliantResources", "NumLogBatchesFailedToPublishThrottled", "NumLogEventsFailedToPublishThrottled", "ParseError", "Ping.Success", "PublishIn.AuthError", "PublishIn.ClientError", "PublishIn.ServerError", "PublishIn.Success", "PublishIn.Throttle", "PublishOut.AuthError", "PublishOut.ClientError", "PublishOut.Success", "QueuedJobExecutionCount", "QueuedJobExecutionTotalCount", "RejectedJobExecutionCount", "RejectedJobExecutionTotalCount", "RemovedJobExecutionCount", "RemovedJobExecutionTotalCount", "ResourcesEvaluated", "RuleMessageThrottled", "RuleNotFound", "RulesExecuted", "ServerError", "Subscribe.AuthError", "Subscribe.ClientError", "Subscribe.ServerError", "Subscribe.Success", "Subscribe.Throttle", "SuccededJobExecutionCount", "SuccededJobExecutionTotalCount", "Success", "TopicMatch", "Unsubscribe.ClientError", "Unsubscribe.ServerError", "Unsubscribe.Success", "Unsubscribe.Throttle", "UpdateThingShadow.Accepted", "Violations", "ViolationsCleared", "ViolationsInvalidated"}, - "AWS/IoTAnalytics": {"ActionExecution", "ActivityExecutionError", "IncomingMessages"}, - "AWS/KMS": {"SecondsUntilKeyMaterialExpiration"}, - "AWS/Kafka": {"ActiveControllerCount", "BytesInPerSec", "BytesOutPerSec", "CpuIdle", "CpuSystem", "CpuUser", "FetchConsumerLocalTimeMsMean", "FetchConsumerRequestQueueTimeMsMean", "FetchConsumerResponseQueueTimeMsMean", "FetchConsumerResponseSendTimeMsMean", "FetchConsumerTotalTimeMsMean", "FetchFollowerLocalTimeMsMean", "FetchFollowerRequestQueueTimeMsMean", "FetchFollowerResponseQueueTimeMsMean", "FetchFollowerResponseSendTimeMsMean", "FetchFollowerTotalTimeMsMean", "FetchMessageConversionsPerSec", "FetchThrottleByteRate", "FetchThrottleQueueSize", "FetchThrottleTime", "GlobalPartitionCount", "GlobalTopicCount", "KafkaAppLogsDiskUsed", "KafkaDataLogsDiskUsed", "LeaderCount", "MemoryBuffered", "MemoryCached", "MemoryFree", "MemoryUsed", "MessagesInPerSec", "NetworkProcessorAvgIdlePercent", "NetworkRxDropped", "NetworkRxErrors", "NetworkRxPackets", "NetworkTxDropped", "NetworkTxErrors", "NetworkTxPackets", "OfflinePartitionsCount", "PartitionCount", "ProduceLocalTimeMsMean", "ProduceMessageConversionsPerSec", "ProduceMessageConversionsTimeMsMean", "ProduceRequestQueueTimeMsMean", "ProduceResponseQueueTimeMsMean", "ProduceResponseSendTimeMsMean", "ProduceThrottleByteRate", "ProduceThrottleQueueSize", "ProduceThrottleTime", "ProduceTotalTimeMsMean", "RequestBytesMean", "RequestExemptFromThrottleTime", "RequestHandlerAvgIdlePercent", "RequestThrottleQueueSize", "RequestThrottleTime", "RequestTime", "RootDiskUsed", "SwapFree", "SwapUsed", "UnderMinIsrPartitionCount", "UnderReplicatedPartitions", "ZooKeeperRequestLatencyMsMean", "ZooKeeperSessionState"}, - "AWS/Kinesis": {"GetRecords.Bytes", "GetRecords.IteratorAge", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Records", "GetRecords.Success", "IncomingBytes", "IncomingRecords", "IteratorAgeMilliseconds", "OutgoingBytes", "OutgoingRecords", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "ReadProvisionedThroughputExceeded", "SubscribeToShard.RateExceeded", "SubscribeToShard.Success", "SubscribeToShardEvent.Bytes", "SubscribeToShardEvent.MillisBehindLatest", "SubscribeToShardEvent.Records", "SubscribeToShardEvent.Success", "WriteProvisionedThroughputExceeded"}, - "AWS/KinesisAnalytics": {"Bytes", "InputProcessing.DroppedRecords", "InputProcessing.Duration", "InputProcessing.OkBytes", "InputProcessing.OkRecords", "InputProcessing.ProcessingFailedRecords", "InputProcessing.Success", "KPUs", "LambdaDelivery.DeliveryFailedRecords", "LambdaDelivery.Duration", "LambdaDelivery.OkRecords", "MillisBehindLatest", "Records", "Success"}, - "AWS/KinesisVideo": {"GetHLSMasterPlaylist.Latency", "GetHLSMasterPlaylist.Requests", "GetHLSMasterPlaylist.Success", "GetHLSMediaPlaylist.Latency", "GetHLSMediaPlaylist.Requests", "GetHLSMediaPlaylist.Success", "GetHLSStreamingSessionURL.Latency", "GetHLSStreamingSessionURL.Requests", "GetHLSStreamingSessionURL.Success", "GetMP4InitFragment.Latency", "GetMP4InitFragment.Requests", "GetMP4InitFragment.Success", "GetMP4MediaFragment.Latency", "GetMP4MediaFragment.OutgoingBytes", "GetMP4MediaFragment.Requests", "GetMP4MediaFragment.Success", "GetMedia.ConnectionErrors", "GetMedia.MillisBehindNow", "GetMedia.OutgoingBytes", "GetMedia.OutgoingFragments", "GetMedia.OutgoingFrames", "GetMedia.Requests", "GetMedia.Success", "GetMediaForFragmentList.OutgoingBytes", "GetMediaForFragmentList.OutgoingFragments", "GetMediaForFragmentList.OutgoingFrames", "GetMediaForFragmentList.Requests", "GetMediaForFragmentList.Success", "GetTSFragment.Latency", "GetTSFragment.OutgoingBytes", "GetTSFragment.Requests", "GetTSFragment.Success", "ListFragments.Latency", "PutMedia.ActiveConnections", "PutMedia.BufferingAckLatency", "PutMedia.ConnectionErrors", "PutMedia.ErrorAckCount", "PutMedia.FragmentIngestionLatency", "PutMedia.FragmentPersistLatency", "PutMedia.IncomingBytes", "PutMedia.IncomingFragments", "PutMedia.IncomingFrames", "PutMedia.Latency", "PutMedia.PersistedAckLatency", "PutMedia.ReceivedAckLatency", "PutMedia.Requests", "PutMedia.Success"}, - "AWS/Lambda": {"ConcurrentExecutions", "DeadLetterErrors", "Duration", "Errors", "Invocations", "IteratorAge", "Throttles", "UnreservedConcurrentExecutions"}, - "AWS/Lex": {"BotChannelAuthErrors", "BotChannelConfigurationErrors", "BotChannelInboundThrottledEvents", "BotChannelOutboundThrottledEvents", "BotChannelRequestCount", "BotChannelResponseCardErrors", "BotChannelSystemErrors", "MissedUtteranceCount", "RuntimeInvalidLambdaResponses", "RuntimeLambdaErrors", "RuntimePollyErrors", "RuntimeRequestCount", "RuntimeSucessfulRequestLatency", "RuntimeSystemErrors", "RuntimeThrottledEvents", "RuntimeUserErrors"}, - "AWS/Logs": {"DeliveryErrors", "DeliveryThrottling", "ForwardedBytes", "ForwardedLogEvents", "IncomingBytes", "IncomingLogEvents"}, - "AWS/ML": {"PredictCount", "PredictFailureCount"}, - "AWS/MediaConnect": {"ARQRecovered", "ARQRequests", "CATError", "CRCError", "ConnectedOutputs", "ContinuityCounter", "FECPackets", "FECRecovered", "NotRecoveredPackets", "OverflowPackets", "PATError", "PCRAccuracyError", "PCRError", "PIDError", "PMTError", "PTSError", "PacketLossPercent", "RecoveredPackets", "RoundTripTime", "SourceBitRate", "TSByteError", "TSSyncLoss", "TransportError"}, - "AWS/MediaConvert": {"AudioOutputSeconds", "Errors", "HDOutputSeconds", "JobsCompletedCount", "JobsErroredCount", "SDOutputSeconds", "StandbyTime", "TranscodingTime", "UHDOutputSeconds"}, - "AWS/MediaPackage": {"ActiveInput", "EgressBytes", "EgressRequestCount", "EgressResponseTime", "IngressBytes", "IngressResponseTime"}, - "AWS/MediaTailor": {"AdDecisionServer.Ads", "AdDecisionServer.Duration", "AdDecisionServer.Errors", "AdDecisionServer.FillRate", "AdDecisionServer.Timeouts", "AdNotReady", "Avails.Duration", "Avails.FillRate", "Avails.FilledDuration", "GetManifest.Errors", "Origin.Errors", "Origin.Timeouts"}, - "AWS/NATGateway": {"ActiveConnectionCount", "BytesInFromDestination", "BytesInFromSource", "BytesOutToDestination", "BytesOutToSource", "ConnectionAttemptCount", "ConnectionEstablishedCount", "ErrorPortAllocation", "IdleTimeoutCount", "PacketsDropCount", "PacketsInFromDestination", "PacketsInFromSource", "PacketsOutToDestination", "PacketsOutToSource"}, - "AWS/Neptune": {"CPUUtilization", "ClusterReplicaLag", "ClusterReplicaLagMaximum", "ClusterReplicaLagMinimum", "EngineUptime", "FreeLocalStorage", "FreeableMemory", "GremlinErrors", "GremlinHttp1xx", "GremlinHttp2xx", "GremlinHttp4xx", "GremlinHttp5xx", "GremlinRequests", "GremlinRequestsPerSec", "GremlinWebSocketAvailableConnections", "GremlinWebSocketClientErrors", "GremlinWebSocketServerErrors", "GremlinWebSocketSuccess", "Http100", "Http101", "Http1xx", "Http200", "Http2xx", "Http400", "Http403", "Http405", "Http413", "Http429", "Http4xx", "Http500", "Http501", "Http5xx", "LoaderErrors", "LoaderRequests", "NetworkReceiveThroughput", "NetworkThroughput", "NetworkTransmitThroughput", "SparqlErrors", "SparqlHttp1xx", "SparqlHttp2xx", "SparqlHttp4xx", "SparqlHttp5xx", "SparqlRequests", "SparqlRequestsPerSec", "StatusErrors", "StatusRequests", "VolumeBytesUsed", "VolumeReadIOPs", "VolumeWriteIOPs"}, - "AWS/NetworkELB": {"ActiveFlowCount", "ActiveFlowCount_TLS", "ClientTLSNegotiationErrorCount", "ConsumedLCUs", "HealthyHostCount", "NewFlowCount", "NewFlowCount_TLS", "ProcessedBytes", "ProcessedBytes_TLS", "TCP_Client_Reset_Count", "TCP_ELB_Reset_Count", "TCP_Target_Reset_Count", "TargetTLSNegotiationErrorCount", "UnHealthyHostCount"}, - "AWS/OpsWorks": {"cpu_idle", "cpu_nice", "cpu_steal", "cpu_system", "cpu_user", "cpu_waitio", "load_1", "load_15", "load_5", "memory_buffers", "memory_cached", "memory_free", "memory_swap", "memory_total", "memory_used", "procs"}, - "AWS/Polly": {"2XXCount", "4XXCount", "5XXCount", "RequestCharacters", "ResponseLatency"}, - "AWS/RDS": {"ActiveTransactions", "AuroraBinlogReplicaLag", "AuroraGlobalDBDataTransferBytes", "AuroraGlobalDBReplicatedWriteIO", "AuroraGlobalDBReplicationLag", "AuroraReplicaLag", "AuroraReplicaLagMaximum", "AuroraReplicaLagMinimum", "BacktrackChangeRecordsCreationRate", "BacktrackChangeRecordsStored", "BacktrackWindowActual", "BacktrackWindowAlert", "BackupRetentionPeriodStorageUsed", "BinLogDiskUsage", "BlockedTransactions", "BufferCacheHitRatio", "BurstBalance", "CPUCreditBalance", "CPUCreditUsage", "CPUUtilization", "CommitLatency", "CommitThroughput", "DDLLatency", "DDLThroughput", "DMLLatency", "DMLThroughput", "DatabaseConnections", "Deadlocks", "DeleteLatency", "DeleteThroughput", "DiskQueueDepth", "EngineUptime", "FailedSQLServerAgentJobsCount", "FreeLocalStorage", "FreeStorageSpace", "FreeableMemory", "InsertLatency", "InsertThroughput", "LoginFailures", "MaximumUsedTransactionIDs", "NetworkReceiveThroughput", "NetworkThroughput", "NetworkTransmitThroughput", "OldestReplicationSlotLag", "Queries", "RDSToAuroraPostgreSQLReplicaLag", "ReadIOPS", "ReadLatency", "ReadThroughput", "ReplicaLag", "ReplicationSlotDiskUsage", "ResultSetCacheHitRatio", "SelectLatency", "SelectThroughput", "ServerlessDatabaseCapacity", "SnapshotStorageUsed", "SwapUsage", "TotalBackupStorageBilled", "TransactionLogsDiskUsage", "TransactionLogsGeneration", "UpdateLatency", "UpdateThroughput", "VolumeBytesUsed", "VolumeReadIOPs", "VolumeWriteIOPs", "WriteIOPS", "WriteLatency", "WriteThroughput"}, - "AWS/Redshift": {"CPUUtilization", "DatabaseConnections", "HealthStatus", "MaintenanceMode", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "PercentageDiskSpaceUsed", "QueriesCompletedPerSecond", "QueryDuration", "QueryRuntimeBreakdown", "ReadIOPS", "ReadLatency", "ReadThroughput", "TotalTableCount", "WLMQueriesCompletedPerSecond", "WLMQueryDuration", "WLMQueueLength", "WriteIOPS", "WriteLatency", "WriteThroughput"}, - "AWS/Route53": {"ChildHealthCheckHealthyCount", "ConnectionTime", "HealthCheckPercentageHealthy", "HealthCheckStatus", "SSLHandshakeTime", "TimeToFirstByte"}, - "AWS/Route53Resolver": {"InboundQueryVolume", "OutboundQueryVolume", "OutboundQueryAggregatedVolume"}, - "AWS/S3": {"4xxErrors", "5xxErrors", "AllRequests", "BucketSizeBytes", "BytesDownloaded", "BytesUploaded", "DeleteRequests", "FirstByteLatency", "GetRequests", "HeadRequests", "ListRequests", "NumberOfObjects", "PostRequests", "PutRequests", "SelectRequests", "SelectReturnedBytes", "SelectScannedBytes", "TotalRequestLatency"}, - "AWS/SES": {"Bounce", "Clicks", "Complaint", "Delivery", "Opens", "Reject", "Rendering Failures", "Reputation.BounceRate", "Reputation.ComplaintRate", "Send"}, - "AWS/SNS": {"NumberOfMessagesPublished", "NumberOfNotificationsDelivered", "NumberOfNotificationsFailed", "NumberOfNotificationsFilteredOut", "NumberOfNotificationsFilteredOut-InvalidAttributes", "NumberOfNotificationsFilteredOut-NoMessageAttributes", "PublishSize", "SMSMonthToDateSpentUSD", "SMSSuccessRate"}, - "AWS/SQS": {"ApproximateAgeOfOldestMessage", "ApproximateNumberOfMessagesDelayed", "ApproximateNumberOfMessagesNotVisible", "ApproximateNumberOfMessagesVisible", "NumberOfEmptyReceives", "NumberOfMessagesDeleted", "NumberOfMessagesReceived", "NumberOfMessagesSent", "SentMessageSize"}, - "AWS/SWF": {"ActivityTaskScheduleToCloseTime", "ActivityTaskScheduleToStartTime", "ActivityTaskStartToCloseTime", "ActivityTasksCanceled", "ActivityTasksCompleted", "ActivityTasksFailed", "ConsumedCapacity", "DecisionTaskScheduleToStartTime", "DecisionTaskStartToCloseTime", "DecisionTasksCompleted", "PendingTasks", "ProvisionedBucketSize", "ProvisionedRefillRate", "ScheduledActivityTasksTimedOutOnClose", "ScheduledActivityTasksTimedOutOnStart", "StartedActivityTasksTimedOutOnClose", "StartedActivityTasksTimedOutOnHeartbeat", "StartedDecisionTasksTimedOutOnClose", "ThrottledEvents", "WorkflowStartToCloseTime", "WorkflowsCanceled", "WorkflowsCompleted", "WorkflowsContinuedAsNew", "WorkflowsFailed", "WorkflowsTerminated", "WorkflowsTimedOut"}, - "AWS/SageMaker": {"CPUUtilization", "DatasetObjectsAutoAnnotated", "DatasetObjectsHumanAnnotated", "DatasetObjectsLabelingFailed", "DiskUtilization", "GPUMemoryUtilization", "GPUUtilization", "Invocation4XXErrors", "Invocation5XXErrors", "Invocations", "InvocationsPerInstance", "JobsFailed", "JobsStopped", "JobsSucceeded", "MemoryUtilization", "ModelLatency", "OverheadLatency", "TotalDatasetObjectsLabeled"}, - "AWS/States": {"ActivitiesFailed", "ActivitiesHeartbeatTimedOut", "ActivitiesScheduled", "ActivitiesStarted", "ActivitiesSucceeded", "ActivitiesTimedOut", "ActivityRunTime", "ActivityScheduleTime", "ActivityTime", "ConsumedCapacity", "ExecutionThrottled", "ExecutionTime", "ExecutionsAborted", "ExecutionsFailed", "ExecutionsStarted", "ExecutionsSucceeded", "ExecutionsTimedOut", "LambdaFunctionRunTime", "LambdaFunctionScheduleTime", "LambdaFunctionTime", "LambdaFunctionsFailed", "LambdaFunctionsHeartbeatTimedOut", "LambdaFunctionsScheduled", "LambdaFunctionsStarted", "LambdaFunctionsSucceeded", "LambdaFunctionsTimedOut", "ProvisionedBucketSize", "ProvisionedRefillRate", "ThrottledEvents"}, - "AWS/StorageGateway": {"CacheFree", "CacheHitPercent", "CachePercentDirty", "CachePercentUsed", "CacheUsed", "CloudBytesDownloaded", "CloudBytesUploaded", "CloudDownloadLatency", "QueuedWrites", "ReadBytes", "ReadTime", "TimeSinceLastRecoveryPoint", "TotalCacheSize", "UploadBufferFree", "UploadBufferPercentUsed", "UploadBufferUsed", "WorkingStorageFree", "WorkingStoragePercentUsed", "WorkingStorageUsed", "WriteBytes", "WriteTime"}, - "AWS/Textract": {"ResponseTime", "ServerErrorCount", "SuccessfulRequestCount", "ThrottledCount", "UserErrorCount"}, - "AWS/ThingsGraph": {"EventStoreQueueSize", "FlowExecutionTime", "FlowExecutionsFailed", "FlowExecutionsStarted", "FlowExecutionsSucceeded", "FlowStepExecutionTime", "FlowStepExecutionsFailed", "FlowStepExecutionsStarted", "FlowStepExecutionsSucceeded"}, - "AWS/TransitGateway": {"BytesIn", "BytesOut", "PacketDropCountBlackhole", "PacketDropCountNoRoute", "PacketsIn", "PacketsOut"}, - "AWS/Translate": {"CharacterCount", "ResponseTime", "ServerErrorCount", "SuccessfulRequestCount", "ThrottledCount", "UserErrorCount"}, - "AWS/TrustedAdvisor": {"GreenChecks", "RedChecks", "RedResources", "ServiceLimitUsage", "YellowChecks", "YellowResources"}, - "AWS/Usage": {"CallCount"}, - "AWS/VPN": {"TunnelDataIn", "TunnelDataOut", "TunnelState"}, - "AWS/WorkSpaces": {"Available", "ConnectionAttempt", "ConnectionFailure", "ConnectionSuccess", "InSessionLatency", "Maintenance", "SessionDisconnect", "SessionLaunchTime", "Stopped", "Unhealthy", "UserConnected"}, - "ECS/ContainerInsights": {"ContainerInstanceCount", "CpuUtilized", "CpuReserved", "DeploymentCount", "DesiredTaskCount", "MemoryUtilized", "MemoryReserved", "NetworkRxBytes", "NetworkTxBytes", "PendingTaskCount", "RunningTaskCount", "ServiceCount", "StorageReadBytes", "StorageWriteBytes", "TaskCount", "TaskSetCount", "instance_cpu_limit", "instance_cpu_reserved_capacity", "instance_cpu_usage_total", "instance_cpu_utilization", "instance_filesystem_utilization", "instance_memory_limit", "instance_memory_reserved_capacity", "instance_memory_utliization", "instance_memory_working_set", "instance_network_total_bytes", "instance_number_of_running_tasks"}, - "ContainerInsights": {"cluster_failed_node_count", "cluster_node_count", "namespace_number_of_running_pods", "node_cpu_limit", "node_cpu_reserved_capacity", "node_cpu_usage_total", "node_cpu_utilization", "node_filesystem_utilization", "node_memory_limit", "node_memory_reserved_capacity", "node_memory_utilization", "node_memory_working_set", "node_network_total_bytes", "node_number_of_running_containers", "node_number_of_running_pods", "pod_cpu_reserved_capacity", "pod_cpu_utilization", "pod_cpu_utilization_over_pod_limit", "pod_memory_reserved_capacity", "pod_memory_utilization", "pod_memory_utilization_over_pod_limit", "pod_number_of_container_restarts", "pod_network_rx_bytes", "pod_network_tx_bytes", "service_number_of_running_pods"}, - "Rekognition": {"DetectedFaceCount", "DetectedLabelCount", "ResponseTime", "ServerErrorCount", "SuccessfulRequestCount", "ThrottledCount", "UserErrorCount"}, - "WAF": {"AllowedRequests", "BlockedRequests", "CountedRequests", "DDoSAttackBitsPerSecond", "DDoSAttackPacketsPerSecond", "DDoSAttackRequestsPerSecond", "DDoSDetected", "PassedRequests"}, - "AWS/Cassandra": {"AccountMaxReads", "AccountMaxTableLevelReads", "AccountMaxTableLevelWrites", "AccountMaxWrites", "AccountProvisionedReadCapacityUtilization", "AccountProvisionedWriteCapacityUtilization", "ConditionalCheckFailedRequests", "ConsumedReadCapacityUnits", "ConsumedWriteCapacityUnits", "MaxProvisionedTableReadCapacityUtilization", "MaxProvisionedTableWriteCapacityUtilization", "ReturnedItemCount", "ReturnedItemCountBySelect", "SuccessfulRequestCount", "SuccessfulRequestLatency", "SystemErrors", "UserErrors"}, - } - dimensionsMap = map[string][]string{ - "AWS/ACMPrivateCA": {}, - "AWS/AmazonMQ": {"Broker", "Queue", "Topic"}, - "AWS/ApiGateway": {"ApiName", "Method", "Resource", "Stage"}, - "AWS/AppStream": {"Fleet"}, - "AWS/AppSync": {"GraphQLAPIId"}, - "AWS/ApplicationELB": {"AvailabilityZone", "LoadBalancer", "TargetGroup"}, - "AWS/AutoScaling": {"AutoScalingGroupName"}, - "AWS/Billing": {"Currency", "LinkedAccount", "ServiceName"}, - "AWS/Chatbot": {"ConfigurationName"}, - "AWS/CloudFront": {"DistributionId", "Region"}, - "AWS/CloudHSM": {"ClusterId", "HsmId", "Region"}, - "AWS/CloudSearch": {"ClientId", "DomainName"}, - "AWS/CodeBuild": {"ProjectName"}, - "AWS/Cognito": {"Operation", "RiskLevel", "UserPoolId"}, - "AWS/Connect": {"InstanceId", "MetricGroup", "Participant", "QueueName", "Stream Type", "Type of Connection"}, - "AWS/DDoSProtection": {"Region", "Rule", "RuleGroup", "WebACL"}, - "AWS/DMS": {"ReplicationInstanceIdentifier", "ReplicationTaskIdentifier"}, - "AWS/DocDB": {"DBClusterIdentifier", "DBInstanceIdentifier", "Role"}, - "AWS/DX": {"ConnectionId"}, - "AWS/DAX": {"Account", "ClusterId", "NodeId"}, - "AWS/DynamoDB": {"GlobalSecondaryIndexName", "Operation", "ReceivingRegion", "StreamLabel", "TableName"}, - "AWS/EBS": {"VolumeId"}, - "AWS/EC2": {"AutoScalingGroupName", "ImageId", "InstanceId", "InstanceType"}, - "AWS/EC2/API": {}, - "AWS/EC2Spot": {"AvailabilityZone", "FleetRequestId", "InstanceType"}, - "AWS/ECS": {"ClusterName", "ServiceName"}, - "AWS/EFS": {"FileSystemId"}, - "AWS/ELB": {"AvailabilityZone", "LoadBalancerName"}, - "AWS/ES": {"ClientId", "DomainName"}, - "AWS/ElastiCache": {"CacheClusterId", "CacheNodeId"}, - "AWS/ElasticBeanstalk": {"EnvironmentName", "InstanceId"}, - "AWS/ElasticInference": {"ElasticInferenceAcceleratorId", "InstanceId"}, - "AWS/ElasticMapReduce": {"ClusterId", "JobFlowId", "JobId"}, - "AWS/ElasticTranscoder": {"Operation", "PipelineId"}, - "AWS/Events": {"RuleName"}, - "AWS/FSx": {}, - "AWS/Firehose": {"DeliveryStreamName"}, - "AWS/GameLift": {"FleetId", "InstanceType", "MatchmakingConfigurationName", "MatchmakingConfigurationName-RuleName", "MetricGroups", "OperatingSystem", "QueueName"}, - "AWS/Glue": {"JobName", "JobRunId", "Type"}, - "AWS/Inspector": {}, - "AWS/IoT": {"ActionType", "BehaviorName", "CheckName", "JobId", "Protocol", "RuleName", "ScheduledAuditName", "SecurityProfileName"}, - "AWS/IoTAnalytics": {"ActionType", "ChannelName", "DatasetName", "DatastoreName", "PipelineActivityName", "PipelineActivityType", "PipelineName"}, - "AWS/KMS": {"KeyId"}, - "AWS/Kafka": {"Broker ID", "Cluster Name", "Topic"}, - "AWS/Kinesis": {"ShardId", "StreamName"}, - "AWS/KinesisAnalytics": {"Application", "Flow", "Id"}, - "AWS/KinesisVideo": {}, - "AWS/Lambda": {"Alias", "ExecutedVersion", "FunctionName", "Resource"}, - "AWS/Lex": {"BotAlias", "BotChannelName", "BotName", "BotVersion", "InputMode", "Operation", "Source"}, - "AWS/Logs": {"DestinationType", "FilterName", "LogGroupName"}, - "AWS/ML": {"MLModelId", "RequestMode"}, - "AWS/MediaConnect": {}, - "AWS/MediaConvert": {"Job", "Operation", "Queue"}, - "AWS/MediaPackage": {"Channel", "No Dimension", "OriginEndpoint", "StatusCodeRange"}, - "AWS/MediaTailor": {"Configuration Name"}, - "AWS/NATGateway": {"NatGatewayId"}, - "AWS/Neptune": {"DBClusterIdentifier", "DatabaseClass", "EngineName", "Role"}, - "AWS/NetworkELB": {"AvailabilityZone", "LoadBalancer", "TargetGroup"}, - "AWS/OpsWorks": {"InstanceId", "LayerId", "StackId"}, - "AWS/Polly": {"Operation"}, - "AWS/RDS": {"DBClusterIdentifier", "DBInstanceIdentifier", "DatabaseClass", "DbClusterIdentifier", "EngineName", "Role", "SourceRegion"}, - "AWS/Redshift": {"ClusterIdentifier", "NodeID", "service class", "stage", "latency", "wlmid"}, - "AWS/Route53": {"HealthCheckId", "Region"}, - "AWS/Route53Resolver": {"EndpointId"}, - "AWS/S3": {"BucketName", "FilterId", "StorageType"}, - "AWS/SES": {}, - "AWS/SNS": {"Application", "Country", "Platform", "SMSType", "TopicName"}, - "AWS/SQS": {"QueueName"}, - "AWS/SWF": {"APIName", "ActivityTypeName", "ActivityTypeVersion", "DecisionName", "Domain", "TaskListName", "WorkflowTypeName", "WorkflowTypeVersion"}, - "AWS/SageMaker": {"EndpointName", "Host", "LabelingJobName", "VariantName"}, - "AWS/States": {"APIName", "ActivityArn", "LambdaFunctionArn", "StateMachineArn", "StateTransition"}, - "AWS/StorageGateway": {"GatewayId", "GatewayName", "VolumeId"}, - "AWS/Textract": {}, - "AWS/ThingsGraph": {"FlowTemplateId", "StepName", "SystemTemplateId"}, - "AWS/TransitGateway": {"TransitGateway"}, - "AWS/Translate": {"LanguagePair", "Operation"}, - "AWS/TrustedAdvisor": {}, - "AWS/Usage": {"Class", "Resource", "Service", "Type"}, - "AWS/VPN": {"TunnelIpAddress", "VpnId"}, - "AWS/WorkSpaces": {"DirectoryId", "WorkspaceId"}, - "ECS/ContainerInsights": {"ClusterName", "ServiceName", "TaskDefinitionFamily", "EC2InstanceId", "ContainerInstanceId"}, - "ContainerInsights": {"ClusterName", "NodeName", "Namespace", "InstanceId", "PodName", "Service"}, - "Rekognition": {}, - "WAF": {"Region", "Rule", "RuleGroup", "WebACL"}, - "AWS/Cassandra": {"Keyspace", "Operation", "TableName"}, - } - - customMetricsMetricsMap = make(map[string]map[string]map[string]*CustomMetricsCache) - customMetricsDimensionsMap = make(map[string]map[string]map[string]*CustomMetricsCache) +var customMetricsMetricsMap = make(map[string]map[string]map[string]*CustomMetricsCache) +var customMetricsDimensionsMap = make(map[string]map[string]map[string]*CustomMetricsCache) +var metricsMap = map[string][]string{ + "AWS/ACMPrivateCA": {"CRLGenerated", "Failure", "MisconfiguredCRLBucket", "Success", "Time"}, + "AWS/AmazonMQ": {"ConsumerCount", "CpuCreditBalance", "CpuUtilization", "CurrentConnectionsCount", "DequeueCount", "DispatchCount", "EnqueueCount", "EnqueueTime", "ExpiredCount", "HeapUsage", "InflightCount", "JournalFilesForFastRecovery", "JournalFilesForFullRecovery", "MemoryUsage", "NetworkIn", "NetworkOut", "OpenTransactionsCount", "ProducerCount", "QueueSize", "StorePercentUsage", "TotalConsumerCount", "TotalMessageCount", "TotalProducerCount"}, + "AWS/ApiGateway": {"4XXError", "5XXError", "CacheHitCount", "CacheMissCount", "Count", "IntegrationLatency", "Latency"}, + "AWS/AppStream": {"ActualCapacity", "AvailableCapacity", "CapacityUtilization", "DesiredCapacity", "InUseCapacity", "InsufficientCapacityError", "PendingCapacity", "RunningCapacity"}, + "AWS/AppSync": {"4XXError", "5XXError", "Latency"}, + "AWS/ApplicationELB": {"ActiveConnectionCount", "ClientTLSNegotiationErrorCount", "ConsumedLCUs", "ELBAuthError", "ELBAuthFailure", "ELBAuthLatency", "ELBAuthRefreshTokenSuccess", "ELBAuthSuccess", "ELBAuthUserClaimsSizeExceeded", "HTTPCode_ELB_3XX_Count", "HTTPCode_ELB_4XX_Count", "HTTPCode_ELB_5XX_Count", "HTTPCode_Target_2XX_Count", "HTTPCode_Target_3XX_Count", "HTTPCode_Target_4XX_Count", "HTTPCode_Target_5XX_Count", "HTTP_Fixed_Response_Count", "HTTP_Redirect_Count", "HTTP_Redirect_Url_Limit_Exceeded_Count", "HealthyHostCount", "IPv6ProcessedBytes", "IPv6RequestCount", "LambdaInternalError", "LambdaTargetProcessedBytes", "LambdaUserError", "NewConnectionCount", "NonStickyRequestCount", "ProcessedBytes", "RejectedConnectionCount", "RequestCount", "RequestCountPerTarget", "RuleEvaluations", "StandardProcessedBytes", "TargetConnectionErrorCount", "TargetResponseTime", "TargetTLSNegotiationErrorCount", "UnHealthyHostCount"}, + "AWS/Athena": {"DataScannedInBytes", "EngineExecutionTime", "QueryPlanningTime", "QueryQueueTime", "QueryState", "QueryType", "ServiceProcessingTime", "TotalExecutionTime", "WorkGroup"}, + "AWS/AutoScaling": {"GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"}, + "AWS/Billing": {"EstimatedCharges"}, + "AWS/Chatbot": {"EventsThrottled", "EventsProcessed", "MessageDeliverySuccess", "MessageDeliveryFailure", "UnsupportedEvents"}, + "AWS/CloudFront": {"4xxErrorRate", "5xxErrorRate", "BytesDownloaded", "BytesUploaded", "Requests", "TotalErrorRate"}, + "AWS/CloudHSM": {"HsmKeysSessionOccupied", "HsmKeysTokenOccupied", "HsmSessionCount", "HsmSslCtxsOccupied", "HsmTemperature", "HsmUnhealthy", "HsmUsersAvailable", "HsmUsersMax", "InterfaceEth2OctetsInput", "InterfaceEth2OctetsOutput"}, + "AWS/CloudSearch": {"IndexUtilization", "Partitions", "SearchableDocuments", "SuccessfulRequests"}, + "AWS/CodeBuild": {"BuildDuration", "Builds", "DownloadSourceDuration", "Duration", "FailedBuilds", "FinalizingDuration", "InstallDuration", "PostBuildDuration", "PreBuildDuration", "ProvisioningDuration", "QueuedDuration", "SubmittedDuration", "SucceededBuilds", "UploadArtifactsDuration"}, + "AWS/Cognito": {"AccountTakeOverRisk", "CompromisedCredentialsRisk", "NoRisk", "OverrideBlock", "Risk"}, + "AWS/Connect": {"CallBackNotDialableNumber", "CallRecordingUploadError", "CallsBreachingConcurrencyQuota", "CallsPerInterval", "ConcurrentCalls", "ConcurrentCallsPercentage", "ContactFlowErrors", "ContactFlowFatalErrors", "LongestQueueWaitTime", "MisconfiguredPhoneNumbers", "MissedCalls", "PublicSigningKeyUsage", "QueueCapacityExceededError", "QueueSize", "ThrottledCalls", "ToInstancePacketLossRate"}, + "AWS/DDoSProtection": {"AllowedRequests", "BlockedRequests", "CountedRequests", "DDoSAttackBitsPerSecond", "DDoSAttackPacketsPerSecond", "DDoSAttackRequestsPerSecond", "DDoSDetected", "PassedRequests"}, + "AWS/DMS": {"CDCChangesDiskSource", "CDCChangesDiskTarget", "CDCChangesMemorySource", "CDCChangesMemoryTarget", "CDCIncomingChanges", "CDCLatencySource", "CDCLatencyTarget", "CDCThroughputBandwidthSource", "CDCThroughputBandwidthTarget", "CDCThroughputRowsSource", "CDCThroughputRowsTarget", "CPUUtilization", "FreeStorageSpace", "FreeableMemory", "FullLoadThroughputBandwidthSource", "FullLoadThroughputBandwidthTarget", "FullLoadThroughputRowsSource", "FullLoadThroughputRowsTarget", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "ReadIOPS", "ReadLatency", "ReadThroughput", "SwapUsage", "WriteIOPS", "WriteLatency", "WriteThroughput"}, + "AWS/DocDB": {"BackupRetentionPeriodStorageUsed", "BufferCacheHitRatio", "ChangeStreamLogSize", "CPUUtilization", "DatabaseConnections", "DBInstanceReplicaLag", "DBClusterReplicaLagMaximum", "DBClusterReplicaLagMinimum", "DiskQueueDepth", "EngineUptime", "FreeableMemory", "FreeLocalStorage", "NetworkReceiveThroughput", "NetworkThroughput", "NetworkTransmitThroughput", "ReadIOPS", "ReadLatency", "ReadThroughput", "SnapshotStorageUsed", "SwapUsage", "TotalBackupStorageBilled", "VolumeBytesUsed", "VolumeReadIOPs", "VolumeWriteIOPs", "WriteIOPS", "WriteLatency", "WriteThroughput"}, + "AWS/DX": {"ConnectionBpsEgress", "ConnectionBpsIngress", "ConnectionCRCErrorCount", "ConnectionLightLevelRx", "ConnectionLightLevelTx", "ConnectionPpsEgress", "ConnectionPpsIngress", "ConnectionState"}, + "AWS/DAX": {"CPUUtilization", "NetworkPacketsIn", "NetworkPacketsOut", "GetItemRequestCount", "BatchGetItemRequestCount", "BatchWriteItemRequestCount", "DeleteItemRequestCount", "PutItemRequestCount", "UpdateItemRequestCount", "TransactWriteItemsCount", "TransactGetItemsCount", "ItemCacheHits", "ItemCacheMisses", "QueryCacheHits", "QueryCacheMisses", "ScanCacheHits", "ScanCacheMisses", "TotalRequestCount", "ErrorRequestCount", "FaultRequestCount", "FailedRequestCount", "QueryRequestCount", "ScanRequestCount", "ClientConnections", "EstimatedDbSize", "EvictedSize"}, + "AWS/DynamoDB": {"ConditionalCheckFailedRequests", "ConsumedReadCapacityUnits", "ConsumedWriteCapacityUnits", "OnlineIndexConsumedWriteCapacity", "OnlineIndexPercentageProgress", "OnlineIndexThrottleEvents", "PendingReplicationCount", "ProvisionedReadCapacityUnits", "ProvisionedWriteCapacityUnits", "ReadThrottleEvents", "ReplicationLatency", "ReturnedBytes", "ReturnedItemCount", "ReturnedRecordsCount", "SuccessfulRequestLatency", "SystemErrors", "ThrottledRequests", "TimeToLiveDeletedItemCount", "UserErrors", "WriteThrottleEvents"}, + "AWS/EBS": {"BurstBalance", "VolumeConsumedReadWriteOps", "VolumeIdleTime", "VolumeQueueLength", "VolumeReadBytes", "VolumeReadOps", "VolumeThroughputPercentage", "VolumeTotalReadTime", "VolumeTotalWriteTime", "VolumeWriteBytes", "VolumeWriteOps"}, + "AWS/EC2": {"CPUCreditBalance", "CPUCreditUsage", "CPUSurplusCreditBalance", "CPUSurplusCreditsCharged", "CPUUtilization", "DiskReadBytes", "DiskReadOps", "DiskWriteBytes", "DiskWriteOps", "EBSByteBalance%", "EBSIOBalance%", "EBSReadBytes", "EBSReadOps", "EBSWriteBytes", "EBSWriteOps", "NetworkIn", "NetworkOut", "NetworkPacketsIn", "NetworkPacketsOut", "StatusCheckFailed", "StatusCheckFailed_Instance", "StatusCheckFailed_System"}, + "AWS/EC2/API": {"ClientErrors", "RequestLimitExceeded", "ServerErrors", "SuccessfulCalls"}, + "AWS/EC2Spot": {"AvailableInstancePoolsCount", "BidsSubmittedForCapacity", "EligibleInstancePoolCount", "FulfilledCapacity", "MaxPercentCapacityAllocation", "PendingCapacity", "PercentCapacityAllocation", "TargetCapacity", "TerminatingCapacity"}, + "AWS/ECS": {"CPUReservation", "CPUUtilization", "GPUReservation", "MemoryReservation", "MemoryUtilization"}, + "AWS/EFS": {"BurstCreditBalance", "ClientConnections", "DataReadIOBytes", "DataWriteIOBytes", "MetadataIOBytes", "PercentIOLimit", "PermittedThroughput", "TotalIOBytes"}, + "AWS/ELB": {"BackendConnectionErrors", "EstimatedALBActiveConnectionCount", "EstimatedALBConsumedLCUs", "EstimatedALBNewConnectionCount", "EstimatedProcessedBytes", "HTTPCode_Backend_2XX", "HTTPCode_Backend_3XX", "HTTPCode_Backend_4XX", "HTTPCode_Backend_5XX", "HTTPCode_ELB_4XX", "HTTPCode_ELB_5XX", "HealthyHostCount", "Latency", "RequestCount", "SpilloverCount", "SurgeQueueLength", "UnHealthyHostCount"}, + "AWS/ES": {"AutomatedSnapshotFailure", "CPUCreditBalance", "CPUUtilization", "ClusterIndexWritesBlocked", "ClusterStatus.green", "ClusterStatus.red", "ClusterStatus.yellow", "ClusterUsedSpace", "DeletedDocuments", "DiskQueueDepth", "ElasticsearchRequests", "FreeStorageSpace", "IndexingLatency", "IndexingRate", "InvalidHostHeaderRequests", "JVMGCOldCollectionCount", "JVMGCOldCollectionTime", "JVMGCYoungCollectionCount", "JVMGCYoungCollectionTime", "JVMMemoryPressure", "KMSKeyError", "KMSKeyInaccessible", "KibanaHealthyNodes", "MasterCPUCreditBalance", "MasterCPUUtilization", "MasterFreeStorageSpace", "MasterJVMMemoryPressure", "MasterReachableFromNode", "Nodes", "ReadIOPS", "ReadLatency", "ReadThroughput", "RequestCount", "SearchLatency", "SearchRate", "SearchableDocuments", "SysMemoryUtilization", "ThreadpoolBulkQueue", "ThreadpoolBulkRejected", "ThreadpoolBulkThreads", "ThreadpoolForce_mergeQueue", "ThreadpoolForce_mergeRejected", "ThreadpoolForce_mergeThreads", "ThreadpoolIndexQueue", "ThreadpoolIndexRejected", "ThreadpoolIndexThreads", "ThreadpoolSearchQueue", "ThreadpoolSearchRejected", "ThreadpoolSearchThreads", "WriteIOPS", "WriteLatency", "WriteThroughput"}, + "AWS/ElastiCache": {"ActiveDefragHits", "BytesReadIntoMemcached", "BytesUsedForCache", "BytesUsedForCacheItems", "BytesUsedForHash", "BytesWrittenOutFromMemcached", "CPUUtilization", "CacheHits", "CacheMisses", "CasBadval", "CasHits", "CasMisses", "CmdConfigGet", "CmdConfigSet", "CmdFlush", "CmdGet", "CmdSet", "CmdTouch", "CurrConfig", "CurrConnections", "CurrItems", "DecrHits", "DecrMisses", "DeleteHits", "DeleteMisses", "EngineCPUUtilization", "EvictedUnfetched", "Evictions", "ExpiredUnfetched", "FreeableMemory", "GetHits", "GetMisses", "GetTypeCmds", "HashBasedCmds", "HyperLogLogBasedCmds", "IncrHits", "IncrMisses", "KeyBasedCmds", "ListBasedCmds", "NetworkBytesIn", "NetworkBytesOut", "NewConnections", "NewItems", "Reclaimed", "ReplicationBytes", "ReplicationLag", "SaveInProgress", "SetBasedCmds", "SetTypeCmds", "SlabsMoved", "SortedSetBasedCmds", "StringBasedCmds", "SwapUsage", "TouchHits", "TouchMisses", "UnusedMemory"}, + "AWS/ElasticBeanstalk": {"ApplicationLatencyP10", "ApplicationLatencyP50", "ApplicationLatencyP75", "ApplicationLatencyP85", "ApplicationLatencyP90", "ApplicationLatencyP95", "ApplicationLatencyP99", "ApplicationLatencyP99.9", "ApplicationRequests2xx", "ApplicationRequests3xx", "ApplicationRequests4xx", "ApplicationRequests5xx", "ApplicationRequestsTotal", "CPUIdle", "CPUIowait", "CPUIrq", "CPUNice", "CPUSoftirq", "CPUSystem", "CPUUser", "EnvironmentHealth", "InstanceHealth", "InstancesDegraded", "InstancesInfo", "InstancesNoData", "InstancesOk", "InstancesPending", "InstancesSevere", "InstancesUnknown", "InstancesWarning", "LoadAverage1min", "LoadAverage5min", "RootFilesystemUtil"}, + "AWS/ElasticInference": {"AcceleratorHealthCheckFailed", "AcceleratorMemoryUsage", "ConnectivityCheckFailed"}, + "AWS/ElasticMapReduce": {"AppsCompleted", "AppsFailed", "AppsKilled", "AppsPending", "AppsRunning", "AppsSubmitted", "BackupFailed", "CapacityRemainingGB", "Cluster Status", "ContainerAllocated", "ContainerPending", "ContainerPendingRatio", "ContainerReserved", "CoreNodesPending", "CoreNodesRunning", "CorruptBlocks", "DfsPendingReplicationBlocks", "HBase", "HDFSBytesRead", "HDFSBytesWritten", "HDFSUtilization", "HbaseBackupFailed", "IO", "IsIdle", "JobsFailed", "JobsRunning", "LiveDataNodes", "LiveTaskTrackers", "MRActiveNodes", "MRDecommissionedNodes", "MRLostNodes", "MRRebootedNodes", "MRTotalNodes", "MRUnhealthyNodes", "Map/Reduce", "MapSlotsOpen", "MapTasksRemaining", "MapTasksRunning", "MemoryAllocatedMB", "MemoryAvailableMB", "MemoryReservedMB", "MemoryTotalMB", "MissingBlocks", "MostRecentBackupDuration", "Node Status", "PendingDeletionBlocks", "ReduceSlotsOpen", "ReduceTasksRemaining", "ReduceTasksRunning", "RemainingMapTasksPerSlot", "S3BytesRead", "S3BytesWritten", "TaskNodesPending", "TaskNodesRunning", "TimeSinceLastSuccessfulBackup", "TotalLoad", "UnderReplicatedBlocks", "YARNMemoryAvailablePercentage"}, + "AWS/ElasticTranscoder": {"Billed Audio Output", "Billed HD Output", "Billed SD Output", "Errors", "Jobs Completed", "Jobs Errored", "Outputs per Job", "Standby Time", "Throttles"}, + "AWS/Events": {"DeadLetterInvocations", "FailedInvocations", "Invocations", "MatchedEvents", "ThrottledRules", "TriggeredRules"}, + "AWS/FSx": {"DataReadBytes", "DataReadOperations", "DataWriteBytes", "DataWriteOperations", "FreeDataStorageCapacity", "MetadataOperations"}, + "AWS/Firehose": {"BackupToS3.Bytes", "BackupToS3.DataFreshness", "BackupToS3.Records", "BackupToS3.Success", "DataReadFromKinesisStream.Bytes", "DataReadFromKinesisStream.Records", "DeliveryToElasticsearch.Bytes", "DeliveryToElasticsearch.Records", "DeliveryToElasticsearch.Success", "DeliveryToRedshift.Bytes", "DeliveryToRedshift.Records", "DeliveryToRedshift.Success", "DeliveryToS3.Bytes", "DeliveryToS3.DataFreshness", "DeliveryToS3.Records", "DeliveryToS3.Success", "DeliveryToSplunk.Bytes", "DeliveryToSplunk.DataFreshness", "DeliveryToSplunk.Records", "DeliveryToSplunk.Success", "DescribeDeliveryStream.Latency", "DescribeDeliveryStream.Requests", "ExecuteProcessing.Duration", "ExecuteProcessing.Success", "FailedConversion.Bytes", "FailedConversion.Records", "IncomingBytes", "IncomingRecords", "KinesisMillisBehindLatest", "ListDeliveryStreams.Latency", "ListDeliveryStreams.Requests", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Requests", "PutRecordBatch.Bytes", "PutRecordBatch.Latency", "PutRecordBatch.Records", "PutRecordBatch.Requests", "SucceedConversion.Bytes", "SucceedConversion.Records", "SucceedProcessing.Bytes", "SucceedProcessing.Records", "ThrottledDescribeStream", "ThrottledGetRecords", "ThrottledGetShardIterator", "UpdateDeliveryStream.Latency", "UpdateDeliveryStream.Requests"}, + "AWS/GameLift": {"ActivatingGameSessions", "ActiveGameSessions", "ActiveInstances", "ActiveServerProcesses", "AvailableGameSessions", "AverageWaitTime", "CurrentPlayerSessions", "CurrentTickets", "DesiredInstances", "FirstChoiceNotViable", "FirstChoiceOutOfCapacity", "GameSessionInterruptions", "HealthyServerProcesses", "IdleInstances", "InstanceInterruptions", "LowestLatencyPlacement", "LowestPricePlacement", "MatchAcceptancesTimedOut", "MatchesAccepted", "MatchesCreated", "MatchesPlaced", "MatchesRejected", "MaxInstances", "MinInstances", "PercentAvailableGameSessions", "PercentHealthyServerProcesses", "PercentIdleInstances", "Placement", "PlacementsCanceled", "PlacementsFailed", "PlacementsStarted", "PlacementsSucceeded", "PlacementsTimedOut", "PlayerSessionActivations", "PlayersStarted", "QueueDepth", "RuleEvaluationsFailed", "RuleEvaluationsPassed", "ServerProcessAbnormalTerminations", "ServerProcessActivations", "ServerProcessTerminations", "TicketsFailed", "TicketsStarted", "TicketsTimedOut", "TimeToMatch", "TimeToTicketSuccess"}, + "AWS/Glue": {"glue.driver.BlockManager.disk.diskSpaceUsed_MB", "glue.driver.ExecutorAllocationManager.executors.numberAllExecutors", "glue.driver.ExecutorAllocationManager.executors.numberMaxNeededExecutors", "glue.driver.aggregate.bytesRead", "glue.driver.aggregate.elapsedTime", "glue.driver.aggregate.numCompletedStages", "glue.driver.aggregate.numCompletedTasks", "glue.driver.aggregate.numFailedTasks", "glue.driver.aggregate.numKilledTasks", "glue.driver.aggregate.recordsRead", "glue.driver.aggregate.shuffleBytesWritten", "glue.driver.aggregate.shuffleLocalBytesRead", "glue.driver.jvm.heap.usage glue.executorId.jvm.heap.usage glue.ALL.jvm.heap.usage", "glue.driver.jvm.heap.used glue.executorId.jvm.heap.used glue.ALL.jvm.heap.used", "glue.driver.s3.filesystem.read_bytes glue.executorId.s3.filesystem.read_bytes glue.ALL.s3.filesystem.read_bytes", "glue.driver.s3.filesystem.write_bytes glue.executorId.s3.filesystem.write_bytes glue.ALL.s3.filesystem.write_bytes", "glue.driver.system.cpuSystemLoad glue.executorId.system.cpuSystemLoad glue.ALL.system.cpuSystemLoad"}, + "AWS/Inspector": {"TotalAssessmentRunFindings", "TotalAssessmentRuns", "TotalHealthyAgents", "TotalMatchingAgents"}, + "AWS/IoT": {"CanceledJobExecutionCount", "CanceledJobExecutionTotalCount", "ClientError", "Connect.AuthError", "Connect.ClientError", "Connect.ServerError", "Connect.Success", "Connect.Throttle", "DeleteThingShadow.Accepted", "FailedJobExecutionCount", "FailedJobExecutionTotalCount", "Failure", "GetThingShadow.Accepted", "InProgressJobExecutionCount", "InProgressJobExecutionTotalCount", "NonCompliantResources", "NumLogBatchesFailedToPublishThrottled", "NumLogEventsFailedToPublishThrottled", "ParseError", "Ping.Success", "PublishIn.AuthError", "PublishIn.ClientError", "PublishIn.ServerError", "PublishIn.Success", "PublishIn.Throttle", "PublishOut.AuthError", "PublishOut.ClientError", "PublishOut.Success", "QueuedJobExecutionCount", "QueuedJobExecutionTotalCount", "RejectedJobExecutionCount", "RejectedJobExecutionTotalCount", "RemovedJobExecutionCount", "RemovedJobExecutionTotalCount", "ResourcesEvaluated", "RuleMessageThrottled", "RuleNotFound", "RulesExecuted", "ServerError", "Subscribe.AuthError", "Subscribe.ClientError", "Subscribe.ServerError", "Subscribe.Success", "Subscribe.Throttle", "SuccededJobExecutionCount", "SuccededJobExecutionTotalCount", "Success", "TopicMatch", "Unsubscribe.ClientError", "Unsubscribe.ServerError", "Unsubscribe.Success", "Unsubscribe.Throttle", "UpdateThingShadow.Accepted", "Violations", "ViolationsCleared", "ViolationsInvalidated"}, + "AWS/IoTAnalytics": {"ActionExecution", "ActivityExecutionError", "IncomingMessages"}, + "AWS/KMS": {"SecondsUntilKeyMaterialExpiration"}, + "AWS/Kafka": {"ActiveControllerCount", "BytesInPerSec", "BytesOutPerSec", "CpuIdle", "CpuSystem", "CpuUser", "FetchConsumerLocalTimeMsMean", "FetchConsumerRequestQueueTimeMsMean", "FetchConsumerResponseQueueTimeMsMean", "FetchConsumerResponseSendTimeMsMean", "FetchConsumerTotalTimeMsMean", "FetchFollowerLocalTimeMsMean", "FetchFollowerRequestQueueTimeMsMean", "FetchFollowerResponseQueueTimeMsMean", "FetchFollowerResponseSendTimeMsMean", "FetchFollowerTotalTimeMsMean", "FetchMessageConversionsPerSec", "FetchThrottleByteRate", "FetchThrottleQueueSize", "FetchThrottleTime", "GlobalPartitionCount", "GlobalTopicCount", "KafkaAppLogsDiskUsed", "KafkaDataLogsDiskUsed", "LeaderCount", "MemoryBuffered", "MemoryCached", "MemoryFree", "MemoryUsed", "MessagesInPerSec", "NetworkProcessorAvgIdlePercent", "NetworkRxDropped", "NetworkRxErrors", "NetworkRxPackets", "NetworkTxDropped", "NetworkTxErrors", "NetworkTxPackets", "OfflinePartitionsCount", "PartitionCount", "ProduceLocalTimeMsMean", "ProduceMessageConversionsPerSec", "ProduceMessageConversionsTimeMsMean", "ProduceRequestQueueTimeMsMean", "ProduceResponseQueueTimeMsMean", "ProduceResponseSendTimeMsMean", "ProduceThrottleByteRate", "ProduceThrottleQueueSize", "ProduceThrottleTime", "ProduceTotalTimeMsMean", "RequestBytesMean", "RequestExemptFromThrottleTime", "RequestHandlerAvgIdlePercent", "RequestThrottleQueueSize", "RequestThrottleTime", "RequestTime", "RootDiskUsed", "SwapFree", "SwapUsed", "UnderMinIsrPartitionCount", "UnderReplicatedPartitions", "ZooKeeperRequestLatencyMsMean", "ZooKeeperSessionState"}, + "AWS/Kinesis": {"GetRecords.Bytes", "GetRecords.IteratorAge", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Records", "GetRecords.Success", "IncomingBytes", "IncomingRecords", "IteratorAgeMilliseconds", "OutgoingBytes", "OutgoingRecords", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "ReadProvisionedThroughputExceeded", "SubscribeToShard.RateExceeded", "SubscribeToShard.Success", "SubscribeToShardEvent.Bytes", "SubscribeToShardEvent.MillisBehindLatest", "SubscribeToShardEvent.Records", "SubscribeToShardEvent.Success", "WriteProvisionedThroughputExceeded"}, + "AWS/KinesisAnalytics": {"Bytes", "InputProcessing.DroppedRecords", "InputProcessing.Duration", "InputProcessing.OkBytes", "InputProcessing.OkRecords", "InputProcessing.ProcessingFailedRecords", "InputProcessing.Success", "KPUs", "LambdaDelivery.DeliveryFailedRecords", "LambdaDelivery.Duration", "LambdaDelivery.OkRecords", "MillisBehindLatest", "Records", "Success"}, + "AWS/KinesisVideo": {"GetHLSMasterPlaylist.Latency", "GetHLSMasterPlaylist.Requests", "GetHLSMasterPlaylist.Success", "GetHLSMediaPlaylist.Latency", "GetHLSMediaPlaylist.Requests", "GetHLSMediaPlaylist.Success", "GetHLSStreamingSessionURL.Latency", "GetHLSStreamingSessionURL.Requests", "GetHLSStreamingSessionURL.Success", "GetMP4InitFragment.Latency", "GetMP4InitFragment.Requests", "GetMP4InitFragment.Success", "GetMP4MediaFragment.Latency", "GetMP4MediaFragment.OutgoingBytes", "GetMP4MediaFragment.Requests", "GetMP4MediaFragment.Success", "GetMedia.ConnectionErrors", "GetMedia.MillisBehindNow", "GetMedia.OutgoingBytes", "GetMedia.OutgoingFragments", "GetMedia.OutgoingFrames", "GetMedia.Requests", "GetMedia.Success", "GetMediaForFragmentList.OutgoingBytes", "GetMediaForFragmentList.OutgoingFragments", "GetMediaForFragmentList.OutgoingFrames", "GetMediaForFragmentList.Requests", "GetMediaForFragmentList.Success", "GetTSFragment.Latency", "GetTSFragment.OutgoingBytes", "GetTSFragment.Requests", "GetTSFragment.Success", "ListFragments.Latency", "PutMedia.ActiveConnections", "PutMedia.BufferingAckLatency", "PutMedia.ConnectionErrors", "PutMedia.ErrorAckCount", "PutMedia.FragmentIngestionLatency", "PutMedia.FragmentPersistLatency", "PutMedia.IncomingBytes", "PutMedia.IncomingFragments", "PutMedia.IncomingFrames", "PutMedia.Latency", "PutMedia.PersistedAckLatency", "PutMedia.ReceivedAckLatency", "PutMedia.Requests", "PutMedia.Success"}, + "AWS/Lambda": {"ConcurrentExecutions", "DeadLetterErrors", "Duration", "Errors", "Invocations", "IteratorAge", "Throttles", "UnreservedConcurrentExecutions"}, + "AWS/Lex": {"BotChannelAuthErrors", "BotChannelConfigurationErrors", "BotChannelInboundThrottledEvents", "BotChannelOutboundThrottledEvents", "BotChannelRequestCount", "BotChannelResponseCardErrors", "BotChannelSystemErrors", "MissedUtteranceCount", "RuntimeInvalidLambdaResponses", "RuntimeLambdaErrors", "RuntimePollyErrors", "RuntimeRequestCount", "RuntimeSucessfulRequestLatency", "RuntimeSystemErrors", "RuntimeThrottledEvents", "RuntimeUserErrors"}, + "AWS/Logs": {"DeliveryErrors", "DeliveryThrottling", "ForwardedBytes", "ForwardedLogEvents", "IncomingBytes", "IncomingLogEvents"}, + "AWS/ML": {"PredictCount", "PredictFailureCount"}, + "AWS/MediaConnect": {"ARQRecovered", "ARQRequests", "CATError", "CRCError", "ConnectedOutputs", "ContinuityCounter", "FECPackets", "FECRecovered", "NotRecoveredPackets", "OverflowPackets", "PATError", "PCRAccuracyError", "PCRError", "PIDError", "PMTError", "PTSError", "PacketLossPercent", "RecoveredPackets", "RoundTripTime", "SourceBitRate", "TSByteError", "TSSyncLoss", "TransportError"}, + "AWS/MediaConvert": {"AudioOutputSeconds", "Errors", "HDOutputSeconds", "JobsCompletedCount", "JobsErroredCount", "SDOutputSeconds", "StandbyTime", "TranscodingTime", "UHDOutputSeconds"}, + "AWS/MediaPackage": {"ActiveInput", "EgressBytes", "EgressRequestCount", "EgressResponseTime", "IngressBytes", "IngressResponseTime"}, + "AWS/MediaTailor": {"AdDecisionServer.Ads", "AdDecisionServer.Duration", "AdDecisionServer.Errors", "AdDecisionServer.FillRate", "AdDecisionServer.Timeouts", "AdNotReady", "Avails.Duration", "Avails.FillRate", "Avails.FilledDuration", "GetManifest.Errors", "Origin.Errors", "Origin.Timeouts"}, + "AWS/NATGateway": {"ActiveConnectionCount", "BytesInFromDestination", "BytesInFromSource", "BytesOutToDestination", "BytesOutToSource", "ConnectionAttemptCount", "ConnectionEstablishedCount", "ErrorPortAllocation", "IdleTimeoutCount", "PacketsDropCount", "PacketsInFromDestination", "PacketsInFromSource", "PacketsOutToDestination", "PacketsOutToSource"}, + "AWS/Neptune": {"CPUUtilization", "ClusterReplicaLag", "ClusterReplicaLagMaximum", "ClusterReplicaLagMinimum", "EngineUptime", "FreeLocalStorage", "FreeableMemory", "GremlinErrors", "GremlinHttp1xx", "GremlinHttp2xx", "GremlinHttp4xx", "GremlinHttp5xx", "GremlinRequests", "GremlinRequestsPerSec", "GremlinWebSocketAvailableConnections", "GremlinWebSocketClientErrors", "GremlinWebSocketServerErrors", "GremlinWebSocketSuccess", "Http100", "Http101", "Http1xx", "Http200", "Http2xx", "Http400", "Http403", "Http405", "Http413", "Http429", "Http4xx", "Http500", "Http501", "Http5xx", "LoaderErrors", "LoaderRequests", "NetworkReceiveThroughput", "NetworkThroughput", "NetworkTransmitThroughput", "SparqlErrors", "SparqlHttp1xx", "SparqlHttp2xx", "SparqlHttp4xx", "SparqlHttp5xx", "SparqlRequests", "SparqlRequestsPerSec", "StatusErrors", "StatusRequests", "VolumeBytesUsed", "VolumeReadIOPs", "VolumeWriteIOPs"}, + "AWS/NetworkELB": {"ActiveFlowCount", "ActiveFlowCount_TLS", "ClientTLSNegotiationErrorCount", "ConsumedLCUs", "HealthyHostCount", "NewFlowCount", "NewFlowCount_TLS", "ProcessedBytes", "ProcessedBytes_TLS", "TCP_Client_Reset_Count", "TCP_ELB_Reset_Count", "TCP_Target_Reset_Count", "TargetTLSNegotiationErrorCount", "UnHealthyHostCount"}, + "AWS/OpsWorks": {"cpu_idle", "cpu_nice", "cpu_steal", "cpu_system", "cpu_user", "cpu_waitio", "load_1", "load_15", "load_5", "memory_buffers", "memory_cached", "memory_free", "memory_swap", "memory_total", "memory_used", "procs"}, + "AWS/Polly": {"2XXCount", "4XXCount", "5XXCount", "RequestCharacters", "ResponseLatency"}, + "AWS/RDS": {"ActiveTransactions", "AuroraBinlogReplicaLag", "AuroraGlobalDBDataTransferBytes", "AuroraGlobalDBReplicatedWriteIO", "AuroraGlobalDBReplicationLag", "AuroraReplicaLag", "AuroraReplicaLagMaximum", "AuroraReplicaLagMinimum", "BacktrackChangeRecordsCreationRate", "BacktrackChangeRecordsStored", "BacktrackWindowActual", "BacktrackWindowAlert", "BackupRetentionPeriodStorageUsed", "BinLogDiskUsage", "BlockedTransactions", "BufferCacheHitRatio", "BurstBalance", "CPUCreditBalance", "CPUCreditUsage", "CPUUtilization", "CommitLatency", "CommitThroughput", "DDLLatency", "DDLThroughput", "DMLLatency", "DMLThroughput", "DatabaseConnections", "Deadlocks", "DeleteLatency", "DeleteThroughput", "DiskQueueDepth", "EngineUptime", "FailedSQLServerAgentJobsCount", "FreeLocalStorage", "FreeStorageSpace", "FreeableMemory", "InsertLatency", "InsertThroughput", "LoginFailures", "MaximumUsedTransactionIDs", "NetworkReceiveThroughput", "NetworkThroughput", "NetworkTransmitThroughput", "OldestReplicationSlotLag", "Queries", "RDSToAuroraPostgreSQLReplicaLag", "ReadIOPS", "ReadLatency", "ReadThroughput", "ReplicaLag", "ReplicationSlotDiskUsage", "ResultSetCacheHitRatio", "SelectLatency", "SelectThroughput", "ServerlessDatabaseCapacity", "SnapshotStorageUsed", "SwapUsage", "TotalBackupStorageBilled", "TransactionLogsDiskUsage", "TransactionLogsGeneration", "UpdateLatency", "UpdateThroughput", "VolumeBytesUsed", "VolumeReadIOPs", "VolumeWriteIOPs", "WriteIOPS", "WriteLatency", "WriteThroughput"}, + "AWS/Redshift": {"CPUUtilization", "DatabaseConnections", "HealthStatus", "MaintenanceMode", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "PercentageDiskSpaceUsed", "QueriesCompletedPerSecond", "QueryDuration", "QueryRuntimeBreakdown", "ReadIOPS", "ReadLatency", "ReadThroughput", "TotalTableCount", "WLMQueriesCompletedPerSecond", "WLMQueryDuration", "WLMQueueLength", "WriteIOPS", "WriteLatency", "WriteThroughput"}, + "AWS/Route53": {"ChildHealthCheckHealthyCount", "ConnectionTime", "HealthCheckPercentageHealthy", "HealthCheckStatus", "SSLHandshakeTime", "TimeToFirstByte"}, + "AWS/Route53Resolver": {"InboundQueryVolume", "OutboundQueryVolume", "OutboundQueryAggregatedVolume"}, + "AWS/S3": {"4xxErrors", "5xxErrors", "AllRequests", "BucketSizeBytes", "BytesDownloaded", "BytesUploaded", "DeleteRequests", "FirstByteLatency", "GetRequests", "HeadRequests", "ListRequests", "NumberOfObjects", "PostRequests", "PutRequests", "SelectRequests", "SelectReturnedBytes", "SelectScannedBytes", "TotalRequestLatency"}, + "AWS/SES": {"Bounce", "Clicks", "Complaint", "Delivery", "Opens", "Reject", "Rendering Failures", "Reputation.BounceRate", "Reputation.ComplaintRate", "Send"}, + "AWS/SNS": {"NumberOfMessagesPublished", "NumberOfNotificationsDelivered", "NumberOfNotificationsFailed", "NumberOfNotificationsFilteredOut", "NumberOfNotificationsFilteredOut-InvalidAttributes", "NumberOfNotificationsFilteredOut-NoMessageAttributes", "PublishSize", "SMSMonthToDateSpentUSD", "SMSSuccessRate"}, + "AWS/SQS": {"ApproximateAgeOfOldestMessage", "ApproximateNumberOfMessagesDelayed", "ApproximateNumberOfMessagesNotVisible", "ApproximateNumberOfMessagesVisible", "NumberOfEmptyReceives", "NumberOfMessagesDeleted", "NumberOfMessagesReceived", "NumberOfMessagesSent", "SentMessageSize"}, + "AWS/SWF": {"ActivityTaskScheduleToCloseTime", "ActivityTaskScheduleToStartTime", "ActivityTaskStartToCloseTime", "ActivityTasksCanceled", "ActivityTasksCompleted", "ActivityTasksFailed", "ConsumedCapacity", "DecisionTaskScheduleToStartTime", "DecisionTaskStartToCloseTime", "DecisionTasksCompleted", "PendingTasks", "ProvisionedBucketSize", "ProvisionedRefillRate", "ScheduledActivityTasksTimedOutOnClose", "ScheduledActivityTasksTimedOutOnStart", "StartedActivityTasksTimedOutOnClose", "StartedActivityTasksTimedOutOnHeartbeat", "StartedDecisionTasksTimedOutOnClose", "ThrottledEvents", "WorkflowStartToCloseTime", "WorkflowsCanceled", "WorkflowsCompleted", "WorkflowsContinuedAsNew", "WorkflowsFailed", "WorkflowsTerminated", "WorkflowsTimedOut"}, + "AWS/SageMaker": {"CPUUtilization", "DatasetObjectsAutoAnnotated", "DatasetObjectsHumanAnnotated", "DatasetObjectsLabelingFailed", "DiskUtilization", "GPUMemoryUtilization", "GPUUtilization", "Invocation4XXErrors", "Invocation5XXErrors", "Invocations", "InvocationsPerInstance", "JobsFailed", "JobsStopped", "JobsSucceeded", "MemoryUtilization", "ModelLatency", "OverheadLatency", "TotalDatasetObjectsLabeled"}, + "AWS/States": {"ActivitiesFailed", "ActivitiesHeartbeatTimedOut", "ActivitiesScheduled", "ActivitiesStarted", "ActivitiesSucceeded", "ActivitiesTimedOut", "ActivityRunTime", "ActivityScheduleTime", "ActivityTime", "ConsumedCapacity", "ExecutionThrottled", "ExecutionTime", "ExecutionsAborted", "ExecutionsFailed", "ExecutionsStarted", "ExecutionsSucceeded", "ExecutionsTimedOut", "LambdaFunctionRunTime", "LambdaFunctionScheduleTime", "LambdaFunctionTime", "LambdaFunctionsFailed", "LambdaFunctionsHeartbeatTimedOut", "LambdaFunctionsScheduled", "LambdaFunctionsStarted", "LambdaFunctionsSucceeded", "LambdaFunctionsTimedOut", "ProvisionedBucketSize", "ProvisionedRefillRate", "ThrottledEvents"}, + "AWS/StorageGateway": {"CacheFree", "CacheHitPercent", "CachePercentDirty", "CachePercentUsed", "CacheUsed", "CloudBytesDownloaded", "CloudBytesUploaded", "CloudDownloadLatency", "QueuedWrites", "ReadBytes", "ReadTime", "TimeSinceLastRecoveryPoint", "TotalCacheSize", "UploadBufferFree", "UploadBufferPercentUsed", "UploadBufferUsed", "WorkingStorageFree", "WorkingStoragePercentUsed", "WorkingStorageUsed", "WriteBytes", "WriteTime"}, + "AWS/Textract": {"ResponseTime", "ServerErrorCount", "SuccessfulRequestCount", "ThrottledCount", "UserErrorCount"}, + "AWS/ThingsGraph": {"EventStoreQueueSize", "FlowExecutionTime", "FlowExecutionsFailed", "FlowExecutionsStarted", "FlowExecutionsSucceeded", "FlowStepExecutionTime", "FlowStepExecutionsFailed", "FlowStepExecutionsStarted", "FlowStepExecutionsSucceeded"}, + "AWS/TransitGateway": {"BytesIn", "BytesOut", "PacketDropCountBlackhole", "PacketDropCountNoRoute", "PacketsIn", "PacketsOut"}, + "AWS/Translate": {"CharacterCount", "ResponseTime", "ServerErrorCount", "SuccessfulRequestCount", "ThrottledCount", "UserErrorCount"}, + "AWS/TrustedAdvisor": {"GreenChecks", "RedChecks", "RedResources", "ServiceLimitUsage", "YellowChecks", "YellowResources"}, + "AWS/Usage": {"CallCount"}, + "AWS/VPN": {"TunnelDataIn", "TunnelDataOut", "TunnelState"}, + "AWS/WorkSpaces": {"Available", "ConnectionAttempt", "ConnectionFailure", "ConnectionSuccess", "InSessionLatency", "Maintenance", "SessionDisconnect", "SessionLaunchTime", "Stopped", "Unhealthy", "UserConnected"}, + "ECS/ContainerInsights": {"ContainerInstanceCount", "CpuUtilized", "CpuReserved", "DeploymentCount", "DesiredTaskCount", "MemoryUtilized", "MemoryReserved", "NetworkRxBytes", "NetworkTxBytes", "PendingTaskCount", "RunningTaskCount", "ServiceCount", "StorageReadBytes", "StorageWriteBytes", "TaskCount", "TaskSetCount", "instance_cpu_limit", "instance_cpu_reserved_capacity", "instance_cpu_usage_total", "instance_cpu_utilization", "instance_filesystem_utilization", "instance_memory_limit", "instance_memory_reserved_capacity", "instance_memory_utliization", "instance_memory_working_set", "instance_network_total_bytes", "instance_number_of_running_tasks"}, + "ContainerInsights": {"cluster_failed_node_count", "cluster_node_count", "namespace_number_of_running_pods", "node_cpu_limit", "node_cpu_reserved_capacity", "node_cpu_usage_total", "node_cpu_utilization", "node_filesystem_utilization", "node_memory_limit", "node_memory_reserved_capacity", "node_memory_utilization", "node_memory_working_set", "node_network_total_bytes", "node_number_of_running_containers", "node_number_of_running_pods", "pod_cpu_reserved_capacity", "pod_cpu_utilization", "pod_cpu_utilization_over_pod_limit", "pod_memory_reserved_capacity", "pod_memory_utilization", "pod_memory_utilization_over_pod_limit", "pod_number_of_container_restarts", "pod_network_rx_bytes", "pod_network_tx_bytes", "service_number_of_running_pods"}, + "Rekognition": {"DetectedFaceCount", "DetectedLabelCount", "ResponseTime", "ServerErrorCount", "SuccessfulRequestCount", "ThrottledCount", "UserErrorCount"}, + "WAF": {"AllowedRequests", "BlockedRequests", "CountedRequests", "DDoSAttackBitsPerSecond", "DDoSAttackPacketsPerSecond", "DDoSAttackRequestsPerSecond", "DDoSDetected", "PassedRequests"}, + "AWS/Cassandra": {"AccountMaxReads", "AccountMaxTableLevelReads", "AccountMaxTableLevelWrites", "AccountMaxWrites", "AccountProvisionedReadCapacityUtilization", "AccountProvisionedWriteCapacityUtilization", "ConditionalCheckFailedRequests", "ConsumedReadCapacityUnits", "ConsumedWriteCapacityUnits", "MaxProvisionedTableReadCapacityUtilization", "MaxProvisionedTableWriteCapacityUtilization", "ReturnedItemCount", "ReturnedItemCountBySelect", "SuccessfulRequestCount", "SuccessfulRequestLatency", "SystemErrors", "UserErrors"}, } +var dimensionsMap = map[string][]string{ + "AWS/ACMPrivateCA": {}, + "AWS/AmazonMQ": {"Broker", "Queue", "Topic"}, + "AWS/ApiGateway": {"ApiName", "Method", "Resource", "Stage"}, + "AWS/AppStream": {"Fleet"}, + "AWS/AppSync": {"GraphQLAPIId"}, + "AWS/ApplicationELB": {"AvailabilityZone", "LoadBalancer", "TargetGroup"}, + "AWS/AutoScaling": {"AutoScalingGroupName"}, + "AWS/Billing": {"Currency", "LinkedAccount", "ServiceName"}, + "AWS/Chatbot": {"ConfigurationName"}, + "AWS/CloudFront": {"DistributionId", "Region"}, + "AWS/CloudHSM": {"ClusterId", "HsmId", "Region"}, + "AWS/CloudSearch": {"ClientId", "DomainName"}, + "AWS/CodeBuild": {"ProjectName"}, + "AWS/Cognito": {"Operation", "RiskLevel", "UserPoolId"}, + "AWS/Connect": {"InstanceId", "MetricGroup", "Participant", "QueueName", "Stream Type", "Type of Connection"}, + "AWS/DDoSProtection": {"Region", "Rule", "RuleGroup", "WebACL"}, + "AWS/DMS": {"ReplicationInstanceIdentifier", "ReplicationTaskIdentifier"}, + "AWS/DocDB": {"DBClusterIdentifier", "DBInstanceIdentifier", "Role"}, + "AWS/DX": {"ConnectionId"}, + "AWS/DAX": {"Account", "ClusterId", "NodeId"}, + "AWS/DynamoDB": {"GlobalSecondaryIndexName", "Operation", "ReceivingRegion", "StreamLabel", "TableName"}, + "AWS/EBS": {"VolumeId"}, + "AWS/EC2": {"AutoScalingGroupName", "ImageId", "InstanceId", "InstanceType"}, + "AWS/EC2/API": {}, + "AWS/EC2Spot": {"AvailabilityZone", "FleetRequestId", "InstanceType"}, + "AWS/ECS": {"ClusterName", "ServiceName"}, + "AWS/EFS": {"FileSystemId"}, + "AWS/ELB": {"AvailabilityZone", "LoadBalancerName"}, + "AWS/ES": {"ClientId", "DomainName"}, + "AWS/ElastiCache": {"CacheClusterId", "CacheNodeId"}, + "AWS/ElasticBeanstalk": {"EnvironmentName", "InstanceId"}, + "AWS/ElasticInference": {"ElasticInferenceAcceleratorId", "InstanceId"}, + "AWS/ElasticMapReduce": {"ClusterId", "JobFlowId", "JobId"}, + "AWS/ElasticTranscoder": {"Operation", "PipelineId"}, + "AWS/Events": {"RuleName"}, + "AWS/FSx": {}, + "AWS/Firehose": {"DeliveryStreamName"}, + "AWS/GameLift": {"FleetId", "InstanceType", "MatchmakingConfigurationName", "MatchmakingConfigurationName-RuleName", "MetricGroups", "OperatingSystem", "QueueName"}, + "AWS/Glue": {"JobName", "JobRunId", "Type"}, + "AWS/Inspector": {}, + "AWS/IoT": {"ActionType", "BehaviorName", "CheckName", "JobId", "Protocol", "RuleName", "ScheduledAuditName", "SecurityProfileName"}, + "AWS/IoTAnalytics": {"ActionType", "ChannelName", "DatasetName", "DatastoreName", "PipelineActivityName", "PipelineActivityType", "PipelineName"}, + "AWS/KMS": {"KeyId"}, + "AWS/Kafka": {"Broker ID", "Cluster Name", "Topic"}, + "AWS/Kinesis": {"ShardId", "StreamName"}, + "AWS/KinesisAnalytics": {"Application", "Flow", "Id"}, + "AWS/KinesisVideo": {}, + "AWS/Lambda": {"Alias", "ExecutedVersion", "FunctionName", "Resource"}, + "AWS/Lex": {"BotAlias", "BotChannelName", "BotName", "BotVersion", "InputMode", "Operation", "Source"}, + "AWS/Logs": {"DestinationType", "FilterName", "LogGroupName"}, + "AWS/ML": {"MLModelId", "RequestMode"}, + "AWS/MediaConnect": {}, + "AWS/MediaConvert": {"Job", "Operation", "Queue"}, + "AWS/MediaPackage": {"Channel", "No Dimension", "OriginEndpoint", "StatusCodeRange"}, + "AWS/MediaTailor": {"Configuration Name"}, + "AWS/NATGateway": {"NatGatewayId"}, + "AWS/Neptune": {"DBClusterIdentifier", "DatabaseClass", "EngineName", "Role"}, + "AWS/NetworkELB": {"AvailabilityZone", "LoadBalancer", "TargetGroup"}, + "AWS/OpsWorks": {"InstanceId", "LayerId", "StackId"}, + "AWS/Polly": {"Operation"}, + "AWS/RDS": {"DBClusterIdentifier", "DBInstanceIdentifier", "DatabaseClass", "DbClusterIdentifier", "EngineName", "Role", "SourceRegion"}, + "AWS/Redshift": {"ClusterIdentifier", "NodeID", "service class", "stage", "latency", "wlmid"}, + "AWS/Route53": {"HealthCheckId", "Region"}, + "AWS/Route53Resolver": {"EndpointId"}, + "AWS/S3": {"BucketName", "FilterId", "StorageType"}, + "AWS/SES": {}, + "AWS/SNS": {"Application", "Country", "Platform", "SMSType", "TopicName"}, + "AWS/SQS": {"QueueName"}, + "AWS/SWF": {"APIName", "ActivityTypeName", "ActivityTypeVersion", "DecisionName", "Domain", "TaskListName", "WorkflowTypeName", "WorkflowTypeVersion"}, + "AWS/SageMaker": {"EndpointName", "Host", "LabelingJobName", "VariantName"}, + "AWS/States": {"APIName", "ActivityArn", "LambdaFunctionArn", "StateMachineArn", "StateTransition"}, + "AWS/StorageGateway": {"GatewayId", "GatewayName", "VolumeId"}, + "AWS/Textract": {}, + "AWS/ThingsGraph": {"FlowTemplateId", "StepName", "SystemTemplateId"}, + "AWS/TransitGateway": {"TransitGateway"}, + "AWS/Translate": {"LanguagePair", "Operation"}, + "AWS/TrustedAdvisor": {}, + "AWS/Usage": {"Class", "Resource", "Service", "Type"}, + "AWS/VPN": {"TunnelIpAddress", "VpnId"}, + "AWS/WorkSpaces": {"DirectoryId", "WorkspaceId"}, + "ECS/ContainerInsights": {"ClusterName", "ServiceName", "TaskDefinitionFamily", "EC2InstanceId", "ContainerInstanceId"}, + "ContainerInsights": {"ClusterName", "NodeName", "Namespace", "InstanceId", "PodName", "Service"}, + "Rekognition": {}, + "WAF": {"Region", "Rule", "RuleGroup", "WebACL"}, + "AWS/Cassandra": {"Keyspace", "Operation", "TableName"}, +} + +var regionCache sync.Map + func (e *CloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) { - result := &tsdb.Response{ - Results: make(map[string]*tsdb.QueryResult), - } firstQuery := queryContext.Queries[0] - queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: firstQuery.RefId} parameters := firstQuery.Model subType := firstQuery.Model.Get("subtype").MustString() @@ -248,24 +237,38 @@ func (e *CloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queryCo case "resource_arns": data, err = e.handleGetResourceArns(ctx, parameters, queryContext) } + if err != nil { + return nil, err + } + queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: firstQuery.RefId} transformToTable(data, queryResult) - result.Results[firstQuery.RefId] = queryResult - return result, err + result := &tsdb.Response{ + Results: map[string]*tsdb.QueryResult{ + firstQuery.RefId: queryResult, + }, + } + return result, nil } func transformToTable(data []suggestData, result *tsdb.QueryResult) { table := &tsdb.Table{ - Columns: make([]tsdb.TableColumn, 2), - Rows: make([]tsdb.RowValues, 0), + Columns: []tsdb.TableColumn{ + { + Text: "text", + }, + { + Text: "value", + }, + }, + Rows: make([]tsdb.RowValues, 0), } - table.Columns[0].Text = "text" - table.Columns[1].Text = "value" for _, r := range data { - values := make([]interface{}, 2) - values[0] = r.Text - values[1] = r.Value + values := []interface{}{ + r.Text, + r.Value, + } table.Rows = append(table.Rows, values) } result.Tables = append(result.Tables, table) @@ -274,19 +277,19 @@ func transformToTable(data []suggestData, result *tsdb.QueryResult) { func parseMultiSelectValue(input string) []string { trimmedInput := strings.TrimSpace(input) - if strings.HasPrefix(trimmedInput, "{") { values := strings.Split(strings.TrimRight(strings.TrimLeft(trimmedInput, "{"), "}"), ",") - trimValues := make([]string, len(values)) + trimmedValues := make([]string, len(values)) for i, v := range values { - trimValues[i] = strings.TrimSpace(v) + trimmedValues[i] = strings.TrimSpace(v) } - return trimValues + return trimmedValues } + return []string{trimmedInput} } -// Whenever this list is updated, frontend list should also be updated. +// Whenever this list is updated, the frontend list should also be updated. // Please update the region list in public/app/plugins/datasource/cloudwatch/partials/config.html func (e *CloudWatchExecutor) handleGetRegions(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.TsdbQuery) ([]suggestData, error) { dsInfo := e.getDsInfo("default") @@ -342,12 +345,10 @@ func (e *CloudWatchExecutor) handleGetNamespaces(ctx context.Context, parameters for key := range metricsMap { keys = append(keys, key) } - customNamespaces := e.DataSource.JsonData.Get("customMetricsNamespaces").MustString() if customNamespaces != "" { keys = append(keys, strings.Split(customNamespaces, ",")...) } - sort.Strings(keys) result := make([]suggestData, 0) @@ -366,7 +367,7 @@ func (e *CloudWatchExecutor) handleGetMetrics(ctx context.Context, parameters *s if !isCustomMetrics(namespace) { var exists bool if namespaceMetrics, exists = metricsMap[namespace]; !exists { - return nil, errors.New("Unable to find namespace " + namespace) + return nil, fmt.Errorf("unable to find namespace %q", namespace) } } else { var err error @@ -395,7 +396,7 @@ func (e *CloudWatchExecutor) handleGetDimensions(ctx context.Context, parameters if !isCustomMetrics(namespace) { var exists bool if dimensionValues, exists = dimensionsMap[namespace]; !exists { - return nil, errors.New("Unable to find dimension " + namespace) + return nil, fmt.Errorf("unable to find dimension %q", namespace) } } else { var err error @@ -453,6 +454,7 @@ func (e *CloudWatchExecutor) handleGetDimensionValues(ctx context.Context, param if _, exists := dupCheck[*dim.Value]; exists { continue } + dupCheck[*dim.Value] = true result = append(result, suggestData{Text: *dim.Value, Value: *dim.Value}) } @@ -580,6 +582,7 @@ func (e *CloudWatchExecutor) handleGetEc2InstanceAttribute(ctx context.Context, if _, exists := dupCheck[data]; exists { continue } + dupCheck[data] = true result = append(result, suggestData{Text: data, Value: data}) } @@ -667,7 +670,7 @@ func (e *CloudWatchExecutor) cloudwatchListMetrics(region string, namespace stri } var resp cloudwatch.ListMetricsOutput - err = svc.ListMetricsPages(params, + if err := svc.ListMetricsPages(params, func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool { metrics.MAwsCloudWatchListMetrics.Inc() metrics, _ := awsutil.ValuesAtPath(page, "Metrics") @@ -675,9 +678,8 @@ func (e *CloudWatchExecutor) cloudwatchListMetrics(region string, namespace stri resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric)) } return !lastPage - }) - if err != nil { - return nil, fmt.Errorf("Failed to call cloudwatch:ListMetrics, %w", err) + }); err != nil { + return nil, fmt.Errorf("failed to call cloudwatch:ListMetrics: %w", err) } return &resp, nil @@ -747,15 +749,18 @@ func getAllMetrics(cwData *DatasourceInfo) (cloudwatch.ListMetricsOutput, error) } var resp cloudwatch.ListMetricsOutput - err = svc.ListMetricsPages(params, - func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool { - metrics.MAwsCloudWatchListMetrics.Inc() - metrics, _ := awsutil.ValuesAtPath(page, "Metrics") - for _, metric := range metrics { - resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric)) - } + err = svc.ListMetricsPages(params, func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool { + metrics.MAwsCloudWatchListMetrics.Inc() + metrics, err := awsutil.ValuesAtPath(page, "Metrics") + if err != nil { return !lastPage - }) + } + + for _, metric := range metrics { + resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric)) + } + return !lastPage + }) return resp, err } diff --git a/pkg/tsdb/cloudwatch/metric_find_query_test.go b/pkg/tsdb/cloudwatch/metric_find_query_test.go index 3cad6cefae4..571851c386c 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query_test.go +++ b/pkg/tsdb/cloudwatch/metric_find_query_test.go @@ -14,8 +14,8 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/tsdb" - . "github.com/smartystreets/goconvey/convey" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type mockedEc2 struct { @@ -44,7 +44,7 @@ func (m mockedRGTA) GetResourcesPages(in *resourcegroupstaggingapi.GetResourcesI func TestCloudWatchMetrics(t *testing.T) { - Convey("When calling getMetricsForCustomMetrics", t, func() { + t.Run("When calling getMetricsForCustomMetrics", func(t *testing.T) { dsInfo := &DatasourceInfo{ Region: "us-east-1", Namespace: "Foo", @@ -65,14 +65,13 @@ func TestCloudWatchMetrics(t *testing.T) { }, }, nil } - metrics, _ := getMetricsForCustomMetrics(dsInfo, f) + metrics, err := getMetricsForCustomMetrics(dsInfo, f) + require.NoError(t, err) - Convey("Should contain Test_MetricName", func() { - So(metrics, ShouldContain, "Test_MetricName") - }) + assert.Contains(t, metrics, "Test_MetricName") }) - Convey("When calling getDimensionsForCustomMetrics", t, func() { + t.Run("When calling getDimensionsForCustomMetrics", func(t *testing.T) { dsInfo := &DatasourceInfo{ Region: "us-east-1", Namespace: "Foo", @@ -93,14 +92,13 @@ func TestCloudWatchMetrics(t *testing.T) { }, }, nil } - dimensionKeys, _ := getDimensionsForCustomMetrics(dsInfo, f) + dimensionKeys, err := getDimensionsForCustomMetrics(dsInfo, f) + require.NoError(t, err) - Convey("Should contain Test_DimensionName", func() { - So(dimensionKeys, ShouldContain, "Test_DimensionName") - }) + assert.Contains(t, dimensionKeys, "Test_DimensionName") }) - Convey("When calling handleGetRegions", t, func() { + t.Run("When calling handleGetRegions", func(t *testing.T) { executor := &CloudWatchExecutor{ ec2Svc: mockedEc2{RespRegions: ec2.DescribeRegionsOutput{ Regions: []*ec2.Region{ @@ -117,16 +115,15 @@ func TestCloudWatchMetrics(t *testing.T) { SecureJsonData: securejsondata.SecureJsonData{}, } - result, _ := executor.handleGetRegions(context.Background(), simplejson.New(), &tsdb.TsdbQuery{}) + result, err := executor.handleGetRegions(context.Background(), simplejson.New(), &tsdb.TsdbQuery{}) + require.NoError(t, err) - Convey("Should return regions", func() { - So(result[0].Text, ShouldEqual, "ap-east-1") - So(result[1].Text, ShouldEqual, "ap-northeast-1") - So(result[2].Text, ShouldEqual, "ap-northeast-2") - }) + assert.Equal(t, "ap-east-1", result[0].Text) + assert.Equal(t, "ap-northeast-1", result[1].Text) + assert.Equal(t, "ap-northeast-2", result[2].Text) }) - Convey("When calling handleGetEc2InstanceAttribute", t, func() { + t.Run("When calling handleGetEc2InstanceAttribute", func(t *testing.T) { executor := &CloudWatchExecutor{ ec2Svc: mockedEc2{Resp: ec2.DescribeInstancesOutput{ Reservations: []*ec2.Reservation{ @@ -153,15 +150,13 @@ func TestCloudWatchMetrics(t *testing.T) { filters := make(map[string]interface{}) filters["tag:Environment"] = []string{"production"} json.Set("filters", filters) - result, _ := executor.handleGetEc2InstanceAttribute(context.Background(), json, &tsdb.TsdbQuery{}) + result, err := executor.handleGetEc2InstanceAttribute(context.Background(), json, &tsdb.TsdbQuery{}) + require.NoError(t, err) - Convey("Should equal production InstanceId", func() { - So(result[0].Text, ShouldEqual, "i-12345678") - }) + assert.Equal(t, "i-12345678", result[0].Text) }) - Convey("When calling handleGetEbsVolumeIds", t, func() { - + t.Run("When calling handleGetEbsVolumeIds", func(t *testing.T) { executor := &CloudWatchExecutor{ ec2Svc: mockedEc2{Resp: ec2.DescribeInstancesOutput{ Reservations: []*ec2.Reservation{ @@ -208,22 +203,21 @@ func TestCloudWatchMetrics(t *testing.T) { json := simplejson.New() json.Set("region", "us-east-1") json.Set("instanceId", "{i-1, i-2, i-3, i-4}") - result, _ := executor.handleGetEbsVolumeIds(context.Background(), json, &tsdb.TsdbQuery{}) + result, err := executor.handleGetEbsVolumeIds(context.Background(), json, &tsdb.TsdbQuery{}) + require.NoError(t, err) - Convey("Should return all 8 VolumeIds", func() { - So(len(result), ShouldEqual, 8) - So(result[0].Text, ShouldEqual, "vol-1-1") - So(result[1].Text, ShouldEqual, "vol-1-2") - So(result[2].Text, ShouldEqual, "vol-2-1") - So(result[3].Text, ShouldEqual, "vol-2-2") - So(result[4].Text, ShouldEqual, "vol-3-1") - So(result[5].Text, ShouldEqual, "vol-3-2") - So(result[6].Text, ShouldEqual, "vol-4-1") - So(result[7].Text, ShouldEqual, "vol-4-2") - }) + require.Len(t, result, 8) + assert.Equal(t, "vol-1-1", result[0].Text) + assert.Equal(t, "vol-1-2", result[1].Text) + assert.Equal(t, "vol-2-1", result[2].Text) + assert.Equal(t, "vol-2-2", result[3].Text) + assert.Equal(t, "vol-3-1", result[4].Text) + assert.Equal(t, "vol-3-2", result[5].Text) + assert.Equal(t, "vol-4-1", result[6].Text) + assert.Equal(t, "vol-4-2", result[7].Text) }) - Convey("When calling handleGetResourceArns", t, func() { + t.Run("When calling handleGetResourceArns", func(t *testing.T) { executor := &CloudWatchExecutor{ rgtaSvc: mockedRGTA{ Resp: resourcegroupstaggingapi.GetResourcesOutput{ @@ -257,15 +251,13 @@ func TestCloudWatchMetrics(t *testing.T) { tags := make(map[string]interface{}) tags["Environment"] = []string{"production"} json.Set("tags", tags) - result, _ := executor.handleGetResourceArns(context.Background(), json, &tsdb.TsdbQuery{}) + result, err := executor.handleGetResourceArns(context.Background(), json, &tsdb.TsdbQuery{}) + require.NoError(t, err) - Convey("Should return all two instances", func() { - So(result[0].Text, ShouldEqual, "arn:aws:ec2:us-east-1:123456789012:instance/i-12345678901234567") - So(result[0].Value, ShouldEqual, "arn:aws:ec2:us-east-1:123456789012:instance/i-12345678901234567") - So(result[1].Text, ShouldEqual, "arn:aws:ec2:us-east-1:123456789012:instance/i-76543210987654321") - So(result[1].Value, ShouldEqual, "arn:aws:ec2:us-east-1:123456789012:instance/i-76543210987654321") - - }) + assert.Equal(t, "arn:aws:ec2:us-east-1:123456789012:instance/i-12345678901234567", result[0].Text) + assert.Equal(t, "arn:aws:ec2:us-east-1:123456789012:instance/i-12345678901234567", result[0].Value) + assert.Equal(t, "arn:aws:ec2:us-east-1:123456789012:instance/i-76543210987654321", result[1].Text) + assert.Equal(t, "arn:aws:ec2:us-east-1:123456789012:instance/i-76543210987654321", result[1].Value) }) } @@ -281,5 +273,4 @@ func TestParseMultiSelectValue(t *testing.T) { values = parseMultiSelectValue("i-{01}") assert.Equal(t, []string{"i-{01}"}, values) - } diff --git a/pkg/tsdb/cloudwatch/query_transformer.go b/pkg/tsdb/cloudwatch/query_transformer.go index 682f9384307..b15aacf6255 100644 --- a/pkg/tsdb/cloudwatch/query_transformer.go +++ b/pkg/tsdb/cloudwatch/query_transformer.go @@ -25,6 +25,10 @@ func (e *CloudWatchExecutor) transformRequestQueriesToCloudWatchQueries(requestQ id = fmt.Sprintf("%s_%v", id, strings.ReplaceAll(*stat, ".", "_")) } + if _, ok := cloudwatchQueries[id]; ok { + return nil, fmt.Errorf("error in query %q - query ID %q is not unique", requestQuery.RefId, id) + } + query := &cloudWatchQuery{ Id: id, RefId: requestQuery.RefId, @@ -39,11 +43,6 @@ func (e *CloudWatchExecutor) transformRequestQueriesToCloudWatchQueries(requestQ ReturnData: requestQuery.ReturnData, MatchExact: requestQuery.MatchExact, } - - if _, ok := cloudwatchQueries[id]; ok { - return nil, fmt.Errorf("Error in query %s. Query id %s is not unique", query.RefId, query.Id) - } - cloudwatchQueries[id] = query } } @@ -52,13 +51,12 @@ func (e *CloudWatchExecutor) transformRequestQueriesToCloudWatchQueries(requestQ } func (e *CloudWatchExecutor) transformQueryResponseToQueryResult(cloudwatchResponses []*cloudwatchResponse) map[string]*tsdb.QueryResult { - results := make(map[string]*tsdb.QueryResult) responsesByRefID := make(map[string][]*cloudwatchResponse) - for _, res := range cloudwatchResponses { responsesByRefID[res.RefId] = append(responsesByRefID[res.RefId], res) } + results := make(map[string]*tsdb.QueryResult) for refID, responses := range responsesByRefID { queryResult := tsdb.NewQueryResult() queryResult.RefId = refID @@ -94,7 +92,6 @@ func (e *CloudWatchExecutor) transformQueryResponseToQueryResult(cloudwatchRespo if requestExceededMaxLimit { queryResult.ErrorString = "Cloudwatch GetMetricData error: Maximum number of allowed metrics exceeded. Your search may have been limited." } - if partialData { queryResult.ErrorString = "Cloudwatch GetMetricData error: Too many datapoints requested - your search has been limited. Please try to reduce the time range" } diff --git a/pkg/tsdb/cloudwatch/request_parser.go b/pkg/tsdb/cloudwatch/request_parser.go index a8c8178cb1d..cc0efb07984 100644 --- a/pkg/tsdb/cloudwatch/request_parser.go +++ b/pkg/tsdb/cloudwatch/request_parser.go @@ -17,18 +17,18 @@ import ( // Parses the json queries and returns a requestQuery. The requestQuery has a 1 to 1 mapping to a query editor row func (e *CloudWatchExecutor) parseQueries(queryContext *tsdb.TsdbQuery, startTime time.Time, endTime time.Time) (map[string][]*requestQuery, error) { requestQueries := make(map[string][]*requestQuery) - for i, model := range queryContext.Queries { queryType := model.Model.Get("type").MustString() if queryType != "timeSeriesQuery" && queryType != "" { continue } - RefID := queryContext.Queries[i].RefId - query, err := parseRequestQuery(queryContext.Queries[i].Model, RefID, startTime, endTime) + refID := queryContext.Queries[i].RefId + query, err := parseRequestQuery(queryContext.Queries[i].Model, refID, startTime, endTime) if err != nil { - return nil, &queryError{err, RefID} + return nil, &queryError{err: err, RefID: refID} } + if _, exist := requestQueries[query.Region]; !exist { requestQueries[query.Region] = make([]*requestQuery, 0) } @@ -39,26 +39,23 @@ func (e *CloudWatchExecutor) parseQueries(queryContext *tsdb.TsdbQuery, startTim } func parseRequestQuery(model *simplejson.Json, refId string, startTime time.Time, endTime time.Time) (*requestQuery, error) { + reNumber := regexp.MustCompile(`^\d+$`) region, err := model.Get("region").String() if err != nil { return nil, err } - namespace, err := model.Get("namespace").String() if err != nil { return nil, err } - metricName, err := model.Get("metricName").String() if err != nil { return nil, err } - dimensions, err := parseDimensions(model) if err != nil { return nil, err } - statistics, err := parseStatistics(model) if err != nil { return nil, err @@ -78,7 +75,7 @@ func parseRequestQuery(model *simplejson.Json, refId string, startTime time.Time } } } else { - if regexp.MustCompile(`^\d+$`).Match([]byte(p)) { + if reNumber.Match([]byte(p)) { period, err = strconv.Atoi(p) if err != nil { return nil, err @@ -124,7 +121,6 @@ func parseRequestQuery(model *simplejson.Json, refId string, startTime time.Time func parseStatistics(model *simplejson.Json) ([]string, error) { var statistics []string - for _, s := range model.Get("statistics").MustArray() { statistics = append(statistics, s.(string)) } @@ -148,7 +144,6 @@ func parseDimensions(model *simplejson.Json) (map[string][]string, error) { } sortedDimensions := sortDimensions(parsedDimensions) - return sortedDimensions, nil } diff --git a/pkg/tsdb/cloudwatch/request_parser_test.go b/pkg/tsdb/cloudwatch/request_parser_test.go index cf63d1eb642..3c79cea26fd 100644 --- a/pkg/tsdb/cloudwatch/request_parser_test.go +++ b/pkg/tsdb/cloudwatch/request_parser_test.go @@ -12,8 +12,10 @@ import ( func TestRequestParser(t *testing.T) { Convey("TestRequestParser", t, func() { timeRange := tsdb.NewTimeRange("now-1h", "now-2h") - from, _ := timeRange.ParseFrom() - to, _ := timeRange.ParseTo() + from, err := timeRange.ParseFrom() + So(err, ShouldBeNil) + to, err := timeRange.ParseTo() + So(err, ShouldBeNil) Convey("when parsing query editor row json", func() { Convey("using new dimensions structure", func() { query := simplejson.NewFromAny(map[string]interface{}{ @@ -102,8 +104,10 @@ func TestRequestParser(t *testing.T) { Convey("when time range is short", func() { query.Set("period", "900") timeRange := tsdb.NewTimeRange("now-1h", "now-2h") - from, _ := timeRange.ParseFrom() - to, _ := timeRange.ParseTo() + from, err := timeRange.ParseFrom() + So(err, ShouldBeNil) + to, err := timeRange.ParseTo() + So(err, ShouldBeNil) res, err := parseRequestQuery(query, "ref1", from, to) So(err, ShouldBeNil) diff --git a/pkg/tsdb/cloudwatch/response_parser.go b/pkg/tsdb/cloudwatch/response_parser.go index 9ea4fd27d25..03b2bc5c36b 100644 --- a/pkg/tsdb/cloudwatch/response_parser.go +++ b/pkg/tsdb/cloudwatch/response_parser.go @@ -14,7 +14,6 @@ import ( func (e *CloudWatchExecutor) parseResponse(metricDataOutputs []*cloudwatch.GetMetricDataOutput, queries map[string]*cloudWatchQuery) ([]*cloudwatchResponse, error) { mdr := make(map[string]map[string]*cloudwatch.MetricDataResult) - for _, mdo := range metricDataOutputs { requestExceededMaxLimit := false for _, message := range mdo.Messages { @@ -42,20 +41,20 @@ func (e *CloudWatchExecutor) parseResponse(metricDataOutputs []*cloudwatch.GetMe cloudWatchResponses := make([]*cloudwatchResponse, 0) for id, lr := range mdr { - response := &cloudwatchResponse{} series, partialData, err := parseGetMetricDataTimeSeries(lr, queries[id]) if err != nil { - return cloudWatchResponses, err + return nil, err } - response.series = series - response.Period = queries[id].Period - response.Expression = queries[id].UsedExpression - response.RefId = queries[id].RefId - response.Id = queries[id].Id - response.RequestExceededMaxLimit = queries[id].RequestExceededMaxLimit - response.PartialData = partialData - + response := &cloudwatchResponse{ + series: series, + Period: queries[id].Period, + Expression: queries[id].UsedExpression, + RefId: queries[id].RefId, + Id: queries[id].Id, + RequestExceededMaxLimit: queries[id].RequestExceededMaxLimit, + PartialData: partialData, + } cloudWatchResponses = append(cloudWatchResponses, response) } @@ -63,14 +62,14 @@ func (e *CloudWatchExecutor) parseResponse(metricDataOutputs []*cloudwatch.GetMe } func parseGetMetricDataTimeSeries(metricDataResults map[string]*cloudwatch.MetricDataResult, query *cloudWatchQuery) (*tsdb.TimeSeriesSlice, bool, error) { - result := tsdb.TimeSeriesSlice{} - partialData := false metricDataResultLabels := make([]string, 0) for k := range metricDataResults { metricDataResultLabels = append(metricDataResultLabels, k) } sort.Strings(metricDataResultLabels) + partialData := false + result := tsdb.TimeSeriesSlice{} for _, label := range metricDataResultLabels { metricDataResult := metricDataResults[label] if *metricDataResult.StatusCode != "Complete" { @@ -79,7 +78,7 @@ func parseGetMetricDataTimeSeries(metricDataResults map[string]*cloudwatch.Metri for _, message := range metricDataResult.Messages { if *message.Code == "ArithmeticError" { - return nil, false, fmt.Errorf("ArithmeticError in query %s: %s", query.RefId, *message.Value) + return nil, false, fmt.Errorf("ArithmeticError in query %q: %s", query.RefId, *message.Value) } } @@ -169,17 +168,17 @@ func formatAlias(query *cloudWatchQuery, stat string, dimensions map[string]stri if len(query.Alias) == 0 && query.isMathExpression() { return query.Id } - if len(query.Alias) == 0 && query.isInferredSearchExpression() && !query.isMultiValuedDimensionExpression() { return label } - data := map[string]string{} - data["region"] = region - data["namespace"] = namespace - data["metric"] = metricName - data["stat"] = stat - data["period"] = period + data := map[string]string{ + "region": region, + "namespace": namespace, + "metric": metricName, + "stat": stat, + "period": period, + } if len(label) != 0 { data["label"] = label } diff --git a/pkg/tsdb/cloudwatch/time_series_query.go b/pkg/tsdb/cloudwatch/time_series_query.go index 01dec511996..23725f049ec 100644 --- a/pkg/tsdb/cloudwatch/time_series_query.go +++ b/pkg/tsdb/cloudwatch/time_series_query.go @@ -10,107 +10,108 @@ import ( ) func (e *CloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) { - results := &tsdb.Response{ - Results: make(map[string]*tsdb.QueryResult), - } - startTime, err := queryContext.TimeRange.ParseFrom() if err != nil { return nil, err } - endTime, err := queryContext.TimeRange.ParseTo() if err != nil { return nil, err } - if !startTime.Before(endTime) { - return nil, fmt.Errorf("Invalid time range: Start time must be before end time") + return nil, fmt.Errorf("invalid time range: start time must be before end time") } requestQueriesByRegion, err := e.parseQueries(queryContext, startTime, endTime) if err != nil { - return results, err + return nil, err } + + if len(requestQueriesByRegion) == 0 { + return &tsdb.Response{ + Results: make(map[string]*tsdb.QueryResult), + }, nil + } + resultChan := make(chan *tsdb.QueryResult, len(queryContext.Queries)) eg, ectx := errgroup.WithContext(ctx) - - if len(requestQueriesByRegion) > 0 { - for r, q := range requestQueriesByRegion { - requestQueries := q - region := r - eg.Go(func() error { - defer func() { - if err := recover(); err != nil { - plog.Error("Execute Get Metric Data Query Panic", "error", err, "stack", log.Stack(1)) - if theErr, ok := err.(error); ok { - resultChan <- &tsdb.QueryResult{ - Error: theErr, - } - } - } - }() - - client, err := e.getClient(region) - if err != nil { - return err - } - - queries, err := e.transformRequestQueriesToCloudWatchQueries(requestQueries) - if err != nil { - for _, query := range requestQueries { + for r, q := range requestQueriesByRegion { + requestQueries := q + region := r + eg.Go(func() error { + defer func() { + if err := recover(); err != nil { + plog.Error("Execute Get Metric Data Query Panic", "error", err, "stack", log.Stack(1)) + if theErr, ok := err.(error); ok { resultChan <- &tsdb.QueryResult{ - RefId: query.RefId, - Error: err, + Error: theErr, } } - return nil } + }() - metricDataInput, err := e.buildMetricDataInput(startTime, endTime, queries) - if err != nil { - return err - } + client, err := e.getClient(region) + if err != nil { + return err + } - cloudwatchResponses := make([]*cloudwatchResponse, 0) - mdo, err := e.executeRequest(ectx, client, metricDataInput) - if err != nil { - for _, query := range requestQueries { - resultChan <- &tsdb.QueryResult{ - RefId: query.RefId, - Error: err, - } + queries, err := e.transformRequestQueriesToCloudWatchQueries(requestQueries) + if err != nil { + for _, query := range requestQueries { + resultChan <- &tsdb.QueryResult{ + RefId: query.RefId, + Error: err, } - return nil - } - - responses, err := e.parseResponse(mdo, queries) - if err != nil { - for _, query := range requestQueries { - resultChan <- &tsdb.QueryResult{ - RefId: query.RefId, - Error: err, - } - } - return nil - } - cloudwatchResponses = append(cloudwatchResponses, responses...) - res := e.transformQueryResponseToQueryResult(cloudwatchResponses) - for _, queryRes := range res { - resultChan <- queryRes } return nil - }) - } - } + } + metricDataInput, err := e.buildMetricDataInput(startTime, endTime, queries) + if err != nil { + return err + } + + cloudwatchResponses := make([]*cloudwatchResponse, 0) + mdo, err := e.executeRequest(ectx, client, metricDataInput) + if err != nil { + for _, query := range requestQueries { + resultChan <- &tsdb.QueryResult{ + RefId: query.RefId, + Error: err, + } + } + return nil + } + + responses, err := e.parseResponse(mdo, queries) + if err != nil { + for _, query := range requestQueries { + resultChan <- &tsdb.QueryResult{ + RefId: query.RefId, + Error: err, + } + } + return nil + } + + cloudwatchResponses = append(cloudwatchResponses, responses...) + res := e.transformQueryResponseToQueryResult(cloudwatchResponses) + for _, queryRes := range res { + resultChan <- queryRes + } + return nil + }) + } if err := eg.Wait(); err != nil { return nil, err } close(resultChan) + + results := &tsdb.Response{ + Results: make(map[string]*tsdb.QueryResult), + } for result := range resultChan { results.Results[result.RefId] = result } - return results, nil } diff --git a/pkg/tsdb/cloudwatch/time_series_query_test.go b/pkg/tsdb/cloudwatch/time_series_query_test.go index 92f3a8573e5..f22f5f9bfbb 100644 --- a/pkg/tsdb/cloudwatch/time_series_query_test.go +++ b/pkg/tsdb/cloudwatch/time_series_query_test.go @@ -5,24 +5,19 @@ import ( "testing" "github.com/grafana/grafana/pkg/tsdb" - - . "github.com/smartystreets/goconvey/convey" + "github.com/stretchr/testify/assert" ) func TestTimeSeriesQuery(t *testing.T) { - Convey("TestTimeSeriesQuery", t, func() { - executor := &CloudWatchExecutor{} + executor := &CloudWatchExecutor{} - Convey("Time range is valid", func() { - Convey("End time before start time should result in error", func() { - _, err := executor.executeTimeSeriesQuery(context.TODO(), &tsdb.TsdbQuery{TimeRange: tsdb.NewTimeRange("now-1h", "now-2h")}) - So(err.Error(), ShouldEqual, "Invalid time range: Start time must be before end time") - }) + t.Run("End time before start time should result in error", func(t *testing.T) { + _, err := executor.executeTimeSeriesQuery(context.TODO(), &tsdb.TsdbQuery{TimeRange: tsdb.NewTimeRange("now-1h", "now-2h")}) + assert.EqualError(t, err, "invalid time range: start time must be before end time") + }) - Convey("End time equals start time should result in error", func() { - _, err := executor.executeTimeSeriesQuery(context.TODO(), &tsdb.TsdbQuery{TimeRange: tsdb.NewTimeRange("now-1h", "now-1h")}) - So(err.Error(), ShouldEqual, "Invalid time range: Start time must be before end time") - }) - }) + t.Run("End time equals start time should result in error", func(t *testing.T) { + _, err := executor.executeTimeSeriesQuery(context.TODO(), &tsdb.TsdbQuery{TimeRange: tsdb.NewTimeRange("now-1h", "now-1h")}) + assert.EqualError(t, err, "invalid time range: start time must be before end time") }) } diff --git a/pkg/tsdb/cloudwatch/types.go b/pkg/tsdb/cloudwatch/types.go index 7e661d16788..c269571a5d6 100644 --- a/pkg/tsdb/cloudwatch/types.go +++ b/pkg/tsdb/cloudwatch/types.go @@ -46,5 +46,5 @@ type queryError struct { } func (e *queryError) Error() string { - return fmt.Sprintf("Error parsing query %s, %s", e.RefID, e.err) + return fmt.Sprintf("error parsing query %q, %s", e.RefID, e.err) }