| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | package metrics | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/url" | 
					
						
							|  |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2022-04-25 19:30:28 -07:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							| 
									
										
										
										
											2020-06-01 12:37:39 -04:00
										 |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/data" | 
					
						
							| 
									
										
										
										
											2022-04-11 14:20:10 -04:00
										 |  |  | 	"go.opentelemetry.io/otel/attribute" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 11:10:12 +01:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azlog" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/tsdb/azuremonitor/resourcegraph" | 
					
						
							|  |  |  | 	azTime "github.com/grafana/grafana/pkg/tsdb/azuremonitor/time" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" | 
					
						
							| 
									
										
										
										
											2020-04-27 17:43:02 +02:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util/errutil" | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 01:47:38 +01:00
										 |  |  | // AzureMonitorDatasource calls the Azure Monitor API - one of the four API's supported | 
					
						
							| 
									
										
										
										
											2021-07-16 12:47:26 +02:00
										 |  |  | type AzureMonitorDatasource struct { | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 	Proxy types.ServiceProxy | 
					
						
							| 
									
										
										
										
											2021-07-16 12:47:26 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 01:17:37 +01:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 	// Used to convert the aggregation value to the Azure enum for deep linking | 
					
						
							| 
									
										
										
										
											2022-04-25 19:30:28 -07:00
										 |  |  | 	aggregationTypeMap   = map[string]int{"None": 0, "Total": 1, "Minimum": 2, "Maximum": 3, "Average": 4, "Count": 7} | 
					
						
							|  |  |  | 	resourceNameLandmark = regexp.MustCompile(`(?i)(/(?P<resourceName>[\w-\.]+)/providers/Microsoft\.Insights/metrics)`) | 
					
						
							| 
									
										
										
										
											2019-02-11 01:17:37 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | const azureMonitorAPIVersion = "2018-01-01" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | func (e *AzureMonitorDatasource) ResourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client) { | 
					
						
							|  |  |  | 	e.Proxy.Do(rw, req, cli) | 
					
						
							| 
									
										
										
										
											2021-07-16 12:47:26 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 01:47:38 +01:00
										 |  |  | // executeTimeSeriesQuery does the following: | 
					
						
							|  |  |  | // 1. build the AzureMonitor url and querystring for each query | 
					
						
							|  |  |  | // 2. executes each query by calling the Azure Monitor API | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | // 3. parses the responses for each query into data frames | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | func (e *AzureMonitorDatasource) ExecuteTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo types.DatasourceInfo, client *http.Client, | 
					
						
							| 
									
										
										
										
											2022-01-20 11:10:12 +01:00
										 |  |  | 	url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error) { | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 	result := backend.NewQueryDataResponse() | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 	queries, err := e.buildQueries(originalQueries, dsInfo) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, query := range queries { | 
					
						
							| 
									
										
										
										
											2022-01-20 11:10:12 +01:00
										 |  |  | 		result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url, tracer) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInfo types.DatasourceInfo) ([]*types.AzureMonitorQuery, error) { | 
					
						
							|  |  |  | 	azureMonitorQueries := []*types.AzureMonitorQuery{} | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, query := range queries { | 
					
						
							|  |  |  | 		var target string | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 		queryJSONModel := types.AzureMonitorJSONQuery{} | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 		err := json.Unmarshal(query.JSON, &queryJSONModel) | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("failed to decode the Azure Monitor query object from JSON: %w", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		azJSONModel := queryJSONModel.AzureMonitor | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 13:27:08 +01:00
										 |  |  | 		ub := urlBuilder{ | 
					
						
							| 
									
										
										
										
											2022-03-31 08:20:29 -07:00
										 |  |  | 			ResourceURI: azJSONModel.ResourceURI, | 
					
						
							|  |  |  | 			// Legacy, used to reconstruct resource URI if it's not present | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 			DefaultSubscription: dsInfo.Settings.SubscriptionId, | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | 			Subscription:        queryJSONModel.Subscription, | 
					
						
							| 
									
										
										
										
											2022-03-31 08:20:29 -07:00
										 |  |  | 			ResourceGroup:       azJSONModel.ResourceGroup, | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | 			MetricDefinition:    azJSONModel.MetricDefinition, | 
					
						
							|  |  |  | 			ResourceName:        azJSONModel.ResourceName, | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-10 15:05:48 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		azJSONModel.DimensionFilters = MigrateDimensionFilters(azJSONModel.DimensionFilters) | 
					
						
							| 
									
										
										
										
											2022-03-31 08:20:29 -07:00
										 |  |  | 		azureURL := ub.BuildMetricsURL() | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-25 19:30:28 -07:00
										 |  |  | 		resourceName := azJSONModel.ResourceName | 
					
						
							|  |  |  | 		if resourceName == "" { | 
					
						
							|  |  |  | 			resourceName = extractResourceNameFromMetricsURL(azureURL) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		urlComponents := map[string]string{} | 
					
						
							|  |  |  | 		urlComponents["resourceURI"] = azJSONModel.ResourceURI | 
					
						
							|  |  |  | 		// Legacy fields used for constructing a deep link to display the query in Azure Portal. | 
					
						
							|  |  |  | 		urlComponents["subscription"] = queryJSONModel.Subscription | 
					
						
							|  |  |  | 		urlComponents["resourceGroup"] = azJSONModel.ResourceGroup | 
					
						
							|  |  |  | 		urlComponents["metricDefinition"] = azJSONModel.MetricDefinition | 
					
						
							|  |  |  | 		urlComponents["resourceName"] = resourceName | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | 		alias := azJSONModel.Alias | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | 		timeGrain := azJSONModel.TimeGrain | 
					
						
							|  |  |  | 		timeGrains := azJSONModel.AllowedTimeGrainsMs | 
					
						
							| 
									
										
										
										
											2022-05-20 15:45:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 01:17:37 +01:00
										 |  |  | 		if timeGrain == "auto" { | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 			timeGrain, err = azTime.SetAutoTimeGrain(query.Interval.Milliseconds(), timeGrains) | 
					
						
							| 
									
										
										
										
											2019-02-11 01:17:37 +01:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 		params := url.Values{} | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | 		params.Add("api-version", azureMonitorAPIVersion) | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 		params.Add("timespan", fmt.Sprintf("%v/%v", query.TimeRange.From.UTC().Format(time.RFC3339), query.TimeRange.To.UTC().Format(time.RFC3339))) | 
					
						
							| 
									
										
										
										
											2019-02-11 01:17:37 +01:00
										 |  |  | 		params.Add("interval", timeGrain) | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | 		params.Add("aggregation", azJSONModel.Aggregation) | 
					
						
							|  |  |  | 		params.Add("metricnames", azJSONModel.MetricName) // MetricName or MetricNames ? | 
					
						
							|  |  |  | 		params.Add("metricnamespace", azJSONModel.MetricNamespace) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 		// old model | 
					
						
							| 
									
										
										
										
											2020-05-26 10:52:33 -04:00
										 |  |  | 		dimension := strings.TrimSpace(azJSONModel.Dimension) | 
					
						
							|  |  |  | 		dimensionFilter := strings.TrimSpace(azJSONModel.DimensionFilter) | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		dimSB := strings.Builder{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-08 15:12:08 -04:00
										 |  |  | 		if dimension != "" && dimensionFilter != "" && dimension != "None" && len(azJSONModel.DimensionFilters) == 0 { | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 			dimSB.WriteString(fmt.Sprintf("%s eq '%s'", dimension, dimensionFilter)) | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2020-09-08 15:12:08 -04:00
										 |  |  | 			for i, filter := range azJSONModel.DimensionFilters { | 
					
						
							| 
									
										
										
										
											2022-05-10 15:05:48 +01:00
										 |  |  | 				if len(filter.Filters) == 0 { | 
					
						
							| 
									
										
										
										
											2022-04-29 17:01:13 +01:00
										 |  |  | 					dimSB.WriteString(fmt.Sprintf("%s eq '*'", filter.Dimension)) | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2022-05-10 15:05:48 +01:00
										 |  |  | 					dimSB.WriteString(filter.ConstructFiltersString()) | 
					
						
							| 
									
										
										
										
											2022-04-29 17:01:13 +01:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-09-08 15:12:08 -04:00
										 |  |  | 				if i != len(azJSONModel.DimensionFilters)-1 { | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 					dimSB.WriteString(" and ") | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if dimSB.String() != "" { | 
					
						
							|  |  |  | 			params.Add("$filter", dimSB.String()) | 
					
						
							| 
									
										
										
										
											2022-03-29 07:27:09 -07:00
										 |  |  | 			if azJSONModel.Top != "" { | 
					
						
							|  |  |  | 				params.Add("top", azJSONModel.Top) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		target = params.Encode() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 15:45:45 +02:00
										 |  |  | 		if setting.Env == setting.Dev { | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 			azlog.Debug("Azuremonitor request", "params", params) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 		azureMonitorQueries = append(azureMonitorQueries, &types.AzureMonitorQuery{ | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 			URL:           azureURL, | 
					
						
							|  |  |  | 			UrlComponents: urlComponents, | 
					
						
							|  |  |  | 			Target:        target, | 
					
						
							|  |  |  | 			Params:        params, | 
					
						
							| 
									
										
										
										
											2021-03-08 07:02:49 +01:00
										 |  |  | 			RefID:         query.RefID, | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 			Alias:         alias, | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 			TimeRange:     query.TimeRange, | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return azureMonitorQueries, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *types.AzureMonitorQuery, dsInfo types.DatasourceInfo, cli *http.Client, | 
					
						
							| 
									
										
										
										
											2022-01-20 11:10:12 +01:00
										 |  |  | 	url string, tracer tracing.Tracer) backend.DataResponse { | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 	dataResponse := backend.DataResponse{} | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-16 12:47:26 +02:00
										 |  |  | 	req, err := e.createRequest(ctx, dsInfo, url) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 		dataResponse.Error = err | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 		return dataResponse | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req.URL.Path = path.Join(req.URL.Path, query.URL) | 
					
						
							|  |  |  | 	req.URL.RawQuery = query.Params.Encode() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 11:10:12 +01:00
										 |  |  | 	ctx, span := tracer.Start(ctx, "azuremonitor query") | 
					
						
							|  |  |  | 	span.SetAttributes("target", query.Target, attribute.Key("target").String(query.Target)) | 
					
						
							|  |  |  | 	span.SetAttributes("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond), attribute.Key("from").Int64(query.TimeRange.From.UnixNano()/int64(time.Millisecond))) | 
					
						
							|  |  |  | 	span.SetAttributes("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond), attribute.Key("until").Int64(query.TimeRange.To.UnixNano()/int64(time.Millisecond))) | 
					
						
							|  |  |  | 	span.SetAttributes("datasource_id", dsInfo.DatasourceID, attribute.Key("datasource_id").Int64(dsInfo.DatasourceID)) | 
					
						
							|  |  |  | 	span.SetAttributes("org_id", dsInfo.OrgID, attribute.Key("org_id").Int64(dsInfo.OrgID)) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 11:10:12 +01:00
										 |  |  | 	defer span.End() | 
					
						
							|  |  |  | 	tracer.Inject(ctx, req.Header, span) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-07 05:18:14 -07:00
										 |  |  | 	azlog.Debug("AzureMonitor", "Request ApiURL", req.URL.String()) | 
					
						
							| 
									
										
										
										
											2020-04-27 17:43:02 +02:00
										 |  |  | 	azlog.Debug("AzureMonitor", "Target", query.Target) | 
					
						
							| 
									
										
										
										
											2022-04-11 14:20:10 -04:00
										 |  |  | 	res, err := cli.Do(req) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 		dataResponse.Error = err | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 		return dataResponse | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-12-15 09:32:06 +01:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err := res.Body.Close(); err != nil { | 
					
						
							|  |  |  | 			azlog.Warn("Failed to close response body", "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	data, err := e.unmarshalResponse(res) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 		dataResponse.Error = err | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 		return dataResponse | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 	azurePortalUrl, err := resourcegraph.GetAzurePortalUrl(dsInfo.Cloud) | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		dataResponse.Error = err | 
					
						
							|  |  |  | 		return dataResponse | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dataResponse.Frames, err = e.parseResponse(data, query, azurePortalUrl) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		dataResponse.Error = err | 
					
						
							|  |  |  | 		return dataResponse | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 	return dataResponse | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | func (e *AzureMonitorDatasource) createRequest(ctx context.Context, dsInfo types.DatasourceInfo, url string) (*http.Request, error) { | 
					
						
							| 
									
										
										
										
											2022-04-11 14:20:10 -04:00
										 |  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-27 17:43:02 +02:00
										 |  |  | 		azlog.Debug("Failed to create request", "error", err) | 
					
						
							|  |  |  | 		return nil, errutil.Wrap("Failed to create request", err) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	req.Header.Set("Content-Type", "application/json") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return req, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | func (e *AzureMonitorDatasource) unmarshalResponse(res *http.Response) (types.AzureMonitorResponse, error) { | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	body, err := ioutil.ReadAll(res.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 		return types.AzureMonitorResponse{}, err | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if res.StatusCode/100 != 2 { | 
					
						
							| 
									
										
										
										
											2020-04-27 17:43:02 +02:00
										 |  |  | 		azlog.Debug("Request failed", "status", res.Status, "body", string(body)) | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 		return types.AzureMonitorResponse{}, fmt.Errorf("request failed, status: %s", res.Status) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 	var data types.AzureMonitorResponse | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	err = json.Unmarshal(body, &data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-27 17:43:02 +02:00
										 |  |  | 		azlog.Debug("Failed to unmarshal AzureMonitor response", "error", err, "status", res.Status, "body", string(body)) | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 		return types.AzureMonitorResponse{}, err | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return data, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | func (e *AzureMonitorDatasource) parseResponse(amr types.AzureMonitorResponse, query *types.AzureMonitorQuery, azurePortalUrl string) (data.Frames, error) { | 
					
						
							| 
									
										
										
										
											2020-06-01 12:37:39 -04:00
										 |  |  | 	if len(amr.Value) == 0 { | 
					
						
							| 
									
										
										
										
											2021-03-08 07:02:49 +01:00
										 |  |  | 		return nil, nil | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 	queryUrl, err := getQueryUrl(query, azurePortalUrl) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 13:13:06 +02:00
										 |  |  | 	frames := data.Frames{} | 
					
						
							| 
									
										
										
										
											2020-06-01 12:37:39 -04:00
										 |  |  | 	for _, series := range amr.Value[0].Timeseries { | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 		labels := data.Labels{} | 
					
						
							|  |  |  | 		for _, md := range series.Metadatavalues { | 
					
						
							|  |  |  | 			labels[md.Name.LocalizedValue] = md.Value | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-01 12:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-09 08:15:19 -04:00
										 |  |  | 		frame := data.NewFrameOfFieldTypes("", len(series.Data), data.FieldTypeTime, data.FieldTypeNullableFloat64) | 
					
						
							| 
									
										
										
										
											2020-06-01 12:37:39 -04:00
										 |  |  | 		frame.RefID = query.RefID | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 -04:00
										 |  |  | 		timeField := frame.Fields[0] | 
					
						
							|  |  |  | 		timeField.Name = data.TimeSeriesTimeFieldName | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 		dataField := frame.Fields[1] | 
					
						
							|  |  |  | 		dataField.Name = amr.Value[0].Name.LocalizedValue | 
					
						
							|  |  |  | 		dataField.Labels = labels | 
					
						
							| 
									
										
										
										
											2020-08-06 16:03:25 -04:00
										 |  |  | 		if amr.Value[0].Unit != "Unspecified" { | 
					
						
							|  |  |  | 			dataField.SetConfig(&data.FieldConfig{ | 
					
						
							|  |  |  | 				Unit: toGrafanaUnit(amr.Value[0].Unit), | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 		if query.Alias != "" { | 
					
						
							| 
									
										
										
										
											2020-08-21 11:37:30 -04:00
										 |  |  | 			displayName := formatAzureMonitorLegendKey(query.Alias, query.UrlComponents["resourceName"], | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 				amr.Value[0].Name.LocalizedValue, "", "", amr.Namespace, amr.Value[0].ID, labels) | 
					
						
							| 
									
										
										
										
											2020-08-21 11:37:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if dataField.Config != nil { | 
					
						
							|  |  |  | 				dataField.Config.DisplayName = displayName | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				dataField.SetConfig(&data.FieldConfig{ | 
					
						
							|  |  |  | 					DisplayName: displayName, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 12:37:39 -04:00
										 |  |  | 		requestedAgg := query.Params.Get("aggregation") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for i, point := range series.Data { | 
					
						
							| 
									
										
										
										
											2020-10-09 08:15:19 -04:00
										 |  |  | 			var value *float64 | 
					
						
							| 
									
										
										
										
											2020-06-01 12:37:39 -04:00
										 |  |  | 			switch requestedAgg { | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 			case "Average": | 
					
						
							|  |  |  | 				value = point.Average | 
					
						
							|  |  |  | 			case "Total": | 
					
						
							|  |  |  | 				value = point.Total | 
					
						
							|  |  |  | 			case "Maximum": | 
					
						
							|  |  |  | 				value = point.Maximum | 
					
						
							|  |  |  | 			case "Minimum": | 
					
						
							|  |  |  | 				value = point.Minimum | 
					
						
							|  |  |  | 			case "Count": | 
					
						
							|  |  |  | 				value = point.Count | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				value = point.Count | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-06-01 12:37:39 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			frame.SetRow(i, point.TimeStamp, value) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 		frameWithLink := resourcegraph.AddConfigLinks(*frame, queryUrl) | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 		frames = append(frames, &frameWithLink) | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 14:54:51 +02:00
										 |  |  | 	return frames, nil | 
					
						
							| 
									
										
										
										
											2019-02-10 01:18:16 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-02-11 01:17:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | // Gets the deep link for the given query | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | func getQueryUrl(query *types.AzureMonitorQuery, azurePortalUrl string) (string, error) { | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 	aggregationType := aggregationTypeMap["Average"] | 
					
						
							|  |  |  | 	aggregation := query.Params.Get("aggregation") | 
					
						
							|  |  |  | 	if aggregation != "" { | 
					
						
							|  |  |  | 		if aggType, ok := aggregationTypeMap[aggregation]; ok { | 
					
						
							|  |  |  | 			aggregationType = aggType | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	timespan, err := json.Marshal(map[string]interface{}{ | 
					
						
							|  |  |  | 		"absolute": struct { | 
					
						
							|  |  |  | 			Start string `json:"startTime"` | 
					
						
							|  |  |  | 			End   string `json:"endTime"` | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			Start: query.TimeRange.From.UTC().Format(time.RFC3339Nano), | 
					
						
							|  |  |  | 			End:   query.TimeRange.To.UTC().Format(time.RFC3339Nano), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	escapedTime := url.QueryEscape(string(timespan)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-25 19:30:28 -07:00
										 |  |  | 	id := query.UrlComponents["resourceURI"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if id == "" { | 
					
						
							|  |  |  | 		ub := urlBuilder{ | 
					
						
							|  |  |  | 			Subscription:     query.UrlComponents["subscription"], | 
					
						
							|  |  |  | 			ResourceGroup:    query.UrlComponents["resourceGroup"], | 
					
						
							|  |  |  | 			MetricDefinition: query.UrlComponents["metricDefinition"], | 
					
						
							|  |  |  | 			ResourceName:     query.UrlComponents["resourceName"], | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		id = ub.buildResourceURIFromLegacyQuery() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 	chartDef, err := json.Marshal(map[string]interface{}{ | 
					
						
							|  |  |  | 		"v2charts": []interface{}{ | 
					
						
							|  |  |  | 			map[string]interface{}{ | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 				"metrics": []types.MetricChartDefinition{ | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 					{ | 
					
						
							|  |  |  | 						ResourceMetadata: map[string]string{ | 
					
						
							|  |  |  | 							"id": id, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 						Name:            query.Params.Get("metricnames"), | 
					
						
							|  |  |  | 						AggregationType: aggregationType, | 
					
						
							|  |  |  | 						Namespace:       query.Params.Get("metricnamespace"), | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 						MetricVisualization: types.MetricVisualization{ | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 							DisplayName:         query.Params.Get("metricnames"), | 
					
						
							|  |  |  | 							ResourceDisplayName: query.UrlComponents["resourceName"], | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	escapedChart := url.QueryEscape(string(chartDef)) | 
					
						
							| 
									
										
										
										
											2022-04-25 05:39:34 -07:00
										 |  |  | 	// Azure Portal will timeout if the chart definition includes a space character encoded as '+'. | 
					
						
							|  |  |  | 	// url.QueryEscape encodes spaces as '+'. | 
					
						
							|  |  |  | 	// Note: this will not encode '+' literals as those are already encoded as '%2B' by url.QueryEscape | 
					
						
							|  |  |  | 	escapedChart = strings.ReplaceAll(escapedChart, "+", "%20") | 
					
						
							| 
									
										
										
										
											2021-09-28 09:24:18 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return fmt.Sprintf("%s/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%s/ChartDefinition/%s", azurePortalUrl, escapedTime, escapedChart), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-07 05:18:14 -07:00
										 |  |  | // formatAzureMonitorLegendKey builds the legend key or timeseries name | 
					
						
							| 
									
										
										
										
											2019-07-04 22:47:24 +02:00
										 |  |  | // Alias patterns like {{resourcename}} are replaced with the appropriate data values. | 
					
						
							| 
									
										
										
										
											2021-03-08 07:02:49 +01:00
										 |  |  | func formatAzureMonitorLegendKey(alias string, resourceName string, metricName string, metadataName string, | 
					
						
							|  |  |  | 	metadataValue string, namespace string, seriesID string, labels data.Labels) string { | 
					
						
							| 
									
										
										
										
											2019-07-04 22:47:24 +02:00
										 |  |  | 	startIndex := strings.Index(seriesID, "/resourceGroups/") + 16 | 
					
						
							|  |  |  | 	endIndex := strings.Index(seriesID, "/providers") | 
					
						
							|  |  |  | 	resourceGroup := seriesID[startIndex:endIndex] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-07 08:42:03 -04:00
										 |  |  | 	// Could be a collision problem if there were two keys that varied only in case, but I don't think that would happen in azure. | 
					
						
							|  |  |  | 	lowerLabels := data.Labels{} | 
					
						
							|  |  |  | 	for k, v := range labels { | 
					
						
							|  |  |  | 		lowerLabels[strings.ToLower(k)] = v | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	keys := make([]string, 0, len(labels)) | 
					
						
							|  |  |  | 	for k := range lowerLabels { | 
					
						
							|  |  |  | 		keys = append(keys, k) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	keys = sort.StringSlice(keys) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 06:41:07 -08:00
										 |  |  | 	result := types.LegendKeyFormat.ReplaceAllFunc([]byte(alias), func(in []byte) []byte { | 
					
						
							| 
									
										
										
										
											2019-07-04 22:47:24 +02:00
										 |  |  | 		metaPartName := strings.Replace(string(in), "{{", "", 1) | 
					
						
							|  |  |  | 		metaPartName = strings.Replace(metaPartName, "}}", "", 1) | 
					
						
							|  |  |  | 		metaPartName = strings.ToLower(strings.TrimSpace(metaPartName)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if metaPartName == "resourcegroup" { | 
					
						
							|  |  |  | 			return []byte(resourceGroup) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if metaPartName == "namespace" { | 
					
						
							|  |  |  | 			return []byte(namespace) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if metaPartName == "resourcename" { | 
					
						
							|  |  |  | 			return []byte(resourceName) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if metaPartName == "metric" { | 
					
						
							|  |  |  | 			return []byte(metricName) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if metaPartName == "dimensionname" { | 
					
						
							| 
									
										
										
										
											2020-09-08 15:12:08 -04:00
										 |  |  | 			if len(keys) == 0 { | 
					
						
							|  |  |  | 				return []byte{} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 			return []byte(keys[0]) | 
					
						
							| 
									
										
										
										
											2019-07-04 22:47:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if metaPartName == "dimensionvalue" { | 
					
						
							| 
									
										
										
										
											2020-09-08 15:12:08 -04:00
										 |  |  | 			if len(keys) == 0 { | 
					
						
							|  |  |  | 				return []byte{} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-07-07 08:42:03 -04:00
										 |  |  | 			return []byte(lowerLabels[keys[0]]) | 
					
						
							| 
									
										
										
										
											2019-07-04 22:47:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-07 08:42:03 -04:00
										 |  |  | 		if v, ok := lowerLabels[metaPartName]; ok { | 
					
						
							| 
									
										
										
										
											2020-06-30 16:26:46 -04:00
										 |  |  | 			return []byte(v) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-04 22:47:24 +02:00
										 |  |  | 		return in | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return string(result) | 
					
						
							| 
									
										
										
										
											2019-02-11 01:22:15 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-07-20 12:29:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Map values from: | 
					
						
							| 
									
										
										
										
											2020-08-13 12:57:16 -04:00
										 |  |  | //   https://docs.microsoft.com/en-us/rest/api/monitor/metrics/list#unit | 
					
						
							| 
									
										
										
										
											2020-07-20 12:29:13 -07:00
										 |  |  | // to | 
					
						
							| 
									
										
										
										
											2021-05-06 16:29:29 +02:00
										 |  |  | //   https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts#L24 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:29:13 -07:00
										 |  |  | func toGrafanaUnit(unit string) string { | 
					
						
							|  |  |  | 	switch unit { | 
					
						
							| 
									
										
										
										
											2020-08-13 12:57:16 -04:00
										 |  |  | 	case "BitsPerSecond": | 
					
						
							|  |  |  | 		return "bps" | 
					
						
							| 
									
										
										
										
											2020-07-20 12:29:13 -07:00
										 |  |  | 	case "Bytes": | 
					
						
							|  |  |  | 		return "decbytes" // or ICE | 
					
						
							|  |  |  | 	case "BytesPerSecond": | 
					
						
							|  |  |  | 		return "Bps" | 
					
						
							| 
									
										
										
										
											2020-08-13 12:57:16 -04:00
										 |  |  | 	case "Count": | 
					
						
							|  |  |  | 		return "short" // this is used for integers | 
					
						
							| 
									
										
										
										
											2020-07-20 12:29:13 -07:00
										 |  |  | 	case "CountPerSecond": | 
					
						
							|  |  |  | 		return "cps" | 
					
						
							| 
									
										
										
										
											2020-08-13 12:57:16 -04:00
										 |  |  | 	case "Percent": | 
					
						
							|  |  |  | 		return "percent" | 
					
						
							| 
									
										
										
										
											2020-12-02 10:09:33 +01:00
										 |  |  | 	case "MilliSeconds": | 
					
						
							| 
									
										
										
										
											2020-07-20 12:29:13 -07:00
										 |  |  | 		return "ms" | 
					
						
							| 
									
										
										
										
											2020-08-13 12:57:16 -04:00
										 |  |  | 	case "Seconds": | 
					
						
							|  |  |  | 		return "s" | 
					
						
							| 
									
										
										
										
											2020-07-20 12:29:13 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return unit // this will become a suffix in the display | 
					
						
							| 
									
										
										
										
											2020-08-13 12:57:16 -04:00
										 |  |  | 	// "ByteSeconds", "Cores", "MilliCores", and "NanoCores" all both: | 
					
						
							|  |  |  | 	// 1. Do not have a corresponding unit in Grafana's current list. | 
					
						
							|  |  |  | 	// 2. Do not have the unit listed in any of Azure Monitor's supported metrics anyways. | 
					
						
							| 
									
										
										
										
											2020-07-20 12:29:13 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-04-25 19:30:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | func extractResourceNameFromMetricsURL(url string) string { | 
					
						
							|  |  |  | 	matches := resourceNameLandmark.FindStringSubmatch(url) | 
					
						
							|  |  |  | 	resourceName := "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if matches == nil { | 
					
						
							|  |  |  | 		return resourceName | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, name := range resourceNameLandmark.SubexpNames() { | 
					
						
							|  |  |  | 		if name == "resourceName" { | 
					
						
							|  |  |  | 			resourceName = matches[i] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return resourceName | 
					
						
							|  |  |  | } |