diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index 5a3fc259892c3..b1da0cd44332a 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -39,8 +39,8 @@ type customMetricsCache struct { Cache []string } -var customMetricsMetricsMap = make(map[string]map[string]map[string]*customMetricsCache) -var customMetricsDimensionsMap = make(map[string]map[string]map[string]*customMetricsCache) +var customMetricsMetricsMap = make(map[string]*customMetricsCache) +var customMetricsDimensionsMap = make(map[string]*customMetricsCache) var metricsMap = map[string][]string{ "AWS/ACMPrivateCA": {"CRLGenerated", "Failure", "MisconfiguredCRLBucket", "Success", "Time"}, "AWS/AmazonMQ": {"BurstBalance", "ConsumerCount", "CpuCreditBalance", "CpuUtilization", "CurrentConnectionsCount", "DequeueCount", "DispatchCount", "EnqueueCount", "EnqueueTime", "EstablishedConnectionsCount", "ExpiredCount", "HeapUsage", "InactiveDurableTopicSubscribersCount", "InFlightCount", "JobSchedulerStorePercentUsage", "JournalFilesForFastRecovery", "JournalFilesForFullRecovery", "MemoryUsage", "NetworkIn", "NetworkOut", "OpenTransactionCount", "ProducerCount", "QueueSize", "ReceiveCount", "StorePercentUsage", "TempPercentUsage", "TotalConsumerCount", "TotalDequeueCount", "TotalEnqueueCount", "TotalMessageCount", "TotalProducerCount", "VolumeReadOps", "VolumeWriteOps"}, @@ -388,7 +388,8 @@ func (e *cloudWatchExecutor) handleGetMetrics(ctx context.Context, parameters *s } } else { var err error - if namespaceMetrics, err = e.getMetricsForCustomMetrics(region, namespace); err != nil { + dsInfo := e.getDSInfo(region) + if namespaceMetrics, err = e.getMetricsForCustomMetrics(region, namespace, dsInfo.Profile); err != nil { return nil, errutil.Wrap("unable to call AWS API", err) } } @@ -415,9 +416,8 @@ func (e *cloudWatchExecutor) handleGetDimensions(ctx context.Context, parameters } else { var err error dsInfo := e.getDSInfo(region) - dsInfo.Namespace = namespace - if dimensionValues, err = e.getDimensionsForCustomMetrics(region, namespace); err != nil { + if dimensionValues, err = e.getDimensionsForCustomMetrics(region, namespace, dsInfo.Profile); err != nil { return nil, errutil.Wrap("unable to call AWS API", err) } } @@ -708,11 +708,8 @@ func (e *cloudWatchExecutor) getAllMetrics(region string, namespace string) (clo return cloudwatch.ListMetricsOutput{}, err } - dsInfo := e.getDSInfo(region) - dsInfo.Namespace = namespace - params := &cloudwatch.ListMetricsInput{ - Namespace: aws.String(dsInfo.Namespace), + Namespace: aws.String(namespace), } plog.Debug("Listing metrics pages") @@ -735,88 +732,88 @@ func (e *cloudWatchExecutor) getAllMetrics(region string, namespace string) (clo var metricsCacheLock sync.Mutex -func (e *cloudWatchExecutor) getMetricsForCustomMetrics(region string, namespace string) ([]string, error) { +func (e *cloudWatchExecutor) getMetricsForCustomMetrics(region, namespace, profile string) ([]string, error) { plog.Debug("Getting metrics for custom metrics", "region", region, "namespace", namespace) metricsCacheLock.Lock() defer metricsCacheLock.Unlock() - dsInfo := e.getDSInfo(region) - dsInfo.Namespace = namespace - - if _, ok := customMetricsMetricsMap[dsInfo.Profile]; !ok { - customMetricsMetricsMap[dsInfo.Profile] = make(map[string]map[string]*customMetricsCache) - } - if _, ok := customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region]; !ok { - customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region] = make(map[string]*customMetricsCache) + bldr := strings.Builder{} + for i, s := range []string{profile, region, namespace} { + if i != 0 { + bldr.WriteString(":") + } + bldr.WriteString(strings.ReplaceAll(s, ":", `\:`)) } - if _, ok := customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace]; !ok { - customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace] = &customMetricsCache{} - customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache = make([]string, 0) + cacheKey := bldr.String() + + if _, ok := customMetricsMetricsMap[cacheKey]; !ok { + customMetricsMetricsMap[cacheKey] = &customMetricsCache{} + customMetricsMetricsMap[cacheKey].Cache = make([]string, 0) } - if customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Expire.After(time.Now()) { - return customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache, nil + if customMetricsMetricsMap[cacheKey].Expire.After(time.Now()) { + return customMetricsMetricsMap[cacheKey].Cache, nil } result, err := e.getAllMetrics(region, namespace) if err != nil { return []string{}, err } - customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache = make([]string, 0) - customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Expire = time.Now().Add(5 * time.Minute) + customMetricsMetricsMap[cacheKey].Cache = make([]string, 0) + customMetricsMetricsMap[cacheKey].Expire = time.Now().Add(5 * time.Minute) for _, metric := range result.Metrics { - if isDuplicate(customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache, *metric.MetricName) { + if isDuplicate(customMetricsMetricsMap[cacheKey].Cache, *metric.MetricName) { continue } - customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache = append( - customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache, *metric.MetricName) + customMetricsMetricsMap[cacheKey].Cache = append( + customMetricsMetricsMap[cacheKey].Cache, *metric.MetricName) } - return customMetricsMetricsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache, nil + return customMetricsMetricsMap[cacheKey].Cache, nil } var dimensionsCacheLock sync.Mutex -func (e *cloudWatchExecutor) getDimensionsForCustomMetrics(region string, namespace string) ([]string, error) { +func (e *cloudWatchExecutor) getDimensionsForCustomMetrics(region, namespace, profile string) ([]string, error) { dimensionsCacheLock.Lock() defer dimensionsCacheLock.Unlock() - dsInfo := e.getDSInfo(region) - dsInfo.Namespace = namespace - - if _, ok := customMetricsDimensionsMap[dsInfo.Profile]; !ok { - customMetricsDimensionsMap[dsInfo.Profile] = make(map[string]map[string]*customMetricsCache) - } - if _, ok := customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region]; !ok { - customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region] = make(map[string]*customMetricsCache) + bldr := strings.Builder{} + for i, s := range []string{profile, region, namespace} { + if i != 0 { + bldr.WriteString(":") + } + bldr.WriteString(strings.ReplaceAll(s, ":", `\:`)) } - if _, ok := customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace]; !ok { - customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace] = &customMetricsCache{} - customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache = make([]string, 0) + cacheKey := bldr.String() + + if _, ok := customMetricsDimensionsMap[cacheKey]; !ok { + customMetricsDimensionsMap[cacheKey] = &customMetricsCache{} + customMetricsDimensionsMap[cacheKey].Cache = make([]string, 0) } - if customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Expire.After(time.Now()) { - return customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache, nil + if customMetricsDimensionsMap[cacheKey].Expire.After(time.Now()) { + return customMetricsDimensionsMap[cacheKey].Cache, nil } result, err := e.getAllMetrics(region, namespace) if err != nil { return []string{}, err } - customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache = make([]string, 0) - customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Expire = time.Now().Add(5 * time.Minute) + customMetricsDimensionsMap[cacheKey].Cache = make([]string, 0) + customMetricsDimensionsMap[cacheKey].Expire = time.Now().Add(5 * time.Minute) for _, metric := range result.Metrics { for _, dimension := range metric.Dimensions { - if isDuplicate(customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache, *dimension.Name) { + if isDuplicate(customMetricsDimensionsMap[cacheKey].Cache, *dimension.Name) { continue } - customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache = append( - customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache, *dimension.Name) + customMetricsDimensionsMap[cacheKey].Cache = append( + customMetricsDimensionsMap[cacheKey].Cache, *dimension.Name) } } - return customMetricsDimensionsMap[dsInfo.Profile][dsInfo.Region][dsInfo.Namespace].Cache, nil + return customMetricsDimensionsMap[cacheKey].Cache, nil } func isDuplicate(nameList []string, target string) bool {