AzureMonitor: Correctly build multi-resource queries for Application Insights components (#70344)

Correctly build multi-resource queries for AI components

- Add additional query property
- Validate resource URI matches correct namespace
- Set applications property if needed
- Update tests
This commit is contained in:
Andreas Christou
2023-07-04 10:45:31 +01:00
committed by GitHub
parent 1d8628c0cd
commit 20b6ae96a3
2 changed files with 185 additions and 145 deletions
@@ -47,6 +47,7 @@ type AzureLogAnalyticsQuery struct {
Query string
Resources []string
QueryType string
AppInsightsQuery bool
}
func (e *AzureLogAnalyticsDatasource) ResourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client) {
@@ -72,10 +73,14 @@ func (e *AzureLogAnalyticsDatasource) ExecuteTimeSeriesQuery(ctx context.Context
return result, nil
}
func getApiURL(resourceOrWorkspace string) string {
func getApiURL(resourceOrWorkspace string, isAppInsightsQuery bool) string {
matchesResourceURI, _ := regexp.MatchString("^/subscriptions/", resourceOrWorkspace)
if matchesResourceURI {
if isAppInsightsQuery {
componentName := resourceOrWorkspace[strings.LastIndex(resourceOrWorkspace, "/")+1:]
return fmt.Sprintf("v1/apps/%s/query", componentName)
}
return fmt.Sprintf("v1%s/query", resourceOrWorkspace)
} else {
return fmt.Sprintf("v1/workspaces/%s/query", resourceOrWorkspace)
@@ -84,12 +89,17 @@ func getApiURL(resourceOrWorkspace string) string {
func (e *AzureLogAnalyticsDatasource) buildQueries(ctx context.Context, logger log.Logger, queries []backend.DataQuery, dsInfo types.DatasourceInfo, tracer tracing.Tracer) ([]*AzureLogAnalyticsQuery, error) {
azureLogAnalyticsQueries := []*AzureLogAnalyticsQuery{}
appInsightsRegExp, err := regexp.Compile("providers/Microsoft.Insights/components")
if err != nil {
return nil, fmt.Errorf("failed to compile Application Insights regex")
}
for _, query := range queries {
resources := []string{}
var resourceOrWorkspace string
var queryString string
var resultFormat dataquery.ResultFormat
appInsightsQuery := false
traceExploreQuery := ""
traceParentExploreQuery := ""
traceLogsExploreQuery := ""
@@ -117,6 +127,7 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(ctx context.Context, logger l
if len(azureLogAnalyticsTarget.Resources) > 0 {
resources = azureLogAnalyticsTarget.Resources
resourceOrWorkspace = azureLogAnalyticsTarget.Resources[0]
appInsightsQuery = appInsightsRegExp.Match([]byte(resourceOrWorkspace))
} else if azureLogAnalyticsTarget.Resource != nil && *azureLogAnalyticsTarget.Resource != "" {
resources = []string{*azureLogAnalyticsTarget.Resource}
resourceOrWorkspace = *azureLogAnalyticsTarget.Resource
@@ -150,6 +161,7 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(ctx context.Context, logger l
resources = azureTracesTarget.Resources
resourceOrWorkspace = azureTracesTarget.Resources[0]
appInsightsQuery = appInsightsRegExp.Match([]byte(resourceOrWorkspace))
resourcesMap := make(map[string]bool, 0)
if len(resources) > 1 {
for _, resource := range resources {
@@ -200,7 +212,7 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(ctx context.Context, logger l
}
}
apiURL := getApiURL(resourceOrWorkspace)
apiURL := getApiURL(resourceOrWorkspace, appInsightsQuery)
rawQuery, err := macros.KqlInterpolate(logger, query, dsInfo, queryString, "TimeGenerated")
if err != nil {
@@ -219,6 +231,7 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(ctx context.Context, logger l
TraceExploreQuery: traceExploreQuery,
TraceParentExploreQuery: traceParentExploreQuery,
TraceLogsExploreQuery: traceLogsExploreQuery,
AppInsightsQuery: appInsightsQuery,
})
}
@@ -436,9 +449,13 @@ func (e *AzureLogAnalyticsDatasource) createRequest(ctx context.Context, logger
"query": query.Query,
"timespan": timespan,
}
if len(query.Resources) > 1 && query.QueryType == string(dataquery.AzureQueryTypeAzureLogAnalytics) {
if len(query.Resources) > 1 && query.QueryType == string(dataquery.AzureQueryTypeAzureLogAnalytics) && !query.AppInsightsQuery {
body["workspaces"] = query.Resources
}
if query.AppInsightsQuery {
body["applications"] = query.Resources
}
jsonValue, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("%v: %w", "failed to create request", err)