diff --git a/.betterer.results b/.betterer.results index 5e3d035af55..883cfa6551b 100644 --- a/.betterer.results +++ b/.betterer.results @@ -3779,8 +3779,7 @@ exports[`better eslint`] = { "public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.test.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"], - [0, 0, 0, "Unexpected any. Specify a different type.", "3"] + [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], "public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], diff --git a/packages/grafana-ui/src/components/Select/SelectBase.tsx b/packages/grafana-ui/src/components/Select/SelectBase.tsx index 065de3928b0..4b650d22394 100644 --- a/packages/grafana-ui/src/components/Select/SelectBase.tsx +++ b/packages/grafana-ui/src/components/Select/SelectBase.tsx @@ -93,6 +93,7 @@ export function SelectBase({ 'aria-label': ariaLabel, autoFocus = false, backspaceRemovesValue = true, + blurInputOnSelect, cacheOptions, className, closeMenuOnSelect = true, @@ -213,6 +214,7 @@ export function SelectBase({ 'aria-label': ariaLabel, autoFocus, backspaceRemovesValue, + blurInputOnSelect, captureMenuScroll: false, closeMenuOnSelect, // We don't want to close if we're actually scrolling the menu diff --git a/packages/grafana-ui/src/components/Select/types.ts b/packages/grafana-ui/src/components/Select/types.ts index f223ffba58b..3994d86c78a 100644 --- a/packages/grafana-ui/src/components/Select/types.ts +++ b/packages/grafana-ui/src/components/Select/types.ts @@ -23,6 +23,7 @@ export interface SelectCommonProps { /** Focus is set to the Select when rendered*/ autoFocus?: boolean; backspaceRemovesValue?: boolean; + blurInputOnSelect?: boolean; className?: string; closeMenuOnSelect?: boolean; /** Used for custom components. For more information, see `react-select` */ diff --git a/pkg/tsdb/azuremonitor/azuremonitor.go b/pkg/tsdb/azuremonitor/azuremonitor.go index c2e93db81f2..42dccdd8ba3 100644 --- a/pkg/tsdb/azuremonitor/azuremonitor.go +++ b/pkg/tsdb/azuremonitor/azuremonitor.go @@ -35,6 +35,7 @@ func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider, t azureMonitor: &metrics.AzureMonitorDatasource{Proxy: proxy}, azureLogAnalytics: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy}, azureResourceGraph: &resourcegraph.AzureResourceGraphDatasource{Proxy: proxy}, + azureTraces: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy}, } im := datasource.NewInstanceManager(NewInstanceSettings(cfg, httpClientProvider, executors)) @@ -86,7 +87,7 @@ func NewInstanceSettings(cfg *setting.Cfg, clientProvider *httpclient.Provider, if err != nil { return nil, fmt.Errorf("error reading settings: %w", err) } - jsonDataObj := map[string]interface{}{} + jsonDataObj := map[string]any{} err = json.Unmarshal(settings.JSONData, &jsonDataObj) if err != nil { return nil, fmt.Errorf("error reading settings: %w", err) @@ -176,6 +177,9 @@ func (s *Service) getDataSourceFromPluginReq(req *backend.QueryDataRequest) (typ return types.DatasourceInfo{}, fmt.Errorf("unable to convert datasource from service instance") } dsInfo.OrgID = req.PluginContext.OrgID + + dsInfo.DatasourceName = req.PluginContext.DataSourceInstanceSettings.Name + dsInfo.DatasourceUID = req.PluginContext.DataSourceInstanceSettings.UID return dsInfo, nil } diff --git a/pkg/tsdb/azuremonitor/azuremonitor_test.go b/pkg/tsdb/azuremonitor/azuremonitor_test.go index 58daa13fcff..2116c1f929f 100644 --- a/pkg/tsdb/azuremonitor/azuremonitor_test.go +++ b/pkg/tsdb/azuremonitor/azuremonitor_test.go @@ -165,6 +165,12 @@ func Test_newMux(t *testing.T) { expectedURL: routes[azureMonitorPublic][azureLogAnalytics].URL, Err: require.NoError, }, + { + name: "creates an Azure Traces executor", + queryType: azureTraces, + expectedURL: routes[azureMonitorPublic][azureLogAnalytics].URL, + Err: require.NoError, + }, } for _, tt := range tests { @@ -189,7 +195,12 @@ func Test_newMux(t *testing.T) { } mux := s.newQueryMux() res, err := mux.QueryData(context.Background(), &backend.QueryDataRequest{ - PluginContext: backend.PluginContext{}, + PluginContext: backend.PluginContext{ + DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ + Name: "datasource_name", + UID: "datasource_UID", + }, + }, Queries: []backend.DataQuery{ {QueryType: tt.queryType}, }, diff --git a/pkg/tsdb/azuremonitor/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/azuremonitor/kinds/dataquery/types_dataquery_gen.go index 96600703b7d..5c71e070681 100644 --- a/pkg/tsdb/azuremonitor/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/azuremonitor/kinds/dataquery/types_dataquery_gen.go @@ -27,12 +27,21 @@ const ( const ( AzureLogsQueryResultFormatTable AzureLogsQueryResultFormat = "table" AzureLogsQueryResultFormatTimeSeries AzureLogsQueryResultFormat = "time_series" + AzureLogsQueryResultFormatTrace AzureLogsQueryResultFormat = "trace" ) // Defines values for AzureMonitorQueryAzureLogAnalyticsResultFormat. const ( AzureMonitorQueryAzureLogAnalyticsResultFormatTable AzureMonitorQueryAzureLogAnalyticsResultFormat = "table" AzureMonitorQueryAzureLogAnalyticsResultFormatTimeSeries AzureMonitorQueryAzureLogAnalyticsResultFormat = "time_series" + AzureMonitorQueryAzureLogAnalyticsResultFormatTrace AzureMonitorQueryAzureLogAnalyticsResultFormat = "trace" +) + +// Defines values for AzureMonitorQueryAzureTracesResultFormat. +const ( + AzureMonitorQueryAzureTracesResultFormatTable AzureMonitorQueryAzureTracesResultFormat = "table" + AzureMonitorQueryAzureTracesResultFormatTimeSeries AzureMonitorQueryAzureTracesResultFormat = "time_series" + AzureMonitorQueryAzureTracesResultFormatTrace AzureMonitorQueryAzureTracesResultFormat = "trace" ) // Defines values for AzureQueryType. @@ -46,10 +55,18 @@ const ( AzureQueryTypeAzureResourceGroups AzureQueryType = "Azure Resource Groups" AzureQueryTypeAzureResourceNames AzureQueryType = "Azure Resource Names" AzureQueryTypeAzureSubscriptions AzureQueryType = "Azure Subscriptions" + AzureQueryTypeAzureTraces AzureQueryType = "Azure Traces" AzureQueryTypeAzureWorkspaces AzureQueryType = "Azure Workspaces" AzureQueryTypeGrafanaTemplateVariableFunction AzureQueryType = "Grafana Template Variable Function" ) +// Defines values for AzureTracesQueryResultFormat. +const ( + AzureTracesQueryResultFormatTable AzureTracesQueryResultFormat = "table" + AzureTracesQueryResultFormatTimeSeries AzureTracesQueryResultFormat = "time_series" + AzureTracesQueryResultFormatTrace AzureTracesQueryResultFormat = "trace" +) + // Defines values for GrafanaTemplateVariableQueryType. const ( GrafanaTemplateVariableQueryTypeAppInsightsGroupByQuery GrafanaTemplateVariableQueryType = "AppInsightsGroupByQuery" @@ -92,6 +109,7 @@ const ( const ( ResultFormatTable ResultFormat = "table" ResultFormatTimeSeries ResultFormat = "time_series" + ResultFormatTrace ResultFormat = "trace" ) // Defines values for SubscriptionsQueryKind. @@ -352,6 +370,36 @@ type AzureMonitorQuery struct { ResultFormat *string `json:"resultFormat,omitempty"` } `json:"azureResourceGraph,omitempty"` + // Application Insights Traces sub-query properties. + AzureTraces *struct { + // Filters for property values. + Filters []struct { + // Values to filter by. + Filters []string `json:"filters"` + + // Comparison operator to use. Either equals or not equals. + Operation string `json:"operation"` + + // Property name, auto-populated based on available traces. + Property string `json:"property"` + } `json:"filters,omitempty"` + + // Operation ID. Used only for Traces queries. + OperationId *string `json:"operationId,omitempty"` + + // KQL query to be executed. + Query *string `json:"query,omitempty"` + + // Array of resource URIs to be queried. + Resources []string `json:"resources,omitempty"` + + // Specifies the format results should be returned as. + ResultFormat *AzureMonitorQueryAzureTracesResultFormat `json:"resultFormat,omitempty"` + + // Types of events to filter by. + TraceTypes []string `json:"traceTypes,omitempty"` + } `json:"azureTraces,omitempty"` + // For mixed data sources the selected datasource is on the query level. // For non mixed scenarios this is undefined. // TODO find a better way to do this ^ that's friendly to schema @@ -394,6 +442,9 @@ type AzureMonitorQuery struct { // Specifies the format results should be returned as. type AzureMonitorQueryAzureLogAnalyticsResultFormat string +// Specifies the format results should be returned as. +type AzureMonitorQueryAzureTracesResultFormat string + // @deprecated Legacy template variable support. type AzureMonitorQueryGrafanaTemplateVariableFn struct { Kind *interface{} `json:"kind,omitempty"` @@ -428,6 +479,51 @@ type AzureResourceGraphQuery struct { ResultFormat *string `json:"resultFormat,omitempty"` } +// AzureTracesFilter defines model for AzureTracesFilter. +type AzureTracesFilter struct { + // Values to filter by. + Filters []string `json:"filters"` + + // Comparison operator to use. Either equals or not equals. + Operation string `json:"operation"` + + // Property name, auto-populated based on available traces. + Property string `json:"property"` +} + +// Application Insights Traces sub-query properties +type AzureTracesQuery struct { + // Filters for property values. + Filters []struct { + // Values to filter by. + Filters []string `json:"filters"` + + // Comparison operator to use. Either equals or not equals. + Operation string `json:"operation"` + + // Property name, auto-populated based on available traces. + Property string `json:"property"` + } `json:"filters,omitempty"` + + // Operation ID. Used only for Traces queries. + OperationId *string `json:"operationId,omitempty"` + + // KQL query to be executed. + Query *string `json:"query,omitempty"` + + // Array of resource URIs to be queried. + Resources []string `json:"resources,omitempty"` + + // Specifies the format results should be returned as. + ResultFormat *AzureTracesQueryResultFormat `json:"resultFormat,omitempty"` + + // Types of events to filter by. + TraceTypes []string `json:"traceTypes,omitempty"` +} + +// Specifies the format results should be returned as. +type AzureTracesQueryResultFormat string + // BaseGrafanaTemplateVariableQuery defines model for BaseGrafanaTemplateVariableQuery. type BaseGrafanaTemplateVariableQuery struct { RawQuery *string `json:"rawQuery,omitempty"` diff --git a/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource.go b/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource.go index 9e4357f2a7f..57c857337e5 100644 --- a/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource.go +++ b/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource.go @@ -12,14 +12,18 @@ import ( "net/url" "path" "regexp" + "sort" + "strings" "time" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/data" "go.opentelemetry.io/otel/attribute" + "k8s.io/utils/strings/slices" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/tracing" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/macros" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" ) @@ -32,13 +36,16 @@ type AzureLogAnalyticsDatasource struct { // AzureLogAnalyticsQuery is the query request that is built from the saved values for // from the UI type AzureLogAnalyticsQuery struct { - RefID string - ResultFormat string - URL string - JSON json.RawMessage - TimeRange backend.TimeRange - Query string - Resources []string + RefID string + ResultFormat string + URL string + TraceExploreQuery string + TraceLogsExploreQuery string + JSON json.RawMessage + TimeRange backend.TimeRange + Query string + Resources []string + QueryType string } func (e *AzureLogAnalyticsDatasource) ResourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client) { @@ -64,22 +71,7 @@ func (e *AzureLogAnalyticsDatasource) ExecuteTimeSeriesQuery(ctx context.Context return result, nil } -func getApiURL(queryJSONModel types.LogJSONQuery) string { - // Legacy queries only specify a Workspace GUID, which we need to use the old workspace-centric - // API URL for, and newer queries specifying a resource URI should use resource-centric API. - // However, legacy workspace queries using a `workspaces()` template variable will be resolved - // to a resource URI, so they should use the new resource-centric. - azureLogAnalyticsTarget := queryJSONModel.AzureLogAnalytics - var resourceOrWorkspace string - - if len(azureLogAnalyticsTarget.Resources) > 0 { - resourceOrWorkspace = azureLogAnalyticsTarget.Resources[0] - } else if azureLogAnalyticsTarget.Resource != "" { - resourceOrWorkspace = azureLogAnalyticsTarget.Resource - } else { - resourceOrWorkspace = azureLogAnalyticsTarget.Workspace - } - +func getApiURL(resourceOrWorkspace string) string { matchesResourceURI, _ := regexp.MatchString("^/subscriptions/", resourceOrWorkspace) if matchesResourceURI { @@ -93,41 +85,108 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(logger log.Logger, queries [] azureLogAnalyticsQueries := []*AzureLogAnalyticsQuery{} for _, query := range queries { - queryJSONModel := types.LogJSONQuery{} - err := json.Unmarshal(query.JSON, &queryJSONModel) - if err != nil { - return nil, fmt.Errorf("failed to decode the Azure Log Analytics query object from JSON: %w", err) + resources := []string{} + var resourceOrWorkspace string + var queryString string + var resultFormat string + traceExploreQuery := "" + traceLogsExploreQuery := "" + if query.QueryType == string(dataquery.AzureQueryTypeAzureLogAnalytics) { + queryJSONModel := types.LogJSONQuery{} + err := json.Unmarshal(query.JSON, &queryJSONModel) + if err != nil { + return nil, fmt.Errorf("failed to decode the Azure Log Analytics query object from JSON: %w", err) + } + + azureLogAnalyticsTarget := queryJSONModel.AzureLogAnalytics + logger.Debug("AzureLogAnalytics", "target", azureLogAnalyticsTarget) + + resultFormat = azureLogAnalyticsTarget.ResultFormat + if resultFormat == "" { + resultFormat = types.TimeSeries + } + + // Legacy queries only specify a Workspace GUID, which we need to use the old workspace-centric + // API URL for, and newer queries specifying a resource URI should use resource-centric API. + // However, legacy workspace queries using a `workspaces()` template variable will be resolved + // to a resource URI, so they should use the new resource-centric. + if len(azureLogAnalyticsTarget.Resources) > 0 { + resources = azureLogAnalyticsTarget.Resources + resourceOrWorkspace = azureLogAnalyticsTarget.Resources[0] + } else if azureLogAnalyticsTarget.Resource != "" { + resources = []string{azureLogAnalyticsTarget.Resource} + resourceOrWorkspace = azureLogAnalyticsTarget.Resource + } else { + resourceOrWorkspace = azureLogAnalyticsTarget.Workspace + } + + queryString = azureLogAnalyticsTarget.Query } - azureLogAnalyticsTarget := queryJSONModel.AzureLogAnalytics - logger.Debug("AzureLogAnalytics", "target", azureLogAnalyticsTarget) + if query.QueryType == string(dataquery.AzureQueryTypeAzureTraces) { + queryJSONModel := types.TracesJSONQuery{} + err := json.Unmarshal(query.JSON, &queryJSONModel) + if err != nil { + return nil, fmt.Errorf("failed to decode the Azure Traces query object from JSON: %w", err) + } - resultFormat := azureLogAnalyticsTarget.ResultFormat - if resultFormat == "" { - resultFormat = types.TimeSeries + azureTracesTarget := queryJSONModel.AzureTraces + logger.Debug("AzureTraces", "target", azureTracesTarget) + + if azureTracesTarget.ResultFormat == nil { + resultFormat = types.Table + } else { + resultFormat = string(*azureTracesTarget.ResultFormat) + if resultFormat == "" { + resultFormat = types.Table + } + } + + resources = azureTracesTarget.Resources + resourceOrWorkspace = azureTracesTarget.Resources[0] + + operationId := "" + if queryJSONModel.AzureTraces.OperationId != nil { + operationId = *queryJSONModel.AzureTraces.OperationId + } + + queryString = buildTracesQuery(operationId, queryJSONModel.AzureTraces.TraceTypes, queryJSONModel.AzureTraces.Filters, &resultFormat) + traceIdVariable := "${__data.fields.traceID}" + if operationId == "" { + traceExploreQuery = buildTracesQuery(traceIdVariable, queryJSONModel.AzureTraces.TraceTypes, queryJSONModel.AzureTraces.Filters, nil) + traceLogsExploreQuery = buildTracesLogsQuery(&traceIdVariable) + } else { + traceExploreQuery = queryString + traceLogsExploreQuery = buildTracesLogsQuery(&operationId) + } + traceExploreQuery, err = macros.KqlInterpolate(logger, query, dsInfo, traceExploreQuery, "TimeGenerated") + if err != nil { + return nil, fmt.Errorf("failed to create traces explore query: %s", err) + } + traceLogsExploreQuery, err = macros.KqlInterpolate(logger, query, dsInfo, traceLogsExploreQuery, "TimeGenerated") + if err != nil { + return nil, fmt.Errorf("failed to create traces logs explore query: %s", err) + } } - apiURL := getApiURL(queryJSONModel) + apiURL := getApiURL(resourceOrWorkspace) - rawQuery, err := macros.KqlInterpolate(logger, query, dsInfo, azureLogAnalyticsTarget.Query, "TimeGenerated") + rawQuery, err := macros.KqlInterpolate(logger, query, dsInfo, queryString, "TimeGenerated") if err != nil { return nil, err } - resources := []string{} - if len(azureLogAnalyticsTarget.Resources) > 0 { - resources = azureLogAnalyticsTarget.Resources - } else if azureLogAnalyticsTarget.Resource != "" { - resources = []string{azureLogAnalyticsTarget.Resource} - } azureLogAnalyticsQueries = append(azureLogAnalyticsQueries, &AzureLogAnalyticsQuery{ - RefID: query.RefID, - ResultFormat: resultFormat, - URL: apiURL, - JSON: query.JSON, - TimeRange: query.TimeRange, - Query: rawQuery, - Resources: resources, + RefID: query.RefID, + ResultFormat: resultFormat, + URL: apiURL, + JSON: query.JSON, + TimeRange: query.TimeRange, + Query: rawQuery, + Resources: resources, + QueryType: query.QueryType, + TraceExploreQuery: traceExploreQuery, + TraceLogsExploreQuery: traceLogsExploreQuery, }) } @@ -156,6 +215,26 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, logger l return dataResponseErrorWithExecuted(fmt.Errorf("credentials for Log Analytics are no longer supported. Go to the data source configuration to update Azure Monitor credentials")) } + queryJSONModel := dataquery.AzureMonitorQuery{} + err := json.Unmarshal(query.JSON, &queryJSONModel) + if err != nil { + dataResponse.Error = err + return dataResponse + } + + if query.QueryType == string(dataquery.AzureQueryTypeAzureTraces) { + if queryJSONModel.AzureTraces.OperationId != nil && *queryJSONModel.AzureTraces.OperationId != "" { + query, err = getCorrelationWorkspaces(ctx, logger, query, dsInfo, *queryJSONModel.AzureTraces.OperationId, tracer) + if err != nil { + dataResponse.Error = err + return dataResponse + } + } + if dataquery.ResultFormat(query.ResultFormat) == (dataquery.ResultFormatTrace) && query.Query == "" { + return dataResponseErrorWithExecuted(fmt.Errorf("cannot visualise trace events using the trace visualiser")) + } + } + req, err := e.createRequest(ctx, logger, url, query) if err != nil { dataResponse.Error = err @@ -196,7 +275,7 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, logger l return dataResponseErrorWithExecuted(err) } - frame, err := ResponseTableToFrame(t, query.RefID, query.Query) + frame, err := ResponseTableToFrame(t, query.RefID, query.Query, dataquery.AzureQueryType(query.QueryType), dataquery.ResultFormat(query.ResultFormat)) if err != nil { return dataResponseErrorWithExecuted(err) } @@ -211,10 +290,12 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, logger l return dataResponse } - queryUrl, err := getQueryUrl(query.Query, query.Resources, azurePortalBaseUrl) - if err != nil { - dataResponse.Error = err - return dataResponse + if query.QueryType == string(dataquery.AzureQueryTypeAzureTraces) && query.ResultFormat == string(dataquery.ResultFormatTrace) { + frame.Meta.PreferredVisualization = "trace" + } + + if query.ResultFormat == string(dataquery.ResultFormatTable) { + frame.Meta.PreferredVisualization = "table" } if query.ResultFormat == types.TimeSeries { @@ -229,7 +310,72 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, logger l } } - AddConfigLinks(*frame, queryUrl) + queryUrl, err := getQueryUrl(query.Query, query.Resources, azurePortalBaseUrl) + if err != nil { + dataResponse.Error = err + return dataResponse + } + + if query.QueryType == string(dataquery.AzureQueryTypeAzureTraces) { + tracesUrl, err := getTracesQueryUrl(query.Resources, azurePortalBaseUrl) + if err != nil { + dataResponse.Error = err + return dataResponse + } + linkTitle := "Explore Trace in Azure Portal" + AddConfigLinks(*frame, tracesUrl, &linkTitle) + + queryJSONModel := dataquery.AzureMonitorQuery{} + err = json.Unmarshal(query.JSON, &queryJSONModel) + if err != nil { + dataResponse.Error = err + return dataResponse + } + traceIdVariable := "${__data.fields.traceID}" + resultFormat := dataquery.AzureMonitorQueryAzureTracesResultFormatTrace + queryJSONModel.AzureTraces.ResultFormat = &resultFormat + queryJSONModel.AzureTraces.Query = &query.TraceExploreQuery + if queryJSONModel.AzureTraces.OperationId == nil || *queryJSONModel.AzureTraces.OperationId == "" { + queryJSONModel.AzureTraces.OperationId = &traceIdVariable + } + + logsQueryType := string(dataquery.AzureQueryTypeAzureLogAnalytics) + logsJSONModel := dataquery.AzureMonitorQuery{ + AzureLogAnalytics: &struct { + Query *string "json:\"query,omitempty\"" + Resource *string "json:\"resource,omitempty\"" + Resources []string "json:\"resources,omitempty\"" + ResultFormat *dataquery.AzureMonitorQueryAzureLogAnalyticsResultFormat "json:\"resultFormat,omitempty\"" + Workspace *string "json:\"workspace,omitempty\"" + }{ + Resources: queryJSONModel.AzureTraces.Resources, + Query: &query.TraceLogsExploreQuery, + }, + QueryType: &logsQueryType, + } + + AddCustomDataLink(*frame, data.DataLink{ + Title: "Explore Trace: ${__data.fields.traceID}", + URL: "", + Internal: &data.InternalDataLink{ + DatasourceUID: dsInfo.DatasourceUID, + DatasourceName: dsInfo.DatasourceName, + Query: queryJSONModel, + }, + }) + + AddCustomDataLink(*frame, data.DataLink{ + Title: "Explore Trace Logs", + URL: "", + Internal: &data.InternalDataLink{ + DatasourceUID: dsInfo.DatasourceUID, + DatasourceName: dsInfo.DatasourceName, + Query: logsJSONModel, + }, + }) + } else { + AddConfigLinks(*frame, queryUrl, nil) + } dataResponse.Frames = data.Frames{frame} return dataResponse @@ -307,6 +453,113 @@ func getQueryUrl(query string, resources []string, azurePortalUrl string) (strin return portalUrl, nil } +func getTracesQueryUrl(resources []string, azurePortalUrl string) (string, error) { + portalUrl := azurePortalUrl + portalUrl += "/#view/AppInsightsExtension/DetailsV2Blade/ComponentId~/" + resource := struct { + ResourceId string `json:"ResourceId"` + }{ + resources[0], + } + resourceMarshalled, err := json.Marshal(resource) + if err != nil { + return "", fmt.Errorf("failed to marshal application insights resource: %s", err) + } + + portalUrl += url.PathEscape(string(resourceMarshalled)) + portalUrl += "/DataModel~/" + + // We're making use of data link variables to select the necessary fields in the frontend + eventId := "%22eventId%22%3A%22${__data.fields.itemId}%22%2C" + timestamp := "%22timestamp%22%3A%22${__data.fields.startTime}%22%2C" + eventTable := "%22eventTable%22%3A%22${__data.fields.itemType}%22" + traceObject := fmt.Sprintf("%%7B%s%s%s%%7D", eventId, timestamp, eventTable) + + portalUrl += traceObject + + return portalUrl, nil +} + +func getCorrelationWorkspaces(ctx context.Context, logger log.Logger, query *AzureLogAnalyticsQuery, dsInfo types.DatasourceInfo, operationId string, tracer tracing.Tracer) (*AzureLogAnalyticsQuery, error) { + azMonService := dsInfo.Services["Azure Monitor"] + correlationUrl := azMonService.URL + fmt.Sprintf("%s/providers/microsoft.insights/transactions/%s", query.Resources[0], operationId) + + callCorrelationAPI := func(url string) (AzureCorrelationAPIResponse, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer([]byte{})) + if err != nil { + logger.Debug("Failed to create request", "error", err) + return AzureCorrelationAPIResponse{}, fmt.Errorf("%v: %w", "failed to create request", err) + } + req.URL.Path = url + req.Header.Set("Content-Type", "application/json") + values := req.URL.Query() + values.Add("api-version", "2019-10-17-preview") + req.URL.RawQuery = values.Encode() + req.Method = "GET" + + ctx, span := tracer.Start(ctx, "azure traces correlation request") + span.SetAttributes("target", req.URL, attribute.Key("target").String(req.URL.String())) + 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)) + + defer span.End() + + tracer.Inject(ctx, req.Header, span) + + logger.Debug("AzureLogAnalytics", "Traces Correlation ApiURL", req.URL.String()) + res, err := azMonService.HTTPClient.Do(req) + if err != nil { + return AzureCorrelationAPIResponse{}, err + } + body, err := io.ReadAll(res.Body) + if err != nil { + return AzureCorrelationAPIResponse{}, err + } + defer func() { + err := res.Body.Close() + if err != nil { + logger.Warn("failed to close response body", "error", err) + } + }() + + if res.StatusCode/100 != 2 { + logger.Debug("Request failed", "status", res.Status, "body", string(body)) + return AzureCorrelationAPIResponse{}, fmt.Errorf("request failed, status: %s, body: %s", res.Status, string(body)) + } + var data AzureCorrelationAPIResponse + d := json.NewDecoder(bytes.NewReader(body)) + d.UseNumber() + err = d.Decode(&data) + if err != nil { + logger.Debug("Failed to unmarshal Azure Traces correlation API response", "error", err, "status", res.Status, "body", string(body)) + return AzureCorrelationAPIResponse{}, err + } + + return data, nil + } + + var nextLink *string + var correlationResponse AzureCorrelationAPIResponse + + correlationResponse, err := callCorrelationAPI(correlationUrl) + if err != nil { + return query, err + } + nextLink = correlationResponse.Properties.NextLink + query.Resources = correlationResponse.Properties.Resources + + for nextLink != nil { + correlationResponse, err := callCorrelationAPI(correlationUrl) + if err != nil { + return query, err + } + query.Resources = append(query.Resources, correlationResponse.Properties.Resources...) + nextLink = correlationResponse.Properties.NextLink + } + + return query, nil +} + // Error definition has been inferred from real data and other model definitions like // https://github.com/Azure/azure-sdk-for-go/blob/3640559afddbad452d265b54fb1c20b30be0b062/services/preview/virtualmachineimagebuilder/mgmt/2019-05-01-preview/virtualmachineimagebuilder/models.go type AzureLogAnalyticsAPIError struct { @@ -334,6 +587,19 @@ type AzureLogAnalyticsResponse struct { Error *AzureLogAnalyticsAPIError `json:"error,omitempty"` } +type AzureCorrelationAPIResponse struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Properties AzureCorrelationAPIResponseProperties `json:"properties"` + Error *AzureLogAnalyticsAPIError `json:"error,omitempty"` +} + +type AzureCorrelationAPIResponseProperties struct { + Resources []string `json:"resources"` + NextLink *string `json:"nextLink,omitempty"` +} + // GetPrimaryResultTable returns the first table in the response named "PrimaryResult", or an // error if there is no table by that name. func (ar *AzureLogAnalyticsResponse) GetPrimaryResultTable() (*types.AzureResponseTable, error) { @@ -392,3 +658,94 @@ func encodeQuery(rawQuery string) (string, error) { return base64.StdEncoding.EncodeToString(b.Bytes()), nil } + +func buildTracesQuery(operationId string, traceTypes []string, filters []types.TracesFilters, resultFormat *string) string { + types := traceTypes + if len(types) == 0 { + types = Tables + } + + filteredTypes := make([]string, 0) + // If the result format is set to trace then we filter out all events that are of the type traces as they don't make sense when visualised as a span + if resultFormat != nil && dataquery.ResultFormat(*resultFormat) == dataquery.ResultFormatTrace { + filteredTypes = slices.Filter(filteredTypes, types, func(s string) bool { return s != "traces" }) + } else { + filteredTypes = types + } + sort.Strings(filteredTypes) + + if len(filteredTypes) == 0 { + return "" + } + + tagsMap := make(map[string]bool) + var tags []string + for _, t := range filteredTypes { + tableTags := getTagsForTable(t) + for _, i := range tableTags { + if tagsMap[i] { + continue + } + if i == "cloud_RoleInstance" || i == "cloud_RoleName" || i == "customDimensions" || i == "customMeasurements" { + continue + } + tags = append(tags, i) + tagsMap[i] = true + } + } + sort.Strings(tags) + + whereClause := "" + + if operationId != "" { + whereClause = fmt.Sprintf("| where (operation_Id != '' and operation_Id == '%s') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == '%s')", operationId, operationId) + } + + filtersClause := "" + + if len(filters) > 0 { + for _, filter := range filters { + if len(filter.Filters) == 0 { + continue + } + operation := "in" + if filter.Operation == "ne" { + operation = "!in" + } + filterValues := []string{} + for _, val := range filter.Filters { + filterValues = append(filterValues, fmt.Sprintf(`"%s"`, val)) + } + filtersClause += fmt.Sprintf("| where %s %s (%s)", filter.Property, operation, strings.Join(filterValues, ",")) + } + } + + propertiesFunc := "bag_merge(customDimensions, customMeasurements)" + if len(tags) > 0 { + propertiesFunc = fmt.Sprintf("bag_merge(bag_pack_columns(%s), customDimensions, customMeasurements)", strings.Join(tags, ",")) + } + + errorProperty := "" + if slices.Contains(filteredTypes, "exceptions") { + errorProperty = `| extend error = iff(itemType == "exceptions", true, false)` + } + + baseQuery := fmt.Sprintf(`set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true %s | where $__timeFilter()`, strings.Join(filteredTypes, ",")) + propertiesStaticQuery := `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + propertiesQuery := fmt.Sprintf(`| extend tags = %s`, propertiesFunc) + projectClause := `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc` + return baseQuery + whereClause + propertiesStaticQuery + propertiesQuery + errorProperty + filtersClause + projectClause +} + +func buildTracesLogsQuery(operationId *string) string { + tables := `union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults` + time := `| where $__timeFilter()` + operationIdFilter := fmt.Sprintf(`| where operation_Id == "%s"`, *operationId) + return strings.Join([]string{tables, time, operationIdFilter}, " \n") +} diff --git a/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource_test.go b/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource_test.go index 12983cb04b2..144193c1da0 100644 --- a/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource_test.go +++ b/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource_test.go @@ -15,6 +15,7 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/tracing" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" ) @@ -45,6 +46,7 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { }`, types.TimeSeries)), RefID: "A", TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ @@ -63,11 +65,11 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { Query: "Perf | where ['TimeGenerated'] >= datetime('2018-03-15T13:00:00Z') and ['TimeGenerated'] <= datetime('2018-03-15T13:34:00Z') | where ['Computer'] in ('comp1','comp2') | summarize avg(CounterValue) by bin(TimeGenerated, 34000ms), Computer", Resources: []string{"/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/cloud-datasources/providers/Microsoft.OperationalInsights/workspaces/AppInsightsTestDataWorkspace"}, TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, Err: require.NoError, }, - { name: "Legacy queries with a workspace GUID should use workspace-centric url", queryModel: []backend.DataQuery{ @@ -80,7 +82,8 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { "resultFormat": "%s" } }`, types.TimeSeries)), - RefID: "A", + RefID: "A", + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ @@ -98,11 +101,11 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { }`, types.TimeSeries)), Query: "Perf", Resources: []string{}, + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, Err: require.NoError, }, - { name: "Legacy workspace queries with a resource URI (from a template variable) should use resource-centric url", queryModel: []backend.DataQuery{ @@ -115,7 +118,8 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { "resultFormat": "%s" } }`, types.TimeSeries)), - RefID: "A", + RefID: "A", + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ @@ -133,11 +137,11 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { }`, types.TimeSeries)), Query: "Perf", Resources: []string{}, + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, Err: require.NoError, }, - { name: "Queries with multiple resources", queryModel: []backend.DataQuery{ @@ -150,7 +154,8 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { "resultFormat": "%s" } }`, types.TimeSeries)), - RefID: "A", + RefID: "A", + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ @@ -168,6 +173,7 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { }`, types.TimeSeries)), Query: "Perf", Resources: []string{"/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/cloud-datasources/providers/Microsoft.OperationalInsights/workspaces/AppInsightsTestDataWorkspace"}, + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, Err: require.NoError, @@ -186,6 +192,7 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { }`, types.TimeSeries)), RefID: "A", TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), }, }, azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ @@ -204,6 +211,632 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { Query: "Perf", Resources: []string{"/subscriptions/r1", "/subscriptions/r2"}, TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureLogAnalytics), + }, + }, + Err: require.NoError, + }, + + { + name: "trace query", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "traceTypes": ["trace"], + "operationId": "test-op-id" + } + }`, dataquery.ResultFormatTable)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTable), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "traceTypes": ["trace"], + "operationId": "test-op-id" + } + }`, dataquery.ResultFormatTable)), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true trace | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(customDimensions, customMeasurements)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true trace | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(customDimensions, customMeasurements)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"test-op-id\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with no result format set", + queryModel: []backend.DataQuery{ + { + JSON: []byte(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "traceTypes": ["trace"], + "operationId": "test-op-id" + } + }`), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTable), + URL: "v1/subscriptions/r1/query", + JSON: []byte(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "traceTypes": ["trace"], + "operationId": "test-op-id" + } + }`), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true trace | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(customDimensions, customMeasurements)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true trace | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(customDimensions, customMeasurements)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"test-op-id\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with no operation ID", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s" + } + }`, dataquery.ResultFormatTable)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTable), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s" + } + }`, dataquery.ResultFormatTable)), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == '${__data.fields.traceID}') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == '${__data.fields.traceID}')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"${__data.fields.traceID}\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with no types", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "operationId": "test-op-id" + } + }`, dataquery.ResultFormatTable)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTable), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "operationId": "test-op-id" + } + }`, dataquery.ResultFormatTable)), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"test-op-id\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with eq filter", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "operationId": "test-op-id", + "filters": [{"filters": ["test-app-id"], "property": "appId", "operation": "eq"}] + } + }`, dataquery.ResultFormatTable)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTable), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "operationId": "test-op-id", + "filters": [{"filters": ["test-app-id"], "property": "appId", "operation": "eq"}] + } + }`, dataquery.ResultFormatTable)), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| where appId in ("test-app-id")` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| where appId in ("test-app-id")` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"test-op-id\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with ne filter", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "operationId": "test-op-id", + "filters": [{"filters": ["test-app-id"], "property": "appId", "operation": "ne"}] + } + }`, dataquery.ResultFormatTable)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTable), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "operationId": "test-op-id", + "filters": [{"filters": ["test-app-id"], "property": "appId", "operation": "ne"}] + } + }`, dataquery.ResultFormatTable)), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| where appId !in ("test-app-id")` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| where appId !in ("test-app-id")` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"test-op-id\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with multiple filters", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "operationId": "test-op-id", + "filters": [{"filters": ["test-app-id"], "property": "appId", "operation": "ne"},{"filters": ["test-client-id"], "property": "clientId", "operation": "eq"}] + } + }`, dataquery.ResultFormatTable)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTable), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "operationId": "test-op-id", + "filters": [{"filters": ["test-app-id"], "property": "appId", "operation": "ne"},{"filters": ["test-client-id"], "property": "clientId", "operation": "eq"}] + } + }`, dataquery.ResultFormatTable)), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| where appId !in ("test-app-id")| where clientId in ("test-client-id")` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| where appId !in ("test-app-id")| where clientId in ("test-client-id")` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"test-op-id\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with trace result format", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s" + } + }`, dataquery.ResultFormatTrace)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTrace), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "resources": ["/subscriptions/r1"], + "resultFormat": "%s" + } + }`, dataquery.ResultFormatTrace)), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests,traces | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == '${__data.fields.traceID}') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == '${__data.fields.traceID}')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"${__data.fields.traceID}\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with trace result format and operation ID", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "operationId": "test-op-id", + "resources": ["/subscriptions/r1"], + "resultFormat": "%s" + } + }`, dataquery.ResultFormatTrace)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTrace), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "operationId": "test-op-id", + "resources": ["/subscriptions/r1"], + "resultFormat": "%s" + } + }`, dataquery.ResultFormatTrace)), + Query: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: `set truncationmaxrecords=10000; set truncationmaxsize=67108864; union isfuzzy=true availabilityResults,customEvents,dependencies,exceptions,pageViews,requests | where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')` + + `| where (operation_Id != '' and operation_Id == 'test-op-id') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == 'test-op-id')` + + `| extend duration = iff(isnull(column_ifexists("duration", real(null))), toreal(0), column_ifexists("duration", real(null)))` + + `| extend spanID = iff(itemType == "pageView" or isempty(column_ifexists("id", "")), tostring(new_guid()), column_ifexists("id", ""))` + + `| extend operationName = iff(isempty(column_ifexists("name", "")), column_ifexists("problemId", ""), column_ifexists("name", ""))` + + `| extend serviceName = cloud_RoleName` + + `| extend serviceTags = bag_pack_columns(cloud_RoleInstance, cloud_RoleName)` + + `| extend tags = bag_merge(bag_pack_columns(appId,appName,application_Version,assembly,client_Browser,client_City,client_CountryOrRegion,client_IP,client_Model,client_OS,client_StateOrProvince,client_Type,data,details,duration,handledAt,iKey,id,innermostAssembly,innermostMessage,innermostMethod,innermostType,itemCount,itemId,itemType,location,message,method,name,operation_Id,operation_Name,operation_ParentId,operation_SyntheticSource,outerAssembly,outerMessage,outerMethod,outerType,performanceBucket,problemId,resultCode,sdkVersion,session_Id,severityLevel,size,source,success,target,timestamp,type,url,user_AccountId,user_AuthenticatedId,user_Id), customDimensions, customMeasurements)` + + `| extend error = iff(itemType == "exceptions", true, false)` + + `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` + + `| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` + + `| order by startTime asc`, + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"test-op-id\"", + }, + }, + Err: require.NoError, + }, + { + name: "trace query with trace result format and only trace type", + queryModel: []backend.DataQuery{ + { + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "operationId": "test-op-id", + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "traceTypes": ["traces"] + } + }`, dataquery.ResultFormatTrace)), + RefID: "A", + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + }, + }, + azureLogAnalyticsQueries: []*AzureLogAnalyticsQuery{ + { + RefID: "A", + ResultFormat: string(dataquery.ResultFormatTrace), + URL: "v1/subscriptions/r1/query", + JSON: []byte(fmt.Sprintf(`{ + "queryType": "Azure Traces", + "azureTraces": { + "operationId": "test-op-id", + "resources": ["/subscriptions/r1"], + "resultFormat": "%s", + "traceTypes": ["traces"] + } + }`, dataquery.ResultFormatTrace)), + Query: "", + Resources: []string{"/subscriptions/r1"}, + TimeRange: timeRange, + QueryType: string(dataquery.AzureQueryTypeAzureTraces), + TraceExploreQuery: "", + TraceLogsExploreQuery: "union *, traces, customEvents, pageViews, requests, dependencies, exceptions, customMetrics, availabilityResults \n" + + "| where ['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z') \n" + + "| where operation_Id == \"test-op-id\"", }, }, Err: require.NoError, @@ -215,7 +848,7 @@ func TestBuildingAzureLogAnalyticsQueries(t *testing.T) { queries, err := datasource.buildQueries(logger, tt.queryModel, types.DatasourceInfo{}) tt.Err(t, err) if diff := cmp.Diff(tt.azureLogAnalyticsQueries[0], queries[0]); diff != "" { - t.Errorf("Result mismatch (-want +got):\n%s", diff) + t.Errorf("Result mismatch (-want +got): \n%s", diff) } }) } diff --git a/pkg/tsdb/azuremonitor/loganalytics/azure-response-table-frame.go b/pkg/tsdb/azuremonitor/loganalytics/azure-response-table-frame.go index ad28b2a0e08..045ba6052d7 100644 --- a/pkg/tsdb/azuremonitor/loganalytics/azure-response-table-frame.go +++ b/pkg/tsdb/azuremonitor/loganalytics/azure-response-table-frame.go @@ -4,11 +4,13 @@ import ( "encoding/json" "fmt" "math" + "sort" "strconv" "strings" "time" "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" ) @@ -43,12 +45,12 @@ func apiErrorToNotice(err *AzureLogAnalyticsAPIError) data.Notice { } // ResponseTableToFrame converts an AzureResponseTable to a data.Frame. -func ResponseTableToFrame(table *types.AzureResponseTable, refID string, executedQuery string) (*data.Frame, error) { +func ResponseTableToFrame(table *types.AzureResponseTable, refID string, executedQuery string, queryType dataquery.AzureQueryType, resultFormat dataquery.ResultFormat) (*data.Frame, error) { if len(table.Rows) == 0 { return nil, nil } - converterFrame, err := converterFrameForTable(table) + converterFrame, err := converterFrameForTable(table, queryType, resultFormat) if err != nil { return nil, err } @@ -64,7 +66,7 @@ func ResponseTableToFrame(table *types.AzureResponseTable, refID string, execute return converterFrame.Frame, nil } -func converterFrameForTable(t *types.AzureResponseTable) (*data.FrameInputConverter, error) { +func converterFrameForTable(t *types.AzureResponseTable, queryType dataquery.AzureQueryType, resultFormat dataquery.ResultFormat) (*data.FrameInputConverter, error) { converters := []data.FieldConverter{} colNames := make([]string, len(t.Columns)) colTypes := make([]string, len(t.Columns)) // for metadata @@ -76,6 +78,9 @@ func converterFrameForTable(t *types.AzureResponseTable) (*data.FrameInputConver if !ok { return nil, fmt.Errorf("unsupported analytics column type %v", col.Type) } + if queryType == dataquery.AzureQueryTypeAzureTraces && resultFormat == dataquery.ResultFormatTrace && (col.Name == "serviceTags" || col.Name == "tags") { + converter = tagsConverter + } converters = append(converters, converter) } @@ -112,6 +117,58 @@ var converterMap = map[string]data.FieldConverter{ "number": decimalConverter, } +type KeyValue struct { + Value interface{} `json:"value"` + Key string `json:"key"` +} + +var tagsConverter = data.FieldConverter{ + OutputFieldType: data.FieldTypeNullableJSON, + Converter: func(v interface{}) (interface{}, error) { + if v == nil { + return nil, nil + } + + m := map[string]any{} + err := json.Unmarshal([]byte(v.(string)), &m) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal trace tags: %s", err) + } + + parsedTags := make([]*KeyValue, 0, len(m)-1) + for k, v := range m { + if v == nil { + continue + } + + switch v.(type) { + case float64: + if v == 0 { + continue + } + case string: + if v == "" { + continue + } + } + + parsedTags = append(parsedTags, &KeyValue{Key: k, Value: v}) + } + sort.Slice(parsedTags, func(i, j int) bool { + return parsedTags[i].Key < parsedTags[j].Key + }) + + marshalledTags, err := json.Marshal(parsedTags) + if err != nil { + return nil, fmt.Errorf("failed to marshal parsed trace tags: %s", err) + } + + jsonTags := json.RawMessage(marshalledTags) + + return &jsonTags, nil + }, +} + var stringConverter = data.FieldConverter{ OutputFieldType: data.FieldTypeNullableString, Converter: func(v interface{}) (interface{}, error) { diff --git a/pkg/tsdb/azuremonitor/loganalytics/azure-response-table-frame_test.go b/pkg/tsdb/azuremonitor/loganalytics/azure-response-table-frame_test.go index 850c58bd71e..cd69d7069ea 100644 --- a/pkg/tsdb/azuremonitor/loganalytics/azure-response-table-frame_test.go +++ b/pkg/tsdb/azuremonitor/loganalytics/azure-response-table-frame_test.go @@ -2,15 +2,15 @@ package loganalytics import ( "encoding/json" - "math" + "fmt" "os" "path/filepath" + "strings" "testing" - "time" - "github.com/google/go-cmp/cmp" "github.com/grafana/grafana-plugin-sdk-go/data" - "github.com/grafana/grafana/pkg/util" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/testdata" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -24,175 +24,87 @@ func TestLogTableToFrame(t *testing.T) { { name: "single series", testFile: "loganalytics/1-log-analytics-response-metrics-single-series.json", - expectedFrame: func() *data.Frame { - frame := data.NewFrame("", - data.NewField("TimeGenerated", nil, []*time.Time{ - util.Pointer(time.Date(2020, 4, 19, 19, 16, 6, 5e8, time.UTC)), - util.Pointer(time.Date(2020, 4, 19, 19, 16, 16, 5e8, time.UTC)), - util.Pointer(time.Date(2020, 4, 19, 19, 16, 26, 5e8, time.UTC)), - }), - data.NewField("Computer", nil, []*string{ - util.Pointer("grafana-vm"), - util.Pointer("grafana-vm"), - util.Pointer("grafana-vm"), - }), - data.NewField("avg_CounterValue", nil, []*float64{ - util.Pointer(1.1), - util.Pointer(2.2), - util.Pointer(3.3), - }), - ) - frame.Meta = &data.FrameMeta{ - Custom: &LogAnalyticsMeta{ColumnTypes: []string{"datetime", "string", "real"}}, - } - return frame - }, }, { name: "response table", testFile: "loganalytics/6-log-analytics-response-table.json", - expectedFrame: func() *data.Frame { - frame := data.NewFrame("", - data.NewField("TenantId", nil, []*string{ - util.Pointer("a2c1b44e-3e57-4410-b027-6cc0ae6dee67"), - util.Pointer("a2c1b44e-3e57-4410-b027-6cc0ae6dee67"), - util.Pointer("a2c1b44e-3e57-4410-b027-6cc0ae6dee67"), - }), - data.NewField("Computer", nil, []*string{ - util.Pointer("grafana-vm"), - util.Pointer("grafana-vm"), - util.Pointer("grafana-vm"), - }), - data.NewField("ObjectName", nil, []*string{ - util.Pointer("Memory"), - util.Pointer("Memory"), - util.Pointer("Memory"), - }), - data.NewField("CounterName", nil, []*string{ - util.Pointer("Available MBytes Memory"), - util.Pointer("Available MBytes Memory"), - util.Pointer("Available MBytes Memory"), - }), - data.NewField("InstanceName", nil, []*string{ - util.Pointer("Memory"), - util.Pointer("Memory"), - util.Pointer("Memory"), - }), - data.NewField("Min", nil, []*float64{nil, nil, nil}), - data.NewField("Max", nil, []*float64{nil, nil, nil}), - data.NewField("SampleCount", nil, []*int32{nil, nil, nil}), - data.NewField("CounterValue", nil, []*float64{ - util.Pointer(2040.0), - util.Pointer(2066.0), - util.Pointer(2066.0), - }), - data.NewField("TimeGenerated", nil, []*time.Time{ - util.Pointer(time.Date(2020, 4, 23, 11, 46, 3, 857e6, time.UTC)), - util.Pointer(time.Date(2020, 4, 23, 11, 46, 13, 857e6, time.UTC)), - util.Pointer(time.Date(2020, 4, 23, 11, 46, 23, 857e6, time.UTC)), - }), - ) - frame.Meta = &data.FrameMeta{ - Custom: &LogAnalyticsMeta{ColumnTypes: []string{"string", "string", "string", - "string", "string", "real", "real", "int", "real", "datetime"}}, - } - return frame - }, }, { name: "all supported field types", testFile: "loganalytics/7-log-analytics-all-types-table.json", - expectedFrame: func() *data.Frame { - frame := data.NewFrame("", - data.NewField("XBool", nil, []*bool{util.Pointer(true)}), - data.NewField("XString", nil, []*string{util.Pointer("Grafana")}), - data.NewField("XDateTime", nil, []*time.Time{util.Pointer(time.Date(2006, 1, 2, 22, 4, 5, 1*1e8, time.UTC))}), - data.NewField("XDynamic", nil, []*string{util.Pointer(`[{"person":"Daniel"},{"cats":23},{"diagnosis":"cat problem"}]`)}), - data.NewField("XGuid", nil, []*string{util.Pointer("74be27de-1e4e-49d9-b579-fe0b331d3642")}), - data.NewField("XInt", nil, []*int32{util.Pointer(int32(2147483647))}), - data.NewField("XLong", nil, []*int64{util.Pointer(int64(9223372036854775807))}), - data.NewField("XReal", nil, []*float64{util.Pointer(1.797693134862315708145274237317043567981e+308)}), - data.NewField("XTimeSpan", nil, []*string{util.Pointer("00:00:00.0000001")}), - data.NewField("XDecimal", nil, []*float64{util.Pointer(79228162514264337593543950335.0)}), - data.NewField("XObject", nil, []*string{util.Pointer(`"{\"person\": \"Daniel\", \"cats\": 23, \"diagnosis\": \"cat problem\"}"`)}), - data.NewField("XNumber", nil, []*float64{util.Pointer(79228162514264337593543950335.0)}), - ) - frame.Meta = &data.FrameMeta{ - Custom: &LogAnalyticsMeta{ColumnTypes: []string{"bool", "string", "datetime", - "dynamic", "guid", "int", "long", "real", "timespan", "decimal", "object", "number"}}, - } - return frame - }, }, { name: "nan and infinity in real response", testFile: "loganalytics/8-log-analytics-response-nan-inf.json", - expectedFrame: func() *data.Frame { - frame := data.NewFrame("", - data.NewField("XInf", nil, []*float64{util.Pointer(math.Inf(0))}), - data.NewField("XInfNeg", nil, []*float64{util.Pointer(math.Inf(-2))}), - data.NewField("XNan", nil, []*float64{util.Pointer(math.NaN())}), - ) - frame.Meta = &data.FrameMeta{ - Custom: &LogAnalyticsMeta{ColumnTypes: []string{"real", "real", "real"}}, - } - return frame - }, }, { name: "data and error in real response", testFile: "loganalytics/9-log-analytics-response-error.json", - expectedFrame: func() *data.Frame { - frame := data.NewFrame("", - data.NewField("OperationName", nil, []*string{util.Pointer("Create or Update Virtual Machine")}), - data.NewField("Level", nil, []*string{util.Pointer("Informational")}), - ) - frame.Meta = &data.FrameMeta{ - Custom: &LogAnalyticsMeta{ColumnTypes: []string{"string", "string"}}, - Notices: []data.Notice{{Severity: data.NoticeSeverityError, Text: "There were some errors when processing your query. Something went wrong processing your query on the server. The results of this query exceed the set limit of 1 records."}}, - } - return frame - }, }, { name: "data and warning in real response", testFile: "loganalytics/10-log-analytics-response-warning.json", - expectedFrame: func() *data.Frame { - frame := data.NewFrame("", - data.NewField("OperationName", nil, []*string{util.Pointer("Create or Update Virtual Machine")}), - data.NewField("Level", nil, []*string{util.Pointer("Informational")}), - ) - frame.Meta = &data.FrameMeta{ - Custom: &LogAnalyticsMeta{ColumnTypes: []string{"string", "string"}}, - Notices: []data.Notice{{Severity: data.NoticeSeverityWarning, Text: "There were some errors when processing your query. Something went wrong processing your query on the server. Not sure what happened."}}, - } - return frame - }, }, { name: "empty data response", testFile: "loganalytics/11-log-analytics-response-empty.json", - expectedFrame: func() *data.Frame { - return nil - }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res := loadLogAnalyticsTestFileWithNumber(t, tt.testFile) - frame, err := ResponseTableToFrame(&res.Tables[0], "A", "query") + res := loadTestFileWithNumber(t, tt.testFile) + frame, err := ResponseTableToFrame(&res.Tables[0], "A", "query", dataquery.AzureQueryTypeAzureLogAnalytics, dataquery.ResultFormatTable) appendErrorNotice(frame, res.Error) require.NoError(t, err) - if diff := cmp.Diff(tt.expectedFrame(), frame, data.FrameTestCompareOptions()...); diff != "" { - t.Errorf("Result mismatch (-want +got):\n%s", diff) - } + testdata.CheckGoldenFrame(t, "../testdata", tt.testFile, frame) }) } } -func loadLogAnalyticsTestFileWithNumber(t *testing.T, name string) AzureLogAnalyticsResponse { +func TestTraceTableToFrame(t *testing.T) { + tests := []struct { + name string + testFile string + expectedFrame func() *data.Frame + resultFormat dataquery.ResultFormat + }{ + { + name: "multi trace", + testFile: "traces/1-traces-multiple-table.json", + resultFormat: dataquery.ResultFormatTable, + }, + { + name: "multi trace as trace format", + testFile: "traces/1-traces-multiple-table.json", + resultFormat: dataquery.ResultFormatTrace, + }, + { + name: "single trace", + testFile: "traces/2-traces-single-table.json", + resultFormat: dataquery.ResultFormatTable, + }, + { + name: "single trace as trace format", + testFile: "traces/2-traces-single-table.json", + resultFormat: dataquery.ResultFormatTrace, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := loadTestFileWithNumber(t, tt.testFile) + frame, err := ResponseTableToFrame(&res.Tables[0], "A", "query", dataquery.AzureQueryTypeAzureTraces, tt.resultFormat) + appendErrorNotice(frame, res.Error) + require.NoError(t, err) + + testdata.CheckGoldenFrame(t, "../testdata", fmt.Sprintf("%s.%s", tt.testFile, strings.ReplaceAll(tt.name, " ", "-")), frame) + }) + } +} + +func loadTestFileWithNumber(t *testing.T, name string) AzureLogAnalyticsResponse { t.Helper() path := filepath.Join("../testdata", name) // Ignore gosec warning G304 since it's a test diff --git a/pkg/tsdb/azuremonitor/loganalytics/consts.go b/pkg/tsdb/azuremonitor/loganalytics/consts.go new file mode 100644 index 00000000000..529c5fcc7da --- /dev/null +++ b/pkg/tsdb/azuremonitor/loganalytics/consts.go @@ -0,0 +1,121 @@ +package loganalytics + +var Tables = []string{"availabilityResults", "dependencies", "customEvents", "exceptions", "pageViews", "requests", "traces"} + +// AttributesOmit - Properties to omit when generating the attributes bag +var AttributesOmit = map[string]string{"operationId": "operationId", "duration": "duration", "id": "id", "name": "name", "problemId": "problemId", "operation_ParentId": "operation_ParentId", "timestamp": "timestamp", "customDimensions": "customDimensions", "operation_Name": "operation_Name"} + +// CommonProperties - common resource centric properties mapped to legacy property names +var CommonProperties = map[string]string{ + "appId": "ResourceGUID", + "application_Version": "AppVersion", + "appName": "_ResourceId", + "client_Browser": "ClientBrowser", + "client_City": "ClientCity", + "client_CountryOrRegion": "ClientCountryOrRegion", + "client_IP": "ClientIP", + "client_Model": "ClientModel", + "client_OS": "ClientOS", + "client_StateOrProvince": "ClientStateOrProvince", + "client_Type": "ClientType", + "cloud_RoleInstance": "AppRoleInstance", + "cloud_RoleName": "AppRoleName", + "customDimensions": "Properties", + "customMeasurements": "Measurements", + "duration": "DurationMs", + "id": "Id", + "iKey": "IKey", + "itemCount": "ItemCount", + "itemId": "_ItemId", + "itemType": "Type", + "name": "Name", + "operation_Id": "OperationId", + "operation_Name": "OperationName", + "operation_ParentId": "OperationParentId", + "operation_SyntheticSource": "OperationSyntheticSource", + "performanceBucket": "PerformanceBucket", + "sdkVersion": "SDKVersion", + "session_Id": "SessionId", + "success": "Success", + "timestamp": "TimeGenerated", + "user_AccountId": "UserAccountId", + "user_AuthenticatedId": "UserAuthenticatedId", + "user_Id": "UserId", +} + +func copyCommonProperties(dst map[string]string, omit map[string]string) map[string]string { + for k, v := range CommonProperties { + if _, ok := omit[k]; !ok { + dst[k] = v + } + } + return dst +} + +var emptyMap = map[string]string{} + +var AvailabilityResultsSchema = copyCommonProperties(map[string]string{ + "location": "Location", + "message": "Message", + "size": "Size", +}, emptyMap) + +var DependenciesSchema = copyCommonProperties(map[string]string{ + "data": "Data", + "resultCode": "ResultCode", + "target": "Target", + "type": "DependencyType", +}, emptyMap) + +var EventsSchema = copyCommonProperties(map[string]string{}, map[string]string{"duration": "duration", "id": "id", "success": "success", "performanceBucket": "performanceBucket"}) + +var PageViewsSchema = copyCommonProperties(map[string]string{"url": "Url"}, map[string]string{"success": "success"}) + +var RequestsSchema = copyCommonProperties(map[string]string{"resultCode": "ResultCode", + "source": "Source", + "url": "Url"}, map[string]string{}) + +var ExceptionsSchema = copyCommonProperties(map[string]string{ + "assembly": "Assembly", + "details": "Details", + "handledAt": "HandledAt", + "innermostAssembly": "InnermostAssembly", + "innermostMessage": "InnermostMessage", + "innermostMethod": "InnermostMethod", + "innermostType": "InnermostType", + "message": "Message", + "method": "Method", + "outerAssembly": "OuterAssembly", + "outerMessage": "OuterMessage", + "outerMethod": "OuterMethod", + "outerType": "OuterType", + "problemId": "ProblemId", + "severityLevel": "SeverityLevel", + "type": "ExceptionType", +}, map[string]string{"duration": "duration", "id": "id", "name": "name", "performanceBucket": "performanceBucket", "success": "success"}) + +var TracesSchema = copyCommonProperties(map[string]string{ + "message": "Message", + "severityLevel": "SeverityLevel", +}, map[string]string{"duration": "duration", "id": "id", "name": "name", "performanceBucket": "performanceBucket", "success": "success"}) + +var TablesSchema = map[string]map[string]string{ + "availabilityResults": AvailabilityResultsSchema, + "dependencies": DependenciesSchema, + "customEvents": EventsSchema, + "exceptions": ExceptionsSchema, + "pageViews": PageViewsSchema, + "requests": RequestsSchema, + "traces": TracesSchema, +} + +func getTagsForTable(table string) []string { + tagsMap := TablesSchema[table] + tags := []string{} + + for k := range tagsMap { + tags = append(tags, k) + } + + return tags +} diff --git a/pkg/tsdb/azuremonitor/loganalytics/utils.go b/pkg/tsdb/azuremonitor/loganalytics/utils.go index c96b7697a80..2a3f36e64c9 100644 --- a/pkg/tsdb/azuremonitor/loganalytics/utils.go +++ b/pkg/tsdb/azuremonitor/loganalytics/utils.go @@ -7,21 +7,34 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/data" ) -func AddConfigLinks(frame data.Frame, dl string) data.Frame { +func AddCustomDataLink(frame data.Frame, dataLink data.DataLink) data.Frame { for i := range frame.Fields { if frame.Fields[i].Config == nil { frame.Fields[i].Config = &data.FieldConfig{} } - deepLink := data.DataLink{ - Title: "View in Azure Portal", - TargetBlank: true, - URL: dl, - } - frame.Fields[i].Config.Links = append(frame.Fields[i].Config.Links, deepLink) + + frame.Fields[i].Config.Links = append(frame.Fields[i].Config.Links, dataLink) } return frame } +func AddConfigLinks(frame data.Frame, dl string, title *string) data.Frame { + linkTitle := "View in Azure Portal" + if title != nil { + linkTitle = *title + } + + deepLink := data.DataLink{ + Title: linkTitle, + TargetBlank: true, + URL: dl, + } + + frame = AddCustomDataLink(frame, deepLink) + + return frame +} + func GetAzurePortalUrl(azureCloud string) (string, error) { switch azureCloud { case azsettings.AzurePublic: diff --git a/pkg/tsdb/azuremonitor/macros/macros.go b/pkg/tsdb/azuremonitor/macros/macros.go index 922ee546c23..b65d1e79e04 100644 --- a/pkg/tsdb/azuremonitor/macros/macros.go +++ b/pkg/tsdb/azuremonitor/macros/macros.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" "github.com/grafana/grafana/pkg/tsdb/legacydata/interval" ) @@ -38,7 +39,7 @@ func KqlInterpolate(logger log.Logger, query backend.DataQuery, dsInfo types.Dat engine := kqlMacroEngine{} defaultTimeFieldForAllDatasources := "timestamp" - if len(defaultTimeField) > 0 { + if len(defaultTimeField) > 0 && query.QueryType != string(dataquery.AzureQueryTypeAzureTraces) { defaultTimeFieldForAllDatasources = defaultTimeField[0] } return engine.Interpolate(logger, query, dsInfo, kql, defaultTimeFieldForAllDatasources) diff --git a/pkg/tsdb/azuremonitor/macros/macros_test.go b/pkg/tsdb/azuremonitor/macros/macros_test.go index 5ae58438ca0..516b9611dba 100644 --- a/pkg/tsdb/azuremonitor/macros/macros_test.go +++ b/pkg/tsdb/azuremonitor/macros/macros_test.go @@ -123,6 +123,16 @@ func TestAzureLogAnalyticsMacros(t *testing.T) { expected: "", Err: require.Error, }, + { + name: "traces time field should remain as timestamp", + query: backend.DataQuery{ + QueryType: "Azure Traces", + TimeRange: timeRange, + }, + kql: `$__timeFilter()`, + expected: "['timestamp'] >= datetime('2018-03-15T13:00:00Z') and ['timestamp'] <= datetime('2018-03-15T13:34:00Z')", + Err: require.NoError, + }, } for _, tt := range tests { diff --git a/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go b/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go index 9a121988629..d021f3205fc 100644 --- a/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go +++ b/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go @@ -379,7 +379,7 @@ func (e *AzureMonitorDatasource) parseResponse(amr types.AzureMonitorResponse, q return nil, err } - frameWithLink := loganalytics.AddConfigLinks(*frame, queryUrl) + frameWithLink := loganalytics.AddConfigLinks(*frame, queryUrl, nil) frames = append(frames, &frameWithLink) } diff --git a/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go b/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go index fd60ee8e4b8..f310f6b0bdb 100644 --- a/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go +++ b/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go @@ -8,6 +8,7 @@ import ( "net/url" "os" "path/filepath" + "strings" "testing" "time" @@ -20,6 +21,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/testdata" azTime "github.com/grafana/grafana/pkg/tsdb/azuremonitor/time" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" "github.com/grafana/grafana/pkg/util" @@ -351,42 +353,7 @@ func TestCustomNamespace(t *testing.T) { }) } -func makeDates(startDate time.Time, count int, interval time.Duration) (times []time.Time) { - for i := 0; i < count; i++ { - times = append(times, startDate.Add(interval*time.Duration(i))) - } - return -} - -func makeTestDataLink(url string) data.DataLink { - return data.DataLink{ - Title: "View in Azure Portal", - TargetBlank: true, - URL: url, - } -} - func TestAzureMonitorParseResponse(t *testing.T) { - // datalinks for the test frames - averageLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` + - `ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C` + - `%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`) - averageLink2 := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` + - `ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana-1%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C` + - `%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana-1%22%7D%7D%5D%7D%5D%7D`) - totalLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` + - `ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C` + - `%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`) - maxLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` + - `ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A3%2C%22namespace%22%3A%22%22%2C` + - `%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`) - minLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` + - `ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A2%2C%22namespace%22%3A%22%22%2C` + - `%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`) - countLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` + - `ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A7%2C%22namespace%22%3A%22%22%2C` + - `%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`) - tests := []struct { name string responseFile string @@ -396,137 +363,67 @@ func TestAzureMonitorParseResponse(t *testing.T) { }{ { name: "average aggregate time series response", - responseFile: "1-azure-monitor-response-avg.json", + responseFile: "azuremonitor/1-azure-monitor-response-avg.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Params: url.Values{ "aggregation": {"Average"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(2.0875), util.Pointer(2.1525), util.Pointer(2.155), util.Pointer(3.6925), util.Pointer(2.44), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{averageLink}})), - }, }, { name: "total aggregate time series response", - responseFile: "2-azure-monitor-response-total.json", + responseFile: "azuremonitor/2-azure-monitor-response-total.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Params: url.Values{ "aggregation": {"Total"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 13, 29, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{totalLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(8.26), util.Pointer(8.7), util.Pointer(14.82), util.Pointer(10.07), util.Pointer(8.52), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{totalLink}})), - }, }, { name: "maximum aggregate time series response", - responseFile: "3-azure-monitor-response-maximum.json", + responseFile: "azuremonitor/3-azure-monitor-response-maximum.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Params: url.Values{ "aggregation": {"Maximum"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 14, 26, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{maxLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(3.07), util.Pointer(2.92), util.Pointer(2.87), util.Pointer(2.27), util.Pointer(2.52), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{maxLink}})), - }, }, { name: "minimum aggregate time series response", - responseFile: "4-azure-monitor-response-minimum.json", + responseFile: "azuremonitor/4-azure-monitor-response-minimum.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Params: url.Values{ "aggregation": {"Minimum"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 14, 43, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{minLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(1.51), util.Pointer(2.38), util.Pointer(1.69), util.Pointer(2.27), util.Pointer(1.96), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{minLink}})), - }, }, { name: "count aggregate time series response", - responseFile: "5-azure-monitor-response-count.json", + responseFile: "azuremonitor/5-azure-monitor-response-count.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Params: url.Values{ "aggregation": {"Count"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 14, 44, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{countLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(4.0), util.Pointer(4.0), util.Pointer(4.0), util.Pointer(4.0), util.Pointer(4.0), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{countLink}})), - }, }, { name: "single dimension time series response", - responseFile: "6-azure-monitor-response-single-dimension.json", + responseFile: "azuremonitor/6-azure-monitor-response-single-dimension.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Params: url.Values{ "aggregation": {"Average"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Count", data.Labels{"blobtype": "PageBlob"}, - []*float64{util.Pointer(3.0), util.Pointer(3.0), util.Pointer(3.0), util.Pointer(3.0), util.Pointer(3.0), nil}). - SetConfig(&data.FieldConfig{Unit: "short", Links: []data.DataLink{averageLink}})), - - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Count", data.Labels{"blobtype": "BlockBlob"}, - []*float64{util.Pointer(1.0), util.Pointer(1.0), util.Pointer(1.0), util.Pointer(1.0), util.Pointer(1.0), nil}). - SetConfig(&data.FieldConfig{Unit: "short", Links: []data.DataLink{averageLink}})), - - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Count", data.Labels{"blobtype": "Azure Data Lake Storage"}, - []*float64{util.Pointer(0.0), util.Pointer(0.0), util.Pointer(0.0), util.Pointer(0.0), util.Pointer(0.0), nil}). - SetConfig(&data.FieldConfig{Unit: "short", Links: []data.DataLink{averageLink}})), - }, }, { name: "with alias patterns in the query", - responseFile: "2-azure-monitor-response-total.json", + responseFile: "azuremonitor/2-azure-monitor-response-total.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", @@ -534,19 +431,10 @@ func TestAzureMonitorParseResponse(t *testing.T) { "aggregation": {"Total"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 13, 29, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{totalLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(8.26), util.Pointer(8.7), util.Pointer(14.82), util.Pointer(10.07), util.Pointer(8.52), - }).SetConfig(&data.FieldConfig{Unit: "percent", DisplayName: "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", Links: []data.DataLink{totalLink}})), - }, }, { name: "single dimension with alias", - responseFile: "6-azure-monitor-response-single-dimension.json", + responseFile: "azuremonitor/6-azure-monitor-response-single-dimension.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Alias: "{{dimensionname}}={{DimensionValue}}", @@ -554,34 +442,10 @@ func TestAzureMonitorParseResponse(t *testing.T) { "aggregation": {"Average"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Count", data.Labels{"blobtype": "PageBlob"}, - []*float64{util.Pointer(3.0), util.Pointer(3.0), util.Pointer(3.0), util.Pointer(3.0), util.Pointer(3.0), nil}).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=PageBlob", Links: []data.DataLink{averageLink}})), - - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Count", data.Labels{"blobtype": "BlockBlob"}, []*float64{ - util.Pointer(1.0), util.Pointer(1.0), util.Pointer(1.0), util.Pointer(1.0), util.Pointer(1.0), nil, - }).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=BlockBlob", Links: []data.DataLink{averageLink}})), - - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Count", data.Labels{"blobtype": "Azure Data Lake Storage"}, []*float64{ - util.Pointer(0.0), util.Pointer(0.0), util.Pointer(0.0), util.Pointer(0.0), util.Pointer(0.0), nil, - }).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=Azure Data Lake Storage", Links: []data.DataLink{averageLink}})), - }, }, { name: "multiple dimension time series response with label alias", - responseFile: "7-azure-monitor-response-multi-dimension.json", + responseFile: "azuremonitor/7-azure-monitor-response-multi-dimension.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}", @@ -589,35 +453,10 @@ func TestAzureMonitorParseResponse(t *testing.T) { "aggregation": {"Average"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Capacity", data.Labels{"blobtype": "PageBlob", "tier": "Standard"}, - []*float64{util.Pointer(675530.0), util.Pointer(675530.0), util.Pointer(675530.0)}).SetConfig( - &data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=PageBlob, Tier=Standard}", Links: []data.DataLink{averageLink}})), - - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Capacity", data.Labels{"blobtype": "BlockBlob", "tier": "Hot"}, - []*float64{util.Pointer(0.0), util.Pointer(0.0), util.Pointer(0.0)}).SetConfig( - &data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=BlockBlob, Tier=Hot}", Links: []data.DataLink{averageLink}})), - - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Blob Capacity", data.Labels{"blobtype": "Azure Data Lake Storage", "tier": "Cool"}, - []*float64{util.Pointer(0.0), util.Pointer(0.0), util.Pointer(0.0)}).SetConfig( - &data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=Azure Data Lake Storage, Tier=Cool}", Links: []data.DataLink{averageLink}})), - }, }, { name: "unspecified unit with alias should not panic", - responseFile: "8-azure-monitor-response-unspecified-unit.json", + responseFile: "azuremonitor/8-azure-monitor-response-unspecified-unit.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Alias: "custom", @@ -625,19 +464,10 @@ func TestAzureMonitorParseResponse(t *testing.T) { "aggregation": {"Average"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - []time.Time{time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC)}, - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(2.0875), - }).SetConfig(&data.FieldConfig{DisplayName: "custom", Links: []data.DataLink{averageLink}})), - }, }, { name: "with legacy azure monitor query properties and without a resource uri", - responseFile: "2-azure-monitor-response-total.json", + responseFile: "azuremonitor/2-azure-monitor-response-total.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", @@ -645,19 +475,10 @@ func TestAzureMonitorParseResponse(t *testing.T) { "aggregation": {"Total"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 13, 29, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{totalLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(8.26), util.Pointer(8.7), util.Pointer(14.82), util.Pointer(10.07), util.Pointer(8.52), - }).SetConfig(&data.FieldConfig{Unit: "percent", DisplayName: "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", Links: []data.DataLink{totalLink}})), - }, }, { name: "with legacy azure monitor query properties and with a resource uri it should use the resource uri", - responseFile: "2-azure-monitor-response-total.json", + responseFile: "azuremonitor/2-azure-monitor-response-total.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", @@ -665,93 +486,38 @@ func TestAzureMonitorParseResponse(t *testing.T) { "aggregation": {"Total"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 9, 13, 29, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{totalLink}}), - data.NewField("Percentage CPU", nil, []*float64{ - util.Pointer(8.26), util.Pointer(8.7), util.Pointer(14.82), util.Pointer(10.07), util.Pointer(8.52), - }).SetConfig(&data.FieldConfig{Unit: "percent", DisplayName: "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", Links: []data.DataLink{totalLink}})), - }, }, { name: "multiple time series response", - responseFile: "9-azure-monitor-response-multi.json", + responseFile: "azuremonitor/9-azure-monitor-response-multi.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/providers/microsoft.insights/metrics", Params: url.Values{ "aggregation": {"Average"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Percentage CPU", data.Labels{"resourceName": "grafana"}, []*float64{ - util.Pointer(2.0875), util.Pointer(2.1525), util.Pointer(2.155), util.Pointer(3.6925), util.Pointer(2.44), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{averageLink}}), - ), - }, }, { name: "multiple time series response with multiple dimensions", - responseFile: "10-azure-monitor-response-multi-with-dimensions.json", + responseFile: "azuremonitor/10-azure-monitor-response-multi-with-dimensions.json", mockQuery: &types.AzureMonitorQuery{ URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/providers/microsoft.insights/metrics", Params: url.Values{ "aggregation": {"Average"}, }, }, - expectedFrames: data.Frames{ - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Percentage CPU", data.Labels{"resourceName": "grafana", "Test Dimension": "value-1"}, []*float64{ - util.Pointer(2.0875), util.Pointer(2.1525), util.Pointer(2.155), util.Pointer(3.6925), util.Pointer(2.44), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{averageLink}}), - ), - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}), - data.NewField("Percentage CPU", data.Labels{"resourceName": "grafana", "Test Dimension": "value-2"}, []*float64{ - util.Pointer(2.0875), util.Pointer(2.1525), util.Pointer(2.155), util.Pointer(3.6925), util.Pointer(2.44), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{averageLink}}), - ), - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink2}}), - data.NewField("Percentage CPU", data.Labels{"resourceName": "grafana-1", "Test Dimension": "value-1"}, []*float64{ - util.Pointer(2.0875), util.Pointer(2.1525), util.Pointer(2.155), util.Pointer(3.6925), util.Pointer(2.44), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{averageLink2}}), - ), - data.NewFrame("", - data.NewField("Time", nil, - makeDates(time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC), 5, time.Minute), - ).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink2}}), - data.NewField("Percentage CPU", data.Labels{"resourceName": "grafana-1", "Test Dimension": "value-3"}, []*float64{ - util.Pointer(2.0875), util.Pointer(2.1525), util.Pointer(2.155), util.Pointer(3.6925), util.Pointer(2.44), - }).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{averageLink2}}), - ), - }, }, } datasource := &AzureMonitorDatasource{} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - azData := loadTestFile(t, "azuremonitor/"+tt.responseFile) + azData := loadTestFile(t, tt.responseFile) dframes, err := datasource.parseResponse(azData, tt.mockQuery, "http://ds") require.NoError(t, err) require.NotNil(t, dframes) - if diff := cmp.Diff(tt.expectedFrames, dframes, data.FrameTestCompareOptions()...); diff != "" { - t.Errorf("Result mismatch (-want +got):\n%s", diff) - } + testdata.CheckGoldenFrames(t, "../testdata", fmt.Sprintf("%s.%s", tt.responseFile, strings.ReplaceAll(tt.name, " ", "-")), dframes) }) } } diff --git a/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go b/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go index cd1ef1e3616..20e9f70d098 100644 --- a/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go +++ b/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/tracing" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/loganalytics" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/macros" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" @@ -42,6 +43,7 @@ type AzureResourceGraphQuery struct { JSON json.RawMessage InterpolatedQuery string TimeRange backend.TimeRange + QueryType string } const ArgAPIVersion = "2021-06-01-preview" @@ -110,6 +112,7 @@ func (e *AzureResourceGraphDatasource) buildQueries(logger log.Logger, queries [ JSON: query.JSON, InterpolatedQuery: interpolatedQuery, TimeRange: query.TimeRange, + QueryType: query.QueryType, }) } @@ -193,7 +196,7 @@ func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, logger return dataResponseErrorWithExecuted(err) } - frame, err := loganalytics.ResponseTableToFrame(&argResponse.Data, query.RefID, query.InterpolatedQuery) + frame, err := loganalytics.ResponseTableToFrame(&argResponse.Data, query.RefID, query.InterpolatedQuery, dataquery.AzureQueryType(query.QueryType), dataquery.ResultFormat(query.ResultFormat)) if err != nil { return dataResponseErrorWithExecuted(err) } @@ -208,7 +211,7 @@ func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, logger } url := azurePortalUrl + "/#blade/HubsExtension/ArgQueryBlade/query/" + url.PathEscape(query.InterpolatedQuery) - frameWithLink := loganalytics.AddConfigLinks(*frame, url) + frameWithLink := loganalytics.AddConfigLinks(*frame, url, nil) if frameWithLink.Meta == nil { frameWithLink.Meta = &data.FrameMeta{} } diff --git a/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go b/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go index 54f6cc04926..d8bf3ced7a5 100644 --- a/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go +++ b/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go @@ -125,7 +125,7 @@ func TestAddConfigData(t *testing.T) { frame := data.Frame{ Fields: []*data.Field{&field}, } - frameWithLink := loganalytics.AddConfigLinks(frame, "http://ds") + frameWithLink := loganalytics.AddConfigLinks(frame, "http://ds", nil) expectedFrameWithLink := data.Frame{ Fields: []*data.Field{ { diff --git a/pkg/tsdb/azuremonitor/routes.go b/pkg/tsdb/azuremonitor/routes.go index 0a57915a1e8..430c1523add 100644 --- a/pkg/tsdb/azuremonitor/routes.go +++ b/pkg/tsdb/azuremonitor/routes.go @@ -11,6 +11,7 @@ const ( azureMonitor = "Azure Monitor" azureLogAnalytics = "Azure Log Analytics" azureResourceGraph = "Azure Resource Graph" + azureTraces = "Azure Traces" ) var azManagement = types.AzRoute{ @@ -57,6 +58,7 @@ var ( azureMonitor: azManagement, azureLogAnalytics: azLogAnalytics, azureResourceGraph: azManagement, + azureTraces: azLogAnalytics, }, azsettings.AzureUSGovernment: { azureMonitor: azUSGovManagement, diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/1-azure-monitor-response-avg.json.average-aggregate-time-series-response.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/1-azure-monitor-response-avg.json.average-aggregate-time-series-response.golden.jsonc new file mode 100644 index 00000000000..b30ba57e5cf --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/1-azure-monitor-response-avg.json.average-aggregate-time-series-response.golden.jsonc @@ -0,0 +1,83 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-08 10:13:00 +0000 UTC | 2.0875 | +// | 2019-02-08 10:14:00 +0000 UTC | 2.1525 | +// | 2019-02-08 10:15:00 +0000 UTC | 2.155 | +// | 2019-02-08 10:16:00 +0000 UTC | 3.6925 | +// | 2019-02-08 10:17:00 +0000 UTC | 2.44 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549620780000, + 1549620840000, + 1549620900000, + 1549620960000, + 1549621020000 + ], + [ + 2.0875, + 2.1525, + 2.155, + 3.6925, + 2.44 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/10-azure-monitor-response-multi-with-dimensions.json.multiple-time-series-response-with-multiple-dimensions.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/10-azure-monitor-response-multi-with-dimensions.json.multiple-time-series-response-with-multiple-dimensions.golden.jsonc new file mode 100644 index 00000000000..4facd82e9d6 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/10-azure-monitor-response-multi-with-dimensions.json.multiple-time-series-response-with-multiple-dimensions.golden.jsonc @@ -0,0 +1,323 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+------------------------------------------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: Test Dimension=value-1, resourceName=grafana | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+------------------------------------------------------+ +// | 2019-02-08 10:13:00 +0000 UTC | 2.0875 | +// | 2019-02-08 10:14:00 +0000 UTC | 2.1525 | +// | 2019-02-08 10:15:00 +0000 UTC | 2.155 | +// | 2019-02-08 10:16:00 +0000 UTC | 3.6925 | +// | 2019-02-08 10:17:00 +0000 UTC | 2.44 | +// +-------------------------------+------------------------------------------------------+ +// +// +// +// Frame[1] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+------------------------------------------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: Test Dimension=value-2, resourceName=grafana | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+------------------------------------------------------+ +// | 2019-02-08 10:13:00 +0000 UTC | 2.0875 | +// | 2019-02-08 10:14:00 +0000 UTC | 2.1525 | +// | 2019-02-08 10:15:00 +0000 UTC | 2.155 | +// | 2019-02-08 10:16:00 +0000 UTC | 3.6925 | +// | 2019-02-08 10:17:00 +0000 UTC | 2.44 | +// +-------------------------------+------------------------------------------------------+ +// +// +// +// Frame[2] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+--------------------------------------------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: Test Dimension=value-1, resourceName=grafana-1 | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+--------------------------------------------------------+ +// | 2019-02-08 10:13:00 +0000 UTC | 2.0875 | +// | 2019-02-08 10:14:00 +0000 UTC | 2.1525 | +// | 2019-02-08 10:15:00 +0000 UTC | 2.155 | +// | 2019-02-08 10:16:00 +0000 UTC | 3.6925 | +// | 2019-02-08 10:17:00 +0000 UTC | 2.44 | +// +-------------------------------+--------------------------------------------------------+ +// +// +// +// Frame[3] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+--------------------------------------------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: Test Dimension=value-3, resourceName=grafana-1 | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+--------------------------------------------------------+ +// | 2019-02-08 10:13:00 +0000 UTC | 2.0875 | +// | 2019-02-08 10:14:00 +0000 UTC | 2.1525 | +// | 2019-02-08 10:15:00 +0000 UTC | 2.155 | +// | 2019-02-08 10:16:00 +0000 UTC | 3.6925 | +// | 2019-02-08 10:17:00 +0000 UTC | 2.44 | +// +-------------------------------+--------------------------------------------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "Test Dimension": "value-1", + "resourceName": "grafana" + }, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549620780000, + 1549620840000, + 1549620900000, + 1549620960000, + 1549621020000 + ], + [ + 2.0875, + 2.1525, + 2.155, + 3.6925, + 2.44 + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "Test Dimension": "value-2", + "resourceName": "grafana" + }, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549620780000, + 1549620840000, + 1549620900000, + 1549620960000, + 1549621020000 + ], + [ + 2.0875, + 2.1525, + 2.155, + 3.6925, + 2.44 + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana-1%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana-1%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "Test Dimension": "value-1", + "resourceName": "grafana-1" + }, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana-1%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana-1%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549620780000, + 1549620840000, + 1549620900000, + 1549620960000, + 1549621020000 + ], + [ + 2.0875, + 2.1525, + 2.155, + 3.6925, + 2.44 + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana-1%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana-1%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "Test Dimension": "value-3", + "resourceName": "grafana-1" + }, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana-1%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana-1%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549620780000, + 1549620840000, + 1549620900000, + 1549620960000, + 1549621020000 + ], + [ + 2.0875, + 2.1525, + 2.155, + 3.6925, + 2.44 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.total-aggregate-time-series-response.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.total-aggregate-time-series-response.golden.jsonc new file mode 100644 index 00000000000..4774e964f20 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.total-aggregate-time-series-response.golden.jsonc @@ -0,0 +1,83 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-09 13:29:00 +0000 UTC | 8.26 | +// | 2019-02-09 13:30:00 +0000 UTC | 8.7 | +// | 2019-02-09 13:31:00 +0000 UTC | 14.82 | +// | 2019-02-09 13:32:00 +0000 UTC | 10.07 | +// | 2019-02-09 13:33:00 +0000 UTC | 8.52 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549718940000, + 1549719000000, + 1549719060000, + 1549719120000, + 1549719180000 + ], + [ + 8.26, + 8.7, + 14.82, + 10.07, + 8.52 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-alias-patterns-in-the-query.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-alias-patterns-in-the-query.golden.jsonc new file mode 100644 index 00000000000..3c425599469 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-alias-patterns-in-the-query.golden.jsonc @@ -0,0 +1,84 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-09 13:29:00 +0000 UTC | 8.26 | +// | 2019-02-09 13:30:00 +0000 UTC | 8.7 | +// | 2019-02-09 13:31:00 +0000 UTC | 14.82 | +// | 2019-02-09 13:32:00 +0000 UTC | 10.07 | +// | 2019-02-09 13:33:00 +0000 UTC | 8.52 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "displayName": "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549718940000, + 1549719000000, + 1549719060000, + 1549719120000, + 1549719180000 + ], + [ + 8.26, + 8.7, + 14.82, + 10.07, + 8.52 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-legacy-azure-monitor-query-properties-and-with-a-resource-uri-it-should-use-the-resource-uri.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-legacy-azure-monitor-query-properties-and-with-a-resource-uri-it-should-use-the-resource-uri.golden.jsonc new file mode 100644 index 00000000000..3c425599469 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-legacy-azure-monitor-query-properties-and-with-a-resource-uri-it-should-use-the-resource-uri.golden.jsonc @@ -0,0 +1,84 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-09 13:29:00 +0000 UTC | 8.26 | +// | 2019-02-09 13:30:00 +0000 UTC | 8.7 | +// | 2019-02-09 13:31:00 +0000 UTC | 14.82 | +// | 2019-02-09 13:32:00 +0000 UTC | 10.07 | +// | 2019-02-09 13:33:00 +0000 UTC | 8.52 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "displayName": "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549718940000, + 1549719000000, + 1549719060000, + 1549719120000, + 1549719180000 + ], + [ + 8.26, + 8.7, + 14.82, + 10.07, + 8.52 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-legacy-azure-monitor-query-properties-and-without-a-resource-uri.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-legacy-azure-monitor-query-properties-and-without-a-resource-uri.golden.jsonc new file mode 100644 index 00000000000..3c425599469 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/2-azure-monitor-response-total.json.with-legacy-azure-monitor-query-properties-and-without-a-resource-uri.golden.jsonc @@ -0,0 +1,84 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-09 13:29:00 +0000 UTC | 8.26 | +// | 2019-02-09 13:30:00 +0000 UTC | 8.7 | +// | 2019-02-09 13:31:00 +0000 UTC | 14.82 | +// | 2019-02-09 13:32:00 +0000 UTC | 10.07 | +// | 2019-02-09 13:33:00 +0000 UTC | 8.52 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "displayName": "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549718940000, + 1549719000000, + 1549719060000, + 1549719120000, + 1549719180000 + ], + [ + 8.26, + 8.7, + 14.82, + 10.07, + 8.52 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/3-azure-monitor-response-maximum.json.maximum-aggregate-time-series-response.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/3-azure-monitor-response-maximum.json.maximum-aggregate-time-series-response.golden.jsonc new file mode 100644 index 00000000000..7b61b79d273 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/3-azure-monitor-response-maximum.json.maximum-aggregate-time-series-response.golden.jsonc @@ -0,0 +1,83 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-09 14:26:00 +0000 UTC | 3.07 | +// | 2019-02-09 14:27:00 +0000 UTC | 2.92 | +// | 2019-02-09 14:28:00 +0000 UTC | 2.87 | +// | 2019-02-09 14:29:00 +0000 UTC | 2.27 | +// | 2019-02-09 14:30:00 +0000 UTC | 2.52 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A3%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A3%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549722360000, + 1549722420000, + 1549722480000, + 1549722540000, + 1549722600000 + ], + [ + 3.07, + 2.92, + 2.87, + 2.27, + 2.52 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/4-azure-monitor-response-minimum.json.minimum-aggregate-time-series-response.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/4-azure-monitor-response-minimum.json.minimum-aggregate-time-series-response.golden.jsonc new file mode 100644 index 00000000000..8ea7fb4bf8b --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/4-azure-monitor-response-minimum.json.minimum-aggregate-time-series-response.golden.jsonc @@ -0,0 +1,83 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-09 14:43:00 +0000 UTC | 1.51 | +// | 2019-02-09 14:44:00 +0000 UTC | 2.38 | +// | 2019-02-09 14:45:00 +0000 UTC | 1.69 | +// | 2019-02-09 14:46:00 +0000 UTC | 2.27 | +// | 2019-02-09 14:47:00 +0000 UTC | 1.96 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A2%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A2%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549723380000, + 1549723440000, + 1549723500000, + 1549723560000, + 1549723620000 + ], + [ + 1.51, + 2.38, + 1.69, + 2.27, + 1.96 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/5-azure-monitor-response-count.json.count-aggregate-time-series-response.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/5-azure-monitor-response-count.json.count-aggregate-time-series-response.golden.jsonc new file mode 100644 index 00000000000..bef9a751e15 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/5-azure-monitor-response-count.json.count-aggregate-time-series-response.golden.jsonc @@ -0,0 +1,83 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-09 14:44:00 +0000 UTC | 4 | +// | 2019-02-09 14:45:00 +0000 UTC | 4 | +// | 2019-02-09 14:46:00 +0000 UTC | 4 | +// | 2019-02-09 14:47:00 +0000 UTC | 4 | +// | 2019-02-09 14:48:00 +0000 UTC | 4 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A7%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A7%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549723440000, + 1549723500000, + 1549723560000, + 1549723620000, + 1549723680000 + ], + [ + 4, + 4, + 4, + 4, + 4 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/6-azure-monitor-response-single-dimension.json.single-dimension-time-series-response.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/6-azure-monitor-response-single-dimension.json.single-dimension-time-series-response.golden.jsonc new file mode 100644 index 00000000000..f30e3d49f55 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/6-azure-monitor-response-single-dimension.json.single-dimension-time-series-response.golden.jsonc @@ -0,0 +1,250 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 6 Rows +// +-------------------------------+---------------------------+ +// | Name: Time | Name: Blob Count | +// | Labels: | Labels: blobtype=PageBlob | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+---------------------------+ +// | 2019-02-09 15:21:00 +0000 UTC | 3 | +// | 2019-02-09 16:21:00 +0000 UTC | 3 | +// | 2019-02-09 17:21:00 +0000 UTC | 3 | +// | 2019-02-09 18:21:00 +0000 UTC | 3 | +// | 2019-02-09 19:21:00 +0000 UTC | 3 | +// | 2019-02-09 20:21:00 +0000 UTC | null | +// +-------------------------------+---------------------------+ +// +// +// +// Frame[1] +// Name: +// Dimensions: 2 Fields by 6 Rows +// +-------------------------------+----------------------------+ +// | Name: Time | Name: Blob Count | +// | Labels: | Labels: blobtype=BlockBlob | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------------+ +// | 2019-02-09 15:21:00 +0000 UTC | 1 | +// | 2019-02-09 16:21:00 +0000 UTC | 1 | +// | 2019-02-09 17:21:00 +0000 UTC | 1 | +// | 2019-02-09 18:21:00 +0000 UTC | 1 | +// | 2019-02-09 19:21:00 +0000 UTC | 1 | +// | 2019-02-09 20:21:00 +0000 UTC | null | +// +-------------------------------+----------------------------+ +// +// +// +// Frame[2] +// Name: +// Dimensions: 2 Fields by 6 Rows +// +-------------------------------+------------------------------------------+ +// | Name: Time | Name: Blob Count | +// | Labels: | Labels: blobtype=Azure Data Lake Storage | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+------------------------------------------+ +// | 2019-02-09 15:21:00 +0000 UTC | 0 | +// | 2019-02-09 16:21:00 +0000 UTC | 0 | +// | 2019-02-09 17:21:00 +0000 UTC | 0 | +// | 2019-02-09 18:21:00 +0000 UTC | 0 | +// | 2019-02-09 19:21:00 +0000 UTC | 0 | +// | 2019-02-09 20:21:00 +0000 UTC | null | +// +-------------------------------+------------------------------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Count", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "PageBlob" + }, + "config": { + "unit": "short", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549725660000, + 1549729260000, + 1549732860000, + 1549736460000, + 1549740060000, + 1549743660000 + ], + [ + 3, + 3, + 3, + 3, + 3, + null + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Count", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "BlockBlob" + }, + "config": { + "unit": "short", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549725660000, + 1549729260000, + 1549732860000, + 1549736460000, + 1549740060000, + 1549743660000 + ], + [ + 1, + 1, + 1, + 1, + 1, + null + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Count", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "Azure Data Lake Storage" + }, + "config": { + "unit": "short", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549725660000, + 1549729260000, + 1549732860000, + 1549736460000, + 1549740060000, + 1549743660000 + ], + [ + 0, + 0, + 0, + 0, + 0, + null + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/6-azure-monitor-response-single-dimension.json.single-dimension-with-alias.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/6-azure-monitor-response-single-dimension.json.single-dimension-with-alias.golden.jsonc new file mode 100644 index 00000000000..983aafc942a --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/6-azure-monitor-response-single-dimension.json.single-dimension-with-alias.golden.jsonc @@ -0,0 +1,253 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 6 Rows +// +-------------------------------+---------------------------+ +// | Name: Time | Name: Blob Count | +// | Labels: | Labels: blobtype=PageBlob | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+---------------------------+ +// | 2019-02-09 15:21:00 +0000 UTC | 3 | +// | 2019-02-09 16:21:00 +0000 UTC | 3 | +// | 2019-02-09 17:21:00 +0000 UTC | 3 | +// | 2019-02-09 18:21:00 +0000 UTC | 3 | +// | 2019-02-09 19:21:00 +0000 UTC | 3 | +// | 2019-02-09 20:21:00 +0000 UTC | null | +// +-------------------------------+---------------------------+ +// +// +// +// Frame[1] +// Name: +// Dimensions: 2 Fields by 6 Rows +// +-------------------------------+----------------------------+ +// | Name: Time | Name: Blob Count | +// | Labels: | Labels: blobtype=BlockBlob | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------------+ +// | 2019-02-09 15:21:00 +0000 UTC | 1 | +// | 2019-02-09 16:21:00 +0000 UTC | 1 | +// | 2019-02-09 17:21:00 +0000 UTC | 1 | +// | 2019-02-09 18:21:00 +0000 UTC | 1 | +// | 2019-02-09 19:21:00 +0000 UTC | 1 | +// | 2019-02-09 20:21:00 +0000 UTC | null | +// +-------------------------------+----------------------------+ +// +// +// +// Frame[2] +// Name: +// Dimensions: 2 Fields by 6 Rows +// +-------------------------------+------------------------------------------+ +// | Name: Time | Name: Blob Count | +// | Labels: | Labels: blobtype=Azure Data Lake Storage | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+------------------------------------------+ +// | 2019-02-09 15:21:00 +0000 UTC | 0 | +// | 2019-02-09 16:21:00 +0000 UTC | 0 | +// | 2019-02-09 17:21:00 +0000 UTC | 0 | +// | 2019-02-09 18:21:00 +0000 UTC | 0 | +// | 2019-02-09 19:21:00 +0000 UTC | 0 | +// | 2019-02-09 20:21:00 +0000 UTC | null | +// +-------------------------------+------------------------------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Count", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "PageBlob" + }, + "config": { + "displayName": "blobtype=PageBlob", + "unit": "short", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549725660000, + 1549729260000, + 1549732860000, + 1549736460000, + 1549740060000, + 1549743660000 + ], + [ + 3, + 3, + 3, + 3, + 3, + null + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Count", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "BlockBlob" + }, + "config": { + "displayName": "blobtype=BlockBlob", + "unit": "short", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549725660000, + 1549729260000, + 1549732860000, + 1549736460000, + 1549740060000, + 1549743660000 + ], + [ + 1, + 1, + 1, + 1, + 1, + null + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Count", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "Azure Data Lake Storage" + }, + "config": { + "displayName": "blobtype=Azure Data Lake Storage", + "unit": "short", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549725660000, + 1549729260000, + 1549732860000, + 1549736460000, + 1549740060000, + 1549743660000 + ], + [ + 0, + 0, + 0, + 0, + 0, + null + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/7-azure-monitor-response-multi-dimension.json.multiple-dimension-time-series-response-with-label-alias.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/7-azure-monitor-response-multi-dimension.json.multiple-dimension-time-series-response-with-label-alias.golden.jsonc new file mode 100644 index 00000000000..f5df32b8670 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/7-azure-monitor-response-multi-dimension.json.multiple-dimension-time-series-response-with-label-alias.golden.jsonc @@ -0,0 +1,229 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 3 Rows +// +-------------------------------+------------------------------------------+ +// | Name: Time | Name: Blob Capacity | +// | Labels: | Labels: blobtype=PageBlob, tier=Standard | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+------------------------------------------+ +// | 2020-06-30 09:58:00 +0000 UTC | 675530 | +// | 2020-06-30 10:58:00 +0000 UTC | 675530 | +// | 2020-06-30 11:58:00 +0000 UTC | 675530 | +// +-------------------------------+------------------------------------------+ +// +// +// +// Frame[1] +// Name: +// Dimensions: 2 Fields by 3 Rows +// +-------------------------------+--------------------------------------+ +// | Name: Time | Name: Blob Capacity | +// | Labels: | Labels: blobtype=BlockBlob, tier=Hot | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+--------------------------------------+ +// | 2020-06-30 09:58:00 +0000 UTC | 0 | +// | 2020-06-30 10:58:00 +0000 UTC | 0 | +// | 2020-06-30 11:58:00 +0000 UTC | 0 | +// +-------------------------------+--------------------------------------+ +// +// +// +// Frame[2] +// Name: +// Dimensions: 2 Fields by 3 Rows +// +-------------------------------+-----------------------------------------------------+ +// | Name: Time | Name: Blob Capacity | +// | Labels: | Labels: blobtype=Azure Data Lake Storage, tier=Cool | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+-----------------------------------------------------+ +// | 2020-06-30 09:58:00 +0000 UTC | 0 | +// | 2020-06-30 10:58:00 +0000 UTC | 0 | +// | 2020-06-30 11:58:00 +0000 UTC | 0 | +// +-------------------------------+-----------------------------------------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Capacity", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "PageBlob", + "tier": "Standard" + }, + "config": { + "displayName": "danieltest {Blob Type=PageBlob, Tier=Standard}", + "unit": "decbytes", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1593511080000, + 1593514680000, + 1593518280000 + ], + [ + 675530, + 675530, + 675530 + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Capacity", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "BlockBlob", + "tier": "Hot" + }, + "config": { + "displayName": "danieltest {Blob Type=BlockBlob, Tier=Hot}", + "unit": "decbytes", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1593511080000, + 1593514680000, + 1593518280000 + ], + [ + 0, + 0, + 0 + ] + ] + } + }, + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Blob Capacity", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "blobtype": "Azure Data Lake Storage", + "tier": "Cool" + }, + "config": { + "displayName": "danieltest {Blob Type=Azure Data Lake Storage, Tier=Cool}", + "unit": "decbytes", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1593511080000, + 1593514680000, + 1593518280000 + ], + [ + 0, + 0, + 0 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/8-azure-monitor-response-unspecified-unit.json.unspecified-unit-with-alias-should-not-panic.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/8-azure-monitor-response-unspecified-unit.json.unspecified-unit-with-alias-should-not-panic.golden.jsonc new file mode 100644 index 00000000000..450b3a8a54b --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/8-azure-monitor-response-unspecified-unit.json.unspecified-unit-with-alias-should-not-panic.golden.jsonc @@ -0,0 +1,71 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 1 Rows +// +-------------------------------+----------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+----------------------+ +// | 2019-02-08 10:13:00 +0000 UTC | 2.0875 | +// +-------------------------------+----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": {}, + "config": { + "displayName": "custom", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549620780000 + ], + [ + 2.0875 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/azuremonitor/9-azure-monitor-response-multi.json.multiple-time-series-response.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/azuremonitor/9-azure-monitor-response-multi.json.multiple-time-series-response.golden.jsonc new file mode 100644 index 00000000000..2c2900de3ad --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/azuremonitor/9-azure-monitor-response-multi.json.multiple-time-series-response.golden.jsonc @@ -0,0 +1,85 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] +// Name: +// Dimensions: 2 Fields by 5 Rows +// +-------------------------------+------------------------------+ +// | Name: Time | Name: Percentage CPU | +// | Labels: | Labels: resourceName=grafana | +// | Type: []time.Time | Type: []*float64 | +// +-------------------------------+------------------------------+ +// | 2019-02-08 10:13:00 +0000 UTC | 2.0875 | +// | 2019-02-08 10:14:00 +0000 UTC | 2.1525 | +// | 2019-02-08 10:15:00 +0000 UTC | 2.155 | +// | 2019-02-08 10:16:00 +0000 UTC | 3.6925 | +// | 2019-02-08 10:17:00 +0000 UTC | 2.44 | +// +-------------------------------+------------------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "fields": [ + { + "name": "Time", + "type": "time", + "typeInfo": { + "frame": "time.Time" + }, + "config": { + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + }, + { + "name": "Percentage CPU", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + }, + "labels": { + "resourceName": "grafana" + }, + "config": { + "unit": "percent", + "links": [ + { + "title": "View in Azure Portal", + "targetBlank": true, + "url": "http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D" + } + ] + } + } + ] + }, + "data": { + "values": [ + [ + 1549620780000, + 1549620840000, + 1549620900000, + 1549620960000, + 1549621020000 + ], + [ + 2.0875, + 2.1525, + 2.155, + 3.6925, + 2.44 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/loganalytics/1-log-analytics-response-metrics-single-series.json.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/loganalytics/1-log-analytics-response-metrics-single-series.json.golden.jsonc new file mode 100644 index 00000000000..95b14faac96 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/loganalytics/1-log-analytics-response-metrics-single-series.json.golden.jsonc @@ -0,0 +1,96 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "datetime", +// "string", +// "real" +// ] +// } +// } +// Name: +// Dimensions: 3 Fields by 3 Rows +// +---------------------------------+-----------------+------------------------+ +// | Name: TimeGenerated | Name: Computer | Name: avg_CounterValue | +// | Labels: | Labels: | Labels: | +// | Type: []*time.Time | Type: []*string | Type: []*float64 | +// +---------------------------------+-----------------+------------------------+ +// | 2020-04-19 19:16:06.5 +0000 UTC | grafana-vm | 1.1 | +// | 2020-04-19 19:16:16.5 +0000 UTC | grafana-vm | 2.2 | +// | 2020-04-19 19:16:26.5 +0000 UTC | grafana-vm | 3.3 | +// +---------------------------------+-----------------+------------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "datetime", + "string", + "real" + ] + } + }, + "fields": [ + { + "name": "TimeGenerated", + "type": "time", + "typeInfo": { + "frame": "time.Time", + "nullable": true + } + }, + { + "name": "Computer", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "avg_CounterValue", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + 1587323766500, + 1587323776500, + 1587323786500 + ], + [ + "grafana-vm", + "grafana-vm", + "grafana-vm" + ], + [ + 1.1, + 2.2, + 3.3 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/loganalytics/10-log-analytics-response-warning.json.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/loganalytics/10-log-analytics-response-warning.json.golden.jsonc new file mode 100644 index 00000000000..0518f9f1554 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/loganalytics/10-log-analytics-response-warning.json.golden.jsonc @@ -0,0 +1,87 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "string", +// "string" +// ] +// }, +// "notices": [ +// { +// "severity": "warning", +// "text": "There were some errors when processing your query. Something went wrong processing your query on the server. Not sure what happened." +// } +// ] +// } +// Name: +// Dimensions: 2 Fields by 1 Rows +// +----------------------------------+-----------------+ +// | Name: OperationName | Name: Level | +// | Labels: | Labels: | +// | Type: []*string | Type: []*string | +// +----------------------------------+-----------------+ +// | Create or Update Virtual Machine | Informational | +// +----------------------------------+-----------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "string", + "string" + ] + }, + "notices": [ + { + "severity": "warning", + "text": "There were some errors when processing your query. Something went wrong processing your query on the server. Not sure what happened." + } + ] + }, + "fields": [ + { + "name": "OperationName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "Level", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + "Create or Update Virtual Machine" + ], + [ + "Informational" + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/loganalytics/11-log-analytics-response-empty.json.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/loganalytics/11-log-analytics-response-empty.json.golden.jsonc new file mode 100644 index 00000000000..e63a03ad551 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/loganalytics/11-log-analytics-response-empty.json.golden.jsonc @@ -0,0 +1,5 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200 +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/loganalytics/6-log-analytics-response-table.json.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/loganalytics/6-log-analytics-response-table.json.golden.jsonc new file mode 100644 index 00000000000..d2b4fd4b607 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/loganalytics/6-log-analytics-response-table.json.golden.jsonc @@ -0,0 +1,201 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "string", +// "string", +// "string", +// "string", +// "string", +// "real", +// "real", +// "int", +// "real", +// "datetime" +// ] +// } +// } +// Name: +// Dimensions: 10 Fields by 3 Rows +// +--------------------------------------+-----------------+------------------+-------------------------+--------------------+------------------+------------------+-------------------+--------------------+-----------------------------------+ +// | Name: TenantId | Name: Computer | Name: ObjectName | Name: CounterName | Name: InstanceName | Name: Min | Name: Max | Name: SampleCount | Name: CounterValue | Name: TimeGenerated | +// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | +// | Type: []*string | Type: []*string | Type: []*string | Type: []*string | Type: []*string | Type: []*float64 | Type: []*float64 | Type: []*int32 | Type: []*float64 | Type: []*time.Time | +// +--------------------------------------+-----------------+------------------+-------------------------+--------------------+------------------+------------------+-------------------+--------------------+-----------------------------------+ +// | a2c1b44e-3e57-4410-b027-6cc0ae6dee67 | grafana-vm | Memory | Available MBytes Memory | Memory | null | null | null | 2040 | 2020-04-23 11:46:03.857 +0000 UTC | +// | a2c1b44e-3e57-4410-b027-6cc0ae6dee67 | grafana-vm | Memory | Available MBytes Memory | Memory | null | null | null | 2066 | 2020-04-23 11:46:13.857 +0000 UTC | +// | a2c1b44e-3e57-4410-b027-6cc0ae6dee67 | grafana-vm | Memory | Available MBytes Memory | Memory | null | null | null | 2066 | 2020-04-23 11:46:23.857 +0000 UTC | +// +--------------------------------------+-----------------+------------------+-------------------------+--------------------+------------------+------------------+-------------------+--------------------+-----------------------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "string", + "string", + "string", + "string", + "string", + "real", + "real", + "int", + "real", + "datetime" + ] + } + }, + "fields": [ + { + "name": "TenantId", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "Computer", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "ObjectName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "CounterName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "InstanceName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "Min", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "Max", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "SampleCount", + "type": "number", + "typeInfo": { + "frame": "int32", + "nullable": true + } + }, + { + "name": "CounterValue", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "TimeGenerated", + "type": "time", + "typeInfo": { + "frame": "time.Time", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + "a2c1b44e-3e57-4410-b027-6cc0ae6dee67", + "a2c1b44e-3e57-4410-b027-6cc0ae6dee67", + "a2c1b44e-3e57-4410-b027-6cc0ae6dee67" + ], + [ + "grafana-vm", + "grafana-vm", + "grafana-vm" + ], + [ + "Memory", + "Memory", + "Memory" + ], + [ + "Available MBytes Memory", + "Available MBytes Memory", + "Available MBytes Memory" + ], + [ + "Memory", + "Memory", + "Memory" + ], + [ + null, + null, + null + ], + [ + null, + null, + null + ], + [ + null, + null, + null + ], + [ + 2040, + 2066, + 2066 + ], + [ + 1587642363857, + 1587642373857, + 1587642383857 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/loganalytics/7-log-analytics-all-types-table.json.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/loganalytics/7-log-analytics-all-types-table.json.golden.jsonc new file mode 100644 index 00000000000..8894e6c3a28 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/loganalytics/7-log-analytics-all-types-table.json.golden.jsonc @@ -0,0 +1,205 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "bool", +// "string", +// "datetime", +// "dynamic", +// "guid", +// "int", +// "long", +// "real", +// "timespan", +// "decimal", +// "object", +// "number" +// ] +// } +// } +// Name: +// Dimensions: 12 Fields by 1 Rows +// +---------------+-----------------+---------------------------------+---------------------------------------------------------------+--------------------------------------+----------------+---------------------+-------------------------+------------------+-----------------------+--------------------------------------------------------------------------+-----------------------+ +// | Name: XBool | Name: XString | Name: XDateTime | Name: XDynamic | Name: XGuid | Name: XInt | Name: XLong | Name: XReal | Name: XTimeSpan | Name: XDecimal | Name: XObject | Name: XNumber | +// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | +// | Type: []*bool | Type: []*string | Type: []*time.Time | Type: []*string | Type: []*string | Type: []*int32 | Type: []*int64 | Type: []*float64 | Type: []*string | Type: []*float64 | Type: []*string | Type: []*float64 | +// +---------------+-----------------+---------------------------------+---------------------------------------------------------------+--------------------------------------+----------------+---------------------+-------------------------+------------------+-----------------------+--------------------------------------------------------------------------+-----------------------+ +// | true | Grafana | 2006-01-02 22:04:05.1 +0000 UTC | [{"person":"Daniel"},{"cats":23},{"diagnosis":"cat problem"}] | 74be27de-1e4e-49d9-b579-fe0b331d3642 | 2147483647 | 9223372036854775807 | 1.7976931348623157e+308 | 00:00:00.0000001 | 7.922816251426434e+28 | "{\"person\": \"Daniel\", \"cats\": 23, \"diagnosis\": \"cat problem\"}" | 7.922816251426434e+28 | +// +---------------+-----------------+---------------------------------+---------------------------------------------------------------+--------------------------------------+----------------+---------------------+-------------------------+------------------+-----------------------+--------------------------------------------------------------------------+-----------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "bool", + "string", + "datetime", + "dynamic", + "guid", + "int", + "long", + "real", + "timespan", + "decimal", + "object", + "number" + ] + } + }, + "fields": [ + { + "name": "XBool", + "type": "boolean", + "typeInfo": { + "frame": "bool", + "nullable": true + } + }, + { + "name": "XString", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "XDateTime", + "type": "time", + "typeInfo": { + "frame": "time.Time", + "nullable": true + } + }, + { + "name": "XDynamic", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "XGuid", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "XInt", + "type": "number", + "typeInfo": { + "frame": "int32", + "nullable": true + } + }, + { + "name": "XLong", + "type": "number", + "typeInfo": { + "frame": "int64", + "nullable": true + } + }, + { + "name": "XReal", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "XTimeSpan", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "XDecimal", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "XObject", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "XNumber", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + true + ], + [ + "Grafana" + ], + [ + 1136239445100 + ], + [ + "[{\"person\":\"Daniel\"},{\"cats\":23},{\"diagnosis\":\"cat problem\"}]" + ], + [ + "74be27de-1e4e-49d9-b579-fe0b331d3642" + ], + [ + 2147483647 + ], + [ + 9223372036854775807 + ], + [ + 1.7976931348623157e+308 + ], + [ + "00:00:00.0000001" + ], + [ + 7.922816251426434e+28 + ], + [ + "\"{\\\"person\\\": \\\"Daniel\\\", \\\"cats\\\": 23, \\\"diagnosis\\\": \\\"cat problem\\\"}\"" + ], + [ + 7.922816251426434e+28 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/loganalytics/8-log-analytics-response-nan-inf.json.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/loganalytics/8-log-analytics-response-nan-inf.json.golden.jsonc new file mode 100644 index 00000000000..eb9ffd62185 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/loganalytics/8-log-analytics-response-nan-inf.json.golden.jsonc @@ -0,0 +1,105 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "real", +// "real", +// "real" +// ] +// } +// } +// Name: +// Dimensions: 3 Fields by 1 Rows +// +------------------+------------------+------------------+ +// | Name: XInf | Name: XInfNeg | Name: XNan | +// | Labels: | Labels: | Labels: | +// | Type: []*float64 | Type: []*float64 | Type: []*float64 | +// +------------------+------------------+------------------+ +// | +Inf | -Inf | NaN | +// +------------------+------------------+------------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "real", + "real", + "real" + ] + } + }, + "fields": [ + { + "name": "XInf", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "XInfNeg", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "XNan", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + null + ], + [ + null + ], + [ + null + ] + ], + "entities": [ + { + "Inf": [ + 0 + ] + }, + { + "NegInf": [ + 0 + ] + }, + { + "NaN": [ + 0 + ] + } + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/loganalytics/9-log-analytics-response-error.json.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/loganalytics/9-log-analytics-response-error.json.golden.jsonc new file mode 100644 index 00000000000..adf3cdd8809 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/loganalytics/9-log-analytics-response-error.json.golden.jsonc @@ -0,0 +1,87 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "string", +// "string" +// ] +// }, +// "notices": [ +// { +// "severity": "error", +// "text": "There were some errors when processing your query. Something went wrong processing your query on the server. The results of this query exceed the set limit of 1 records." +// } +// ] +// } +// Name: +// Dimensions: 2 Fields by 1 Rows +// +----------------------------------+-----------------+ +// | Name: OperationName | Name: Level | +// | Labels: | Labels: | +// | Type: []*string | Type: []*string | +// +----------------------------------+-----------------+ +// | Create or Update Virtual Machine | Informational | +// +----------------------------------+-----------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "string", + "string" + ] + }, + "notices": [ + { + "severity": "error", + "text": "There were some errors when processing your query. Something went wrong processing your query on the server. The results of this query exceed the set limit of 1 records." + } + ] + }, + "fields": [ + { + "name": "OperationName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "Level", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + "Create or Update Virtual Machine" + ], + [ + "Informational" + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json b/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json new file mode 100644 index 00000000000..57a40e59f27 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json @@ -0,0 +1,94 @@ +{ + "tables": [ + { + "name": "PrimaryResult", + "columns": [ + { + "name": "traceID", + "type": "string" + }, + { + "name": "spanID", + "type": "string" + }, + { + "name": "parentSpanID", + "type": "string" + }, + { + "name": "duration", + "type": "real" + }, + { + "name": "serviceName", + "type": "string" + }, + { + "name": "operationName", + "type": "string" + }, + { + "name": "startTime", + "type": "datetime" + }, + { + "name": "serviceTags", + "type": "dynamic" + }, + { + "name": "tags", + "type": "dynamic" + }, + { + "name": "itemId", + "type": "string" + }, + { + "name": "itemType", + "type": "string" + } + ], + "rows": [ + [ + "cfae497bfd7a44169f35643940820938", + "b52403c5-5b27-43a8-9bc6-5938667a4470", + "|cfae497bfd7a44169f35643940820938.", + 0, + "", + "GET /github/grafana/grafana/commits", + "2023-04-17T14:58:10.176Z", + "{\"service\":\"github-test-data\",\"limit\":\"5000\",\"remaining\":\"4351\",\"reset\":\"1681746512\",\"used\":\"649\",\"timestamp\":\"2023-04-17T14:58:10.0000000Z\"}", + "{\"client_IP\":\"0.0.0.0\",\"operation_Id\":\"cfae497bfd7a44169f35643940820938\",\"duration\":0,\"iKey\":\"195b4fe4-7b01-4814-abca-ffceb1f62c8f\",\"size\":null,\"sdkVersion\":\"node:1.8.9\",\"name\":\"\",\"client_Model\":\"\",\"cloud_RoleName\":\"Web\",\"customMeasurements\":null,\"client_Browser\":\"\",\"operation_Name\":\"GET /github/grafana/grafana/commits\",\"performanceBucket\":\"\",\"client_CountryOrRegion\":\"Ireland\",\"cloud_RoleInstance\":\"test-vm\",\"appName\":\"test-app\",\"client_Type\":\"PC\",\"operation_ParentId\":\"|cfae497bfd7a44169f35643940820938.\",\"success\":\"\",\"application_Version\":\"1.0.0\",\"operation_SyntheticSource\":\"\",\"itemType\":\"trace\",\"user_AccountId\":\"\",\"session_Id\":\"\",\"timestamp\":\"2023-04-17T14:58:10.1760000Z\",\"message\":\"github commits rate limiting info\",\"client_City\":\"Dublin\",\"client_StateOrProvince\":\"Dublin\",\"itemId\":\"65863e6b-dd30-11ed-a808-002248268105\",\"client_OS\":\"Linux 5.4.0-1036-azure\",\"id\":\"\",\"customDimensions\":{\"service\":\"github-test-data\",\"limit\":\"5000\",\"remaining\":\"4351\",\"reset\":\"1681746512\",\"used\":\"649\",\"timestamp\":\"2023-04-17T14:58:10.0000000Z\"},\"itemCount\":1,\"location\":\"\",\"user_AuthenticatedId\":\"\",\"appId\":\"4ad5a808-11f7-49d5-9713-f6ede83141e4\",\"user_Id\":\"\",\"resultCode\":\"\",\"type\":\"\",\"data\":\"\",\"target\":\"\",\"assembly\":\"\",\"outerType\":\"\",\"innermostAssembly\":\"\",\"innermostType\":\"\",\"method\":\"\",\"problemId\":\"\",\"handledAt\":\"\",\"outerMessage\":\"\",\"details\":null,\"innermostMethod\":\"\",\"innermostMessage\":\"\",\"outerAssembly\":\"\",\"outerMethod\":\"\",\"severityLevel\":1,\"url\":\"\",\"source\":\"\"}", + "65863e6b-dd30-11ed-a808-002248268105", + "trace" + ], + [ + "e766f18a0adc49418d297b1a244f1bfb", + "|e766f18a0adc49418d297b1a244f1bfb.1901.", + "|e766f18a0adc49418d297b1a244f1bfb.", + 330, + "GET /repos/grafana/grafana/commits", + "GET /github/grafana/grafana/commits", + "2023-04-17T14:58:10.764Z", + null, + "{\"client_IP\":\"0.0.0.0\",\"operation_Id\":\"e766f18a0adc49418d297b1a244f1bfb\",\"duration\":330,\"iKey\":\"195b4fe4-7b01-4814-abca-ffceb1f62c8f\",\"size\":null,\"sdkVersion\":\"node:1.8.9\",\"name\":\"GET /repos/grafana/grafana/commits\",\"client_Model\":\"\",\"cloud_RoleName\":\"Web\",\"customMeasurements\":null,\"client_Browser\":\"\",\"operation_Name\":\"GET /github/grafana/grafana/commits\",\"performanceBucket\":\"250ms-500ms\",\"client_CountryOrRegion\":\"Ireland\",\"cloud_RoleInstance\":\"test-vm\",\"appName\":\"test-app\",\"client_Type\":\"PC\",\"operation_ParentId\":\"|e766f18a0adc49418d297b1a244f1bfb.\",\"success\":\"True\",\"application_Version\":\"1.0.0\",\"operation_SyntheticSource\":\"\",\"itemType\":\"dependency\",\"user_AccountId\":\"\",\"session_Id\":\"\",\"timestamp\":\"2023-04-17T14:58:10.7640000Z\",\"message\":\"\",\"client_City\":\"Dublin\",\"client_StateOrProvince\":\"Dublin\",\"itemId\":\"78c1bcf4-dd30-11ed-a808-0022481f7f28\",\"client_OS\":\"Linux 5.4.0-1036-azure\",\"id\":\"|e766f18a0adc49418d297b1a244f1bfb.1901.\",\"customDimensions\":null,\"itemCount\":1,\"location\":\"\",\"user_AuthenticatedId\":\"\",\"appId\":\"4ad5a808-11f7-49d5-9713-f6ede83141e4\",\"user_Id\":\"\",\"resultCode\":\"200\",\"type\":\"HTTP\",\"data\":\"https://api.github.com/repos/grafana/grafana/commits\",\"target\":\"api.github.com\",\"assembly\":\"\",\"outerType\":\"\",\"innermostAssembly\":\"\",\"innermostType\":\"\",\"method\":\"\",\"problemId\":\"\",\"handledAt\":\"\",\"outerMessage\":\"\",\"details\":null,\"innermostMethod\":\"\",\"innermostMessage\":\"\",\"outerAssembly\":\"\",\"outerMethod\":\"\",\"severityLevel\":null,\"url\":\"\",\"source\":\"\"}", + "78c1bcf4-dd30-11ed-a808-0022481f7f28", + "dependency" + ], + [ + "b1f0047386554fa59b7c5330560a0799", + "|b1f0047386554fa59b7c5330560a0799.", + "b1f0047386554fa59b7c5330560a0799", + 352, + "GET /github/grafana/grafana/commits", + "GET /github/grafana/grafana/commits", + "2023-04-17T14:58:11.579Z", + null, + "{\"client_IP\":\"0.0.0.0\",\"operation_Id\":\"b1f0047386554fa59b7c5330560a0799\",\"duration\":352,\"iKey\":\"195b4fe4-7b01-4814-abca-ffceb1f62c8f\",\"size\":null,\"sdkVersion\":\"node:1.8.9\",\"name\":\"GET /github/grafana/grafana/commits\",\"client_Model\":\"\",\"cloud_RoleName\":\"Web\",\"customMeasurements\":null,\"client_Browser\":\"\",\"operation_Name\":\"GET /github/grafana/grafana/commits\",\"performanceBucket\":\"250ms-500ms\",\"client_CountryOrRegion\":\"\",\"cloud_RoleInstance\":\"test-vm\",\"appName\":\"test-app\",\"client_Type\":\"PC\",\"operation_ParentId\":\"b1f0047386554fa59b7c5330560a0799\",\"success\":\"True\",\"application_Version\":\"1.0.0\",\"operation_SyntheticSource\":\"\",\"itemType\":\"request\",\"user_AccountId\":\"\",\"session_Id\":\"\",\"timestamp\":\"2023-04-17T14:58:11.5790000Z\",\"message\":\"\",\"client_City\":\"\",\"client_StateOrProvince\":\"\",\"itemId\":\"5c126241-dd30-11ed-a80a-00224826882d\",\"client_OS\":\"Linux 5.4.0-1036-azure\",\"id\":\"|b1f0047386554fa59b7c5330560a0799.\",\"customDimensions\":null,\"itemCount\":1,\"location\":\"\",\"user_AuthenticatedId\":\"\",\"appId\":\"4ad5a808-11f7-49d5-9713-f6ede83141e4\",\"user_Id\":\"\",\"resultCode\":\"200\",\"type\":\"\",\"data\":\"\",\"target\":\"\",\"assembly\":\"\",\"outerType\":\"\",\"innermostAssembly\":\"\",\"innermostType\":\"\",\"method\":\"\",\"problemId\":\"\",\"handledAt\":\"\",\"outerMessage\":\"\",\"details\":null,\"innermostMethod\":\"\",\"innermostMessage\":\"\",\"outerAssembly\":\"\",\"outerMethod\":\"\",\"severityLevel\":null,\"url\":\"test-url\",\"source\":\"\"}", + "5c126241-dd30-11ed-a80a-00224826882d", + "request" + ] + ] + } + ] +} diff --git a/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json.multi-trace-as-trace-format.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json.multi-trace-as-trace-format.golden.jsonc new file mode 100644 index 00000000000..5cb334595cc --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json.multi-trace-as-trace-format.golden.jsonc @@ -0,0 +1,559 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "string", +// "string", +// "string", +// "real", +// "string", +// "string", +// "datetime", +// "dynamic", +// "dynamic", +// "string", +// "string" +// ] +// } +// } +// Name: +// Dimensions: 11 Fields by 3 Rows +// +----------------------------------+-----------------------------------------+------------------------------------+------------------+-------------------------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// | Name: traceID | Name: spanID | Name: parentSpanID | Name: duration | Name: serviceName | Name: operationName | Name: startTime | Name: serviceTags | Name: tags | Name: itemId | Name: itemType | +// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | +// | Type: []*string | Type: []*string | Type: []*string | Type: []*float64 | Type: []*string | Type: []*string | Type: []*time.Time | Type: []*json.RawMessage | Type: []*json.RawMessage | Type: []*string | Type: []*string | +// +----------------------------------+-----------------------------------------+------------------------------------+------------------+-------------------------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// | cfae497bfd7a44169f35643940820938 | b52403c5-5b27-43a8-9bc6-5938667a4470 | |cfae497bfd7a44169f35643940820938. | 0 | | GET /github/grafana/grafana/commits | 2023-04-17 14:58:10.176 +0000 UTC | [{"value":"5000","key":"limit"},{"value":"4351","key":"remaining"},{"value":"1681746512","key":"reset"},{"value":"github-test-data","key":"service"},{"value":"2023-04-17T14:58:10.0000000Z","key":"timestamp"},{"value":"649","key":"used"}] | [{"value":"4ad5a808-11f7-49d5-9713-f6ede83141e4","key":"appId"},{"value":"test-app","key":"appName"},{"value":"1.0.0","key":"application_Version"},{"value":"Dublin","key":"client_City"},{"value":"Ireland","key":"client_CountryOrRegion"},{"value":"0.0.0.0","key":"client_IP"},{"value":"Linux 5.4.0-1036-azure","key":"client_OS"},{"value":"Dublin","key":"client_StateOrProvince"},{"value":"PC","key":"client_Type"},{"value":"test-vm","key":"cloud_RoleInstance"},{"value":"Web","key":"cloud_RoleName"},{"value":{"limit":"5000","remaining":"4351","reset":"1681746512","service":"github-test-data","timestamp":"2023-04-17T14:58:10.0000000Z","used":"649"},"key":"customDimensions"},{"value":0,"key":"duration"},{"value":"195b4fe4-7b01-4814-abca-ffceb1f62c8f","key":"iKey"},{"value":1,"key":"itemCount"},{"value":"65863e6b-dd30-11ed-a808-002248268105","key":"itemId"},{"value":"trace","key":"itemType"},{"value":"github commits rate limiting info","key":"message"},{"value":"cfae497bfd7a44169f35643940820938","key":"operation_Id"},{"value":"GET /github/grafana/grafana/commits","key":"operation_Name"},{"value":"|cfae497bfd7a44169f35643940820938.","key":"operation_ParentId"},{"value":"node:1.8.9","key":"sdkVersion"},{"value":1,"key":"severityLevel"},{"value":"2023-04-17T14:58:10.1760000Z","key":"timestamp"}] | 65863e6b-dd30-11ed-a808-002248268105 | trace | +// | e766f18a0adc49418d297b1a244f1bfb | |e766f18a0adc49418d297b1a244f1bfb.1901. | |e766f18a0adc49418d297b1a244f1bfb. | 330 | GET /repos/grafana/grafana/commits | GET /github/grafana/grafana/commits | 2023-04-17 14:58:10.764 +0000 UTC | null | [{"value":"4ad5a808-11f7-49d5-9713-f6ede83141e4","key":"appId"},{"value":"test-app","key":"appName"},{"value":"1.0.0","key":"application_Version"},{"value":"Dublin","key":"client_City"},{"value":"Ireland","key":"client_CountryOrRegion"},{"value":"0.0.0.0","key":"client_IP"},{"value":"Linux 5.4.0-1036-azure","key":"client_OS"},{"value":"Dublin","key":"client_StateOrProvince"},{"value":"PC","key":"client_Type"},{"value":"test-vm","key":"cloud_RoleInstance"},{"value":"Web","key":"cloud_RoleName"},{"value":"https://api.github.com/repos/grafana/grafana/commits","key":"data"},{"value":330,"key":"duration"},{"value":"195b4fe4-7b01-4814-abca-ffceb1f62c8f","key":"iKey"},{"value":"|e766f18a0adc49418d297b1a244f1bfb.1901.","key":"id"},{"value":1,"key":"itemCount"},{"value":"78c1bcf4-dd30-11ed-a808-0022481f7f28","key":"itemId"},{"value":"dependency","key":"itemType"},{"value":"GET /repos/grafana/grafana/commits","key":"name"},{"value":"e766f18a0adc49418d297b1a244f1bfb","key":"operation_Id"},{"value":"GET /github/grafana/grafana/commits","key":"operation_Name"},{"value":"|e766f18a0adc49418d297b1a244f1bfb.","key":"operation_ParentId"},{"value":"250ms-500ms","key":"performanceBucket"},{"value":"200","key":"resultCode"},{"value":"node:1.8.9","key":"sdkVersion"},{"value":"True","key":"success"},{"value":"api.github.com","key":"target"},{"value":"2023-04-17T14:58:10.7640000Z","key":"timestamp"},{"value":"HTTP","key":"type"}] | 78c1bcf4-dd30-11ed-a808-0022481f7f28 | dependency | +// | b1f0047386554fa59b7c5330560a0799 | |b1f0047386554fa59b7c5330560a0799. | b1f0047386554fa59b7c5330560a0799 | 352 | GET /github/grafana/grafana/commits | GET /github/grafana/grafana/commits | 2023-04-17 14:58:11.579 +0000 UTC | null | [{"value":"4ad5a808-11f7-49d5-9713-f6ede83141e4","key":"appId"},{"value":"test-app","key":"appName"},{"value":"1.0.0","key":"application_Version"},{"value":"0.0.0.0","key":"client_IP"},{"value":"Linux 5.4.0-1036-azure","key":"client_OS"},{"value":"PC","key":"client_Type"},{"value":"test-vm","key":"cloud_RoleInstance"},{"value":"Web","key":"cloud_RoleName"},{"value":352,"key":"duration"},{"value":"195b4fe4-7b01-4814-abca-ffceb1f62c8f","key":"iKey"},{"value":"|b1f0047386554fa59b7c5330560a0799.","key":"id"},{"value":1,"key":"itemCount"},{"value":"5c126241-dd30-11ed-a80a-00224826882d","key":"itemId"},{"value":"request","key":"itemType"},{"value":"GET /github/grafana/grafana/commits","key":"name"},{"value":"b1f0047386554fa59b7c5330560a0799","key":"operation_Id"},{"value":"GET /github/grafana/grafana/commits","key":"operation_Name"},{"value":"b1f0047386554fa59b7c5330560a0799","key":"operation_ParentId"},{"value":"250ms-500ms","key":"performanceBucket"},{"value":"200","key":"resultCode"},{"value":"node:1.8.9","key":"sdkVersion"},{"value":"True","key":"success"},{"value":"2023-04-17T14:58:11.5790000Z","key":"timestamp"},{"value":"test-url","key":"url"}] | 5c126241-dd30-11ed-a80a-00224826882d | request | +// +----------------------------------+-----------------------------------------+------------------------------------+------------------+-------------------------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "string", + "string", + "string", + "real", + "string", + "string", + "datetime", + "dynamic", + "dynamic", + "string", + "string" + ] + } + }, + "fields": [ + { + "name": "traceID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "spanID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "parentSpanID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "duration", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "serviceName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "operationName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "startTime", + "type": "time", + "typeInfo": { + "frame": "time.Time", + "nullable": true + } + }, + { + "name": "serviceTags", + "type": "other", + "typeInfo": { + "frame": "json.RawMessage", + "nullable": true + } + }, + { + "name": "tags", + "type": "other", + "typeInfo": { + "frame": "json.RawMessage", + "nullable": true + } + }, + { + "name": "itemId", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "itemType", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + "cfae497bfd7a44169f35643940820938", + "e766f18a0adc49418d297b1a244f1bfb", + "b1f0047386554fa59b7c5330560a0799" + ], + [ + "b52403c5-5b27-43a8-9bc6-5938667a4470", + "|e766f18a0adc49418d297b1a244f1bfb.1901.", + "|b1f0047386554fa59b7c5330560a0799." + ], + [ + "|cfae497bfd7a44169f35643940820938.", + "|e766f18a0adc49418d297b1a244f1bfb.", + "b1f0047386554fa59b7c5330560a0799" + ], + [ + 0, + 330, + 352 + ], + [ + "", + "GET /repos/grafana/grafana/commits", + "GET /github/grafana/grafana/commits" + ], + [ + "GET /github/grafana/grafana/commits", + "GET /github/grafana/grafana/commits", + "GET /github/grafana/grafana/commits" + ], + [ + 1681743490176, + 1681743490764, + 1681743491579 + ], + [ + [ + { + "value": "5000", + "key": "limit" + }, + { + "value": "4351", + "key": "remaining" + }, + { + "value": "1681746512", + "key": "reset" + }, + { + "value": "github-test-data", + "key": "service" + }, + { + "value": "2023-04-17T14:58:10.0000000Z", + "key": "timestamp" + }, + { + "value": "649", + "key": "used" + } + ], + null, + null + ], + [ + [ + { + "value": "4ad5a808-11f7-49d5-9713-f6ede83141e4", + "key": "appId" + }, + { + "value": "test-app", + "key": "appName" + }, + { + "value": "1.0.0", + "key": "application_Version" + }, + { + "value": "Dublin", + "key": "client_City" + }, + { + "value": "Ireland", + "key": "client_CountryOrRegion" + }, + { + "value": "0.0.0.0", + "key": "client_IP" + }, + { + "value": "Linux 5.4.0-1036-azure", + "key": "client_OS" + }, + { + "value": "Dublin", + "key": "client_StateOrProvince" + }, + { + "value": "PC", + "key": "client_Type" + }, + { + "value": "test-vm", + "key": "cloud_RoleInstance" + }, + { + "value": "Web", + "key": "cloud_RoleName" + }, + { + "value": { + "limit": "5000", + "remaining": "4351", + "reset": "1681746512", + "service": "github-test-data", + "timestamp": "2023-04-17T14:58:10.0000000Z", + "used": "649" + }, + "key": "customDimensions" + }, + { + "value": 0, + "key": "duration" + }, + { + "value": "195b4fe4-7b01-4814-abca-ffceb1f62c8f", + "key": "iKey" + }, + { + "value": 1, + "key": "itemCount" + }, + { + "value": "65863e6b-dd30-11ed-a808-002248268105", + "key": "itemId" + }, + { + "value": "trace", + "key": "itemType" + }, + { + "value": "github commits rate limiting info", + "key": "message" + }, + { + "value": "cfae497bfd7a44169f35643940820938", + "key": "operation_Id" + }, + { + "value": "GET /github/grafana/grafana/commits", + "key": "operation_Name" + }, + { + "value": "|cfae497bfd7a44169f35643940820938.", + "key": "operation_ParentId" + }, + { + "value": "node:1.8.9", + "key": "sdkVersion" + }, + { + "value": 1, + "key": "severityLevel" + }, + { + "value": "2023-04-17T14:58:10.1760000Z", + "key": "timestamp" + } + ], + [ + { + "value": "4ad5a808-11f7-49d5-9713-f6ede83141e4", + "key": "appId" + }, + { + "value": "test-app", + "key": "appName" + }, + { + "value": "1.0.0", + "key": "application_Version" + }, + { + "value": "Dublin", + "key": "client_City" + }, + { + "value": "Ireland", + "key": "client_CountryOrRegion" + }, + { + "value": "0.0.0.0", + "key": "client_IP" + }, + { + "value": "Linux 5.4.0-1036-azure", + "key": "client_OS" + }, + { + "value": "Dublin", + "key": "client_StateOrProvince" + }, + { + "value": "PC", + "key": "client_Type" + }, + { + "value": "test-vm", + "key": "cloud_RoleInstance" + }, + { + "value": "Web", + "key": "cloud_RoleName" + }, + { + "value": "https://api.github.com/repos/grafana/grafana/commits", + "key": "data" + }, + { + "value": 330, + "key": "duration" + }, + { + "value": "195b4fe4-7b01-4814-abca-ffceb1f62c8f", + "key": "iKey" + }, + { + "value": "|e766f18a0adc49418d297b1a244f1bfb.1901.", + "key": "id" + }, + { + "value": 1, + "key": "itemCount" + }, + { + "value": "78c1bcf4-dd30-11ed-a808-0022481f7f28", + "key": "itemId" + }, + { + "value": "dependency", + "key": "itemType" + }, + { + "value": "GET /repos/grafana/grafana/commits", + "key": "name" + }, + { + "value": "e766f18a0adc49418d297b1a244f1bfb", + "key": "operation_Id" + }, + { + "value": "GET /github/grafana/grafana/commits", + "key": "operation_Name" + }, + { + "value": "|e766f18a0adc49418d297b1a244f1bfb.", + "key": "operation_ParentId" + }, + { + "value": "250ms-500ms", + "key": "performanceBucket" + }, + { + "value": "200", + "key": "resultCode" + }, + { + "value": "node:1.8.9", + "key": "sdkVersion" + }, + { + "value": "True", + "key": "success" + }, + { + "value": "api.github.com", + "key": "target" + }, + { + "value": "2023-04-17T14:58:10.7640000Z", + "key": "timestamp" + }, + { + "value": "HTTP", + "key": "type" + } + ], + [ + { + "value": "4ad5a808-11f7-49d5-9713-f6ede83141e4", + "key": "appId" + }, + { + "value": "test-app", + "key": "appName" + }, + { + "value": "1.0.0", + "key": "application_Version" + }, + { + "value": "0.0.0.0", + "key": "client_IP" + }, + { + "value": "Linux 5.4.0-1036-azure", + "key": "client_OS" + }, + { + "value": "PC", + "key": "client_Type" + }, + { + "value": "test-vm", + "key": "cloud_RoleInstance" + }, + { + "value": "Web", + "key": "cloud_RoleName" + }, + { + "value": 352, + "key": "duration" + }, + { + "value": "195b4fe4-7b01-4814-abca-ffceb1f62c8f", + "key": "iKey" + }, + { + "value": "|b1f0047386554fa59b7c5330560a0799.", + "key": "id" + }, + { + "value": 1, + "key": "itemCount" + }, + { + "value": "5c126241-dd30-11ed-a80a-00224826882d", + "key": "itemId" + }, + { + "value": "request", + "key": "itemType" + }, + { + "value": "GET /github/grafana/grafana/commits", + "key": "name" + }, + { + "value": "b1f0047386554fa59b7c5330560a0799", + "key": "operation_Id" + }, + { + "value": "GET /github/grafana/grafana/commits", + "key": "operation_Name" + }, + { + "value": "b1f0047386554fa59b7c5330560a0799", + "key": "operation_ParentId" + }, + { + "value": "250ms-500ms", + "key": "performanceBucket" + }, + { + "value": "200", + "key": "resultCode" + }, + { + "value": "node:1.8.9", + "key": "sdkVersion" + }, + { + "value": "True", + "key": "success" + }, + { + "value": "2023-04-17T14:58:11.5790000Z", + "key": "timestamp" + }, + { + "value": "test-url", + "key": "url" + } + ] + ], + [ + "65863e6b-dd30-11ed-a808-002248268105", + "78c1bcf4-dd30-11ed-a808-0022481f7f28", + "5c126241-dd30-11ed-a80a-00224826882d" + ], + [ + "trace", + "dependency", + "request" + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json.multi-trace.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json.multi-trace.golden.jsonc new file mode 100644 index 00000000000..d5225934962 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/traces/1-traces-multiple-table.json.multi-trace.golden.jsonc @@ -0,0 +1,216 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "string", +// "string", +// "string", +// "real", +// "string", +// "string", +// "datetime", +// "dynamic", +// "dynamic", +// "string", +// "string" +// ] +// } +// } +// Name: +// Dimensions: 11 Fields by 3 Rows +// +----------------------------------+-----------------------------------------+------------------------------------+------------------+-------------------------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// | Name: traceID | Name: spanID | Name: parentSpanID | Name: duration | Name: serviceName | Name: operationName | Name: startTime | Name: serviceTags | Name: tags | Name: itemId | Name: itemType | +// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | +// | Type: []*string | Type: []*string | Type: []*string | Type: []*float64 | Type: []*string | Type: []*string | Type: []*time.Time | Type: []*string | Type: []*string | Type: []*string | Type: []*string | +// +----------------------------------+-----------------------------------------+------------------------------------+------------------+-------------------------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// | cfae497bfd7a44169f35643940820938 | b52403c5-5b27-43a8-9bc6-5938667a4470 | |cfae497bfd7a44169f35643940820938. | 0 | | GET /github/grafana/grafana/commits | 2023-04-17 14:58:10.176 +0000 UTC | {"service":"github-test-data","limit":"5000","remaining":"4351","reset":"1681746512","used":"649","timestamp":"2023-04-17T14:58:10.0000000Z"} | {"client_IP":"0.0.0.0","operation_Id":"cfae497bfd7a44169f35643940820938","duration":0,"iKey":"195b4fe4-7b01-4814-abca-ffceb1f62c8f","size":null,"sdkVersion":"node:1.8.9","name":"","client_Model":"","cloud_RoleName":"Web","customMeasurements":null,"client_Browser":"","operation_Name":"GET /github/grafana/grafana/commits","performanceBucket":"","client_CountryOrRegion":"Ireland","cloud_RoleInstance":"test-vm","appName":"test-app","client_Type":"PC","operation_ParentId":"|cfae497bfd7a44169f35643940820938.","success":"","application_Version":"1.0.0","operation_SyntheticSource":"","itemType":"trace","user_AccountId":"","session_Id":"","timestamp":"2023-04-17T14:58:10.1760000Z","message":"github commits rate limiting info","client_City":"Dublin","client_StateOrProvince":"Dublin","itemId":"65863e6b-dd30-11ed-a808-002248268105","client_OS":"Linux 5.4.0-1036-azure","id":"","customDimensions":{"service":"github-test-data","limit":"5000","remaining":"4351","reset":"1681746512","used":"649","timestamp":"2023-04-17T14:58:10.0000000Z"},"itemCount":1,"location":"","user_AuthenticatedId":"","appId":"4ad5a808-11f7-49d5-9713-f6ede83141e4","user_Id":"","resultCode":"","type":"","data":"","target":"","assembly":"","outerType":"","innermostAssembly":"","innermostType":"","method":"","problemId":"","handledAt":"","outerMessage":"","details":null,"innermostMethod":"","innermostMessage":"","outerAssembly":"","outerMethod":"","severityLevel":1,"url":"","source":""} | 65863e6b-dd30-11ed-a808-002248268105 | trace | +// | e766f18a0adc49418d297b1a244f1bfb | |e766f18a0adc49418d297b1a244f1bfb.1901. | |e766f18a0adc49418d297b1a244f1bfb. | 330 | GET /repos/grafana/grafana/commits | GET /github/grafana/grafana/commits | 2023-04-17 14:58:10.764 +0000 UTC | null | {"client_IP":"0.0.0.0","operation_Id":"e766f18a0adc49418d297b1a244f1bfb","duration":330,"iKey":"195b4fe4-7b01-4814-abca-ffceb1f62c8f","size":null,"sdkVersion":"node:1.8.9","name":"GET /repos/grafana/grafana/commits","client_Model":"","cloud_RoleName":"Web","customMeasurements":null,"client_Browser":"","operation_Name":"GET /github/grafana/grafana/commits","performanceBucket":"250ms-500ms","client_CountryOrRegion":"Ireland","cloud_RoleInstance":"test-vm","appName":"test-app","client_Type":"PC","operation_ParentId":"|e766f18a0adc49418d297b1a244f1bfb.","success":"True","application_Version":"1.0.0","operation_SyntheticSource":"","itemType":"dependency","user_AccountId":"","session_Id":"","timestamp":"2023-04-17T14:58:10.7640000Z","message":"","client_City":"Dublin","client_StateOrProvince":"Dublin","itemId":"78c1bcf4-dd30-11ed-a808-0022481f7f28","client_OS":"Linux 5.4.0-1036-azure","id":"|e766f18a0adc49418d297b1a244f1bfb.1901.","customDimensions":null,"itemCount":1,"location":"","user_AuthenticatedId":"","appId":"4ad5a808-11f7-49d5-9713-f6ede83141e4","user_Id":"","resultCode":"200","type":"HTTP","data":"https://api.github.com/repos/grafana/grafana/commits","target":"api.github.com","assembly":"","outerType":"","innermostAssembly":"","innermostType":"","method":"","problemId":"","handledAt":"","outerMessage":"","details":null,"innermostMethod":"","innermostMessage":"","outerAssembly":"","outerMethod":"","severityLevel":null,"url":"","source":""} | 78c1bcf4-dd30-11ed-a808-0022481f7f28 | dependency | +// | b1f0047386554fa59b7c5330560a0799 | |b1f0047386554fa59b7c5330560a0799. | b1f0047386554fa59b7c5330560a0799 | 352 | GET /github/grafana/grafana/commits | GET /github/grafana/grafana/commits | 2023-04-17 14:58:11.579 +0000 UTC | null | {"client_IP":"0.0.0.0","operation_Id":"b1f0047386554fa59b7c5330560a0799","duration":352,"iKey":"195b4fe4-7b01-4814-abca-ffceb1f62c8f","size":null,"sdkVersion":"node:1.8.9","name":"GET /github/grafana/grafana/commits","client_Model":"","cloud_RoleName":"Web","customMeasurements":null,"client_Browser":"","operation_Name":"GET /github/grafana/grafana/commits","performanceBucket":"250ms-500ms","client_CountryOrRegion":"","cloud_RoleInstance":"test-vm","appName":"test-app","client_Type":"PC","operation_ParentId":"b1f0047386554fa59b7c5330560a0799","success":"True","application_Version":"1.0.0","operation_SyntheticSource":"","itemType":"request","user_AccountId":"","session_Id":"","timestamp":"2023-04-17T14:58:11.5790000Z","message":"","client_City":"","client_StateOrProvince":"","itemId":"5c126241-dd30-11ed-a80a-00224826882d","client_OS":"Linux 5.4.0-1036-azure","id":"|b1f0047386554fa59b7c5330560a0799.","customDimensions":null,"itemCount":1,"location":"","user_AuthenticatedId":"","appId":"4ad5a808-11f7-49d5-9713-f6ede83141e4","user_Id":"","resultCode":"200","type":"","data":"","target":"","assembly":"","outerType":"","innermostAssembly":"","innermostType":"","method":"","problemId":"","handledAt":"","outerMessage":"","details":null,"innermostMethod":"","innermostMessage":"","outerAssembly":"","outerMethod":"","severityLevel":null,"url":"test-url","source":""} | 5c126241-dd30-11ed-a80a-00224826882d | request | +// +----------------------------------+-----------------------------------------+------------------------------------+------------------+-------------------------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "string", + "string", + "string", + "real", + "string", + "string", + "datetime", + "dynamic", + "dynamic", + "string", + "string" + ] + } + }, + "fields": [ + { + "name": "traceID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "spanID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "parentSpanID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "duration", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "serviceName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "operationName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "startTime", + "type": "time", + "typeInfo": { + "frame": "time.Time", + "nullable": true + } + }, + { + "name": "serviceTags", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "tags", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "itemId", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "itemType", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + "cfae497bfd7a44169f35643940820938", + "e766f18a0adc49418d297b1a244f1bfb", + "b1f0047386554fa59b7c5330560a0799" + ], + [ + "b52403c5-5b27-43a8-9bc6-5938667a4470", + "|e766f18a0adc49418d297b1a244f1bfb.1901.", + "|b1f0047386554fa59b7c5330560a0799." + ], + [ + "|cfae497bfd7a44169f35643940820938.", + "|e766f18a0adc49418d297b1a244f1bfb.", + "b1f0047386554fa59b7c5330560a0799" + ], + [ + 0, + 330, + 352 + ], + [ + "", + "GET /repos/grafana/grafana/commits", + "GET /github/grafana/grafana/commits" + ], + [ + "GET /github/grafana/grafana/commits", + "GET /github/grafana/grafana/commits", + "GET /github/grafana/grafana/commits" + ], + [ + 1681743490176, + 1681743490764, + 1681743491579 + ], + [ + "{\"service\":\"github-test-data\",\"limit\":\"5000\",\"remaining\":\"4351\",\"reset\":\"1681746512\",\"used\":\"649\",\"timestamp\":\"2023-04-17T14:58:10.0000000Z\"}", + null, + null + ], + [ + "{\"client_IP\":\"0.0.0.0\",\"operation_Id\":\"cfae497bfd7a44169f35643940820938\",\"duration\":0,\"iKey\":\"195b4fe4-7b01-4814-abca-ffceb1f62c8f\",\"size\":null,\"sdkVersion\":\"node:1.8.9\",\"name\":\"\",\"client_Model\":\"\",\"cloud_RoleName\":\"Web\",\"customMeasurements\":null,\"client_Browser\":\"\",\"operation_Name\":\"GET /github/grafana/grafana/commits\",\"performanceBucket\":\"\",\"client_CountryOrRegion\":\"Ireland\",\"cloud_RoleInstance\":\"test-vm\",\"appName\":\"test-app\",\"client_Type\":\"PC\",\"operation_ParentId\":\"|cfae497bfd7a44169f35643940820938.\",\"success\":\"\",\"application_Version\":\"1.0.0\",\"operation_SyntheticSource\":\"\",\"itemType\":\"trace\",\"user_AccountId\":\"\",\"session_Id\":\"\",\"timestamp\":\"2023-04-17T14:58:10.1760000Z\",\"message\":\"github commits rate limiting info\",\"client_City\":\"Dublin\",\"client_StateOrProvince\":\"Dublin\",\"itemId\":\"65863e6b-dd30-11ed-a808-002248268105\",\"client_OS\":\"Linux 5.4.0-1036-azure\",\"id\":\"\",\"customDimensions\":{\"service\":\"github-test-data\",\"limit\":\"5000\",\"remaining\":\"4351\",\"reset\":\"1681746512\",\"used\":\"649\",\"timestamp\":\"2023-04-17T14:58:10.0000000Z\"},\"itemCount\":1,\"location\":\"\",\"user_AuthenticatedId\":\"\",\"appId\":\"4ad5a808-11f7-49d5-9713-f6ede83141e4\",\"user_Id\":\"\",\"resultCode\":\"\",\"type\":\"\",\"data\":\"\",\"target\":\"\",\"assembly\":\"\",\"outerType\":\"\",\"innermostAssembly\":\"\",\"innermostType\":\"\",\"method\":\"\",\"problemId\":\"\",\"handledAt\":\"\",\"outerMessage\":\"\",\"details\":null,\"innermostMethod\":\"\",\"innermostMessage\":\"\",\"outerAssembly\":\"\",\"outerMethod\":\"\",\"severityLevel\":1,\"url\":\"\",\"source\":\"\"}", + "{\"client_IP\":\"0.0.0.0\",\"operation_Id\":\"e766f18a0adc49418d297b1a244f1bfb\",\"duration\":330,\"iKey\":\"195b4fe4-7b01-4814-abca-ffceb1f62c8f\",\"size\":null,\"sdkVersion\":\"node:1.8.9\",\"name\":\"GET /repos/grafana/grafana/commits\",\"client_Model\":\"\",\"cloud_RoleName\":\"Web\",\"customMeasurements\":null,\"client_Browser\":\"\",\"operation_Name\":\"GET /github/grafana/grafana/commits\",\"performanceBucket\":\"250ms-500ms\",\"client_CountryOrRegion\":\"Ireland\",\"cloud_RoleInstance\":\"test-vm\",\"appName\":\"test-app\",\"client_Type\":\"PC\",\"operation_ParentId\":\"|e766f18a0adc49418d297b1a244f1bfb.\",\"success\":\"True\",\"application_Version\":\"1.0.0\",\"operation_SyntheticSource\":\"\",\"itemType\":\"dependency\",\"user_AccountId\":\"\",\"session_Id\":\"\",\"timestamp\":\"2023-04-17T14:58:10.7640000Z\",\"message\":\"\",\"client_City\":\"Dublin\",\"client_StateOrProvince\":\"Dublin\",\"itemId\":\"78c1bcf4-dd30-11ed-a808-0022481f7f28\",\"client_OS\":\"Linux 5.4.0-1036-azure\",\"id\":\"|e766f18a0adc49418d297b1a244f1bfb.1901.\",\"customDimensions\":null,\"itemCount\":1,\"location\":\"\",\"user_AuthenticatedId\":\"\",\"appId\":\"4ad5a808-11f7-49d5-9713-f6ede83141e4\",\"user_Id\":\"\",\"resultCode\":\"200\",\"type\":\"HTTP\",\"data\":\"https://api.github.com/repos/grafana/grafana/commits\",\"target\":\"api.github.com\",\"assembly\":\"\",\"outerType\":\"\",\"innermostAssembly\":\"\",\"innermostType\":\"\",\"method\":\"\",\"problemId\":\"\",\"handledAt\":\"\",\"outerMessage\":\"\",\"details\":null,\"innermostMethod\":\"\",\"innermostMessage\":\"\",\"outerAssembly\":\"\",\"outerMethod\":\"\",\"severityLevel\":null,\"url\":\"\",\"source\":\"\"}", + "{\"client_IP\":\"0.0.0.0\",\"operation_Id\":\"b1f0047386554fa59b7c5330560a0799\",\"duration\":352,\"iKey\":\"195b4fe4-7b01-4814-abca-ffceb1f62c8f\",\"size\":null,\"sdkVersion\":\"node:1.8.9\",\"name\":\"GET /github/grafana/grafana/commits\",\"client_Model\":\"\",\"cloud_RoleName\":\"Web\",\"customMeasurements\":null,\"client_Browser\":\"\",\"operation_Name\":\"GET /github/grafana/grafana/commits\",\"performanceBucket\":\"250ms-500ms\",\"client_CountryOrRegion\":\"\",\"cloud_RoleInstance\":\"test-vm\",\"appName\":\"test-app\",\"client_Type\":\"PC\",\"operation_ParentId\":\"b1f0047386554fa59b7c5330560a0799\",\"success\":\"True\",\"application_Version\":\"1.0.0\",\"operation_SyntheticSource\":\"\",\"itemType\":\"request\",\"user_AccountId\":\"\",\"session_Id\":\"\",\"timestamp\":\"2023-04-17T14:58:11.5790000Z\",\"message\":\"\",\"client_City\":\"\",\"client_StateOrProvince\":\"\",\"itemId\":\"5c126241-dd30-11ed-a80a-00224826882d\",\"client_OS\":\"Linux 5.4.0-1036-azure\",\"id\":\"|b1f0047386554fa59b7c5330560a0799.\",\"customDimensions\":null,\"itemCount\":1,\"location\":\"\",\"user_AuthenticatedId\":\"\",\"appId\":\"4ad5a808-11f7-49d5-9713-f6ede83141e4\",\"user_Id\":\"\",\"resultCode\":\"200\",\"type\":\"\",\"data\":\"\",\"target\":\"\",\"assembly\":\"\",\"outerType\":\"\",\"innermostAssembly\":\"\",\"innermostType\":\"\",\"method\":\"\",\"problemId\":\"\",\"handledAt\":\"\",\"outerMessage\":\"\",\"details\":null,\"innermostMethod\":\"\",\"innermostMessage\":\"\",\"outerAssembly\":\"\",\"outerMethod\":\"\",\"severityLevel\":null,\"url\":\"test-url\",\"source\":\"\"}" + ], + [ + "65863e6b-dd30-11ed-a808-002248268105", + "78c1bcf4-dd30-11ed-a808-0022481f7f28", + "5c126241-dd30-11ed-a80a-00224826882d" + ], + [ + "trace", + "dependency", + "request" + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json b/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json new file mode 100644 index 00000000000..e66081489c8 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json @@ -0,0 +1,69 @@ +{ + "tables": [ + { + "name": "PrimaryResult", + "columns": [ + { + "name": "traceID", + "type": "string" + }, + { + "name": "spanID", + "type": "string" + }, + { + "name": "parentSpanID", + "type": "string" + }, + { + "name": "duration", + "type": "real" + }, + { + "name": "serviceName", + "type": "string" + }, + { + "name": "operationName", + "type": "string" + }, + { + "name": "startTime", + "type": "datetime" + }, + { + "name": "serviceTags", + "type": "dynamic" + }, + { + "name": "tags", + "type": "dynamic" + }, + { + "name": "itemId", + "type": "string" + }, + { + "name": "itemType", + "type": "string" + } + ], + "rows": [ + [ + "cfae497bfd7a44169f35643940820938", + "b52403c5-5b27-43a8-9bc6-5938667a4470", + "|cfae497bfd7a44169f35643940820938.", + 0, + "", + "GET /github/grafana/grafana/commits", + "2023-04-17T14:58:10.176Z", + "{\"service\":\"github-test-data\",\"limit\":\"5000\",\"remaining\":\"4351\",\"reset\":\"1681746512\",\"used\":\"649\",\"timestamp\":\"2023-04-17T14:58:10.0000000Z\"}", + "{\"client_IP\":\"0.0.0.0\",\"operation_Id\":\"cfae497bfd7a44169f35643940820938\",\"duration\":0,\"iKey\":\"195b4fe4-7b01-4814-abca-ffceb1f62c8f\",\"size\":null,\"sdkVersion\":\"node:1.8.9\",\"name\":\"\",\"client_Model\":\"\",\"cloud_RoleName\":\"Web\",\"customMeasurements\":null,\"client_Browser\":\"\",\"operation_Name\":\"GET /github/grafana/grafana/commits\",\"performanceBucket\":\"\",\"client_CountryOrRegion\":\"Ireland\",\"cloud_RoleInstance\":\"test-vm\",\"appName\":\"test-app\",\"client_Type\":\"PC\",\"operation_ParentId\":\"|cfae497bfd7a44169f35643940820938.\",\"success\":\"\",\"application_Version\":\"1.0.0\",\"operation_SyntheticSource\":\"\",\"itemType\":\"trace\",\"user_AccountId\":\"\",\"session_Id\":\"\",\"timestamp\":\"2023-04-17T14:58:10.1760000Z\",\"message\":\"github commits rate limiting info\",\"client_City\":\"Dublin\",\"client_StateOrProvince\":\"Dublin\",\"itemId\":\"65863e6b-dd30-11ed-a808-002248268105\",\"client_OS\":\"Linux 5.4.0-1036-azure\",\"id\":\"\",\"customDimensions\":{\"service\":\"github-test-data\",\"limit\":\"5000\",\"remaining\":\"4351\",\"reset\":\"1681746512\",\"used\":\"649\",\"timestamp\":\"2023-04-17T14:58:10.0000000Z\"},\"itemCount\":1,\"location\":\"\",\"user_AuthenticatedId\":\"\",\"appId\":\"4ad5a808-11f7-49d5-9713-f6ede83141e4\",\"user_Id\":\"\",\"resultCode\":\"\",\"type\":\"\",\"data\":\"\",\"target\":\"\",\"assembly\":\"\",\"outerType\":\"\",\"innermostAssembly\":\"\",\"innermostType\":\"\",\"method\":\"\",\"problemId\":\"\",\"handledAt\":\"\",\"outerMessage\":\"\",\"details\":null,\"innermostMethod\":\"\",\"innermostMessage\":\"\",\"outerAssembly\":\"\",\"outerMethod\":\"\",\"severityLevel\":1,\"url\":\"\",\"source\":\"\"}", + "65863e6b-dd30-11ed-a808-002248268105", + "trace" + ] + ] + } + ] + } + \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json.single-trace-as-trace-format.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json.single-trace-as-trace-format.golden.jsonc new file mode 100644 index 00000000000..86a6297d6ef --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json.single-trace-as-trace-format.golden.jsonc @@ -0,0 +1,321 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "string", +// "string", +// "string", +// "real", +// "string", +// "string", +// "datetime", +// "dynamic", +// "dynamic", +// "string", +// "string" +// ] +// } +// } +// Name: +// Dimensions: 11 Fields by 1 Rows +// +----------------------------------+--------------------------------------+------------------------------------+------------------+-------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// | Name: traceID | Name: spanID | Name: parentSpanID | Name: duration | Name: serviceName | Name: operationName | Name: startTime | Name: serviceTags | Name: tags | Name: itemId | Name: itemType | +// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | +// | Type: []*string | Type: []*string | Type: []*string | Type: []*float64 | Type: []*string | Type: []*string | Type: []*time.Time | Type: []*json.RawMessage | Type: []*json.RawMessage | Type: []*string | Type: []*string | +// +----------------------------------+--------------------------------------+------------------------------------+------------------+-------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// | cfae497bfd7a44169f35643940820938 | b52403c5-5b27-43a8-9bc6-5938667a4470 | |cfae497bfd7a44169f35643940820938. | 0 | | GET /github/grafana/grafana/commits | 2023-04-17 14:58:10.176 +0000 UTC | [{"value":"5000","key":"limit"},{"value":"4351","key":"remaining"},{"value":"1681746512","key":"reset"},{"value":"github-test-data","key":"service"},{"value":"2023-04-17T14:58:10.0000000Z","key":"timestamp"},{"value":"649","key":"used"}] | [{"value":"4ad5a808-11f7-49d5-9713-f6ede83141e4","key":"appId"},{"value":"test-app","key":"appName"},{"value":"1.0.0","key":"application_Version"},{"value":"Dublin","key":"client_City"},{"value":"Ireland","key":"client_CountryOrRegion"},{"value":"0.0.0.0","key":"client_IP"},{"value":"Linux 5.4.0-1036-azure","key":"client_OS"},{"value":"Dublin","key":"client_StateOrProvince"},{"value":"PC","key":"client_Type"},{"value":"test-vm","key":"cloud_RoleInstance"},{"value":"Web","key":"cloud_RoleName"},{"value":{"limit":"5000","remaining":"4351","reset":"1681746512","service":"github-test-data","timestamp":"2023-04-17T14:58:10.0000000Z","used":"649"},"key":"customDimensions"},{"value":0,"key":"duration"},{"value":"195b4fe4-7b01-4814-abca-ffceb1f62c8f","key":"iKey"},{"value":1,"key":"itemCount"},{"value":"65863e6b-dd30-11ed-a808-002248268105","key":"itemId"},{"value":"trace","key":"itemType"},{"value":"github commits rate limiting info","key":"message"},{"value":"cfae497bfd7a44169f35643940820938","key":"operation_Id"},{"value":"GET /github/grafana/grafana/commits","key":"operation_Name"},{"value":"|cfae497bfd7a44169f35643940820938.","key":"operation_ParentId"},{"value":"node:1.8.9","key":"sdkVersion"},{"value":1,"key":"severityLevel"},{"value":"2023-04-17T14:58:10.1760000Z","key":"timestamp"}] | 65863e6b-dd30-11ed-a808-002248268105 | trace | +// +----------------------------------+--------------------------------------+------------------------------------+------------------+-------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "string", + "string", + "string", + "real", + "string", + "string", + "datetime", + "dynamic", + "dynamic", + "string", + "string" + ] + } + }, + "fields": [ + { + "name": "traceID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "spanID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "parentSpanID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "duration", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "serviceName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "operationName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "startTime", + "type": "time", + "typeInfo": { + "frame": "time.Time", + "nullable": true + } + }, + { + "name": "serviceTags", + "type": "other", + "typeInfo": { + "frame": "json.RawMessage", + "nullable": true + } + }, + { + "name": "tags", + "type": "other", + "typeInfo": { + "frame": "json.RawMessage", + "nullable": true + } + }, + { + "name": "itemId", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "itemType", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + "cfae497bfd7a44169f35643940820938" + ], + [ + "b52403c5-5b27-43a8-9bc6-5938667a4470" + ], + [ + "|cfae497bfd7a44169f35643940820938." + ], + [ + 0 + ], + [ + "" + ], + [ + "GET /github/grafana/grafana/commits" + ], + [ + 1681743490176 + ], + [ + [ + { + "value": "5000", + "key": "limit" + }, + { + "value": "4351", + "key": "remaining" + }, + { + "value": "1681746512", + "key": "reset" + }, + { + "value": "github-test-data", + "key": "service" + }, + { + "value": "2023-04-17T14:58:10.0000000Z", + "key": "timestamp" + }, + { + "value": "649", + "key": "used" + } + ] + ], + [ + [ + { + "value": "4ad5a808-11f7-49d5-9713-f6ede83141e4", + "key": "appId" + }, + { + "value": "test-app", + "key": "appName" + }, + { + "value": "1.0.0", + "key": "application_Version" + }, + { + "value": "Dublin", + "key": "client_City" + }, + { + "value": "Ireland", + "key": "client_CountryOrRegion" + }, + { + "value": "0.0.0.0", + "key": "client_IP" + }, + { + "value": "Linux 5.4.0-1036-azure", + "key": "client_OS" + }, + { + "value": "Dublin", + "key": "client_StateOrProvince" + }, + { + "value": "PC", + "key": "client_Type" + }, + { + "value": "test-vm", + "key": "cloud_RoleInstance" + }, + { + "value": "Web", + "key": "cloud_RoleName" + }, + { + "value": { + "limit": "5000", + "remaining": "4351", + "reset": "1681746512", + "service": "github-test-data", + "timestamp": "2023-04-17T14:58:10.0000000Z", + "used": "649" + }, + "key": "customDimensions" + }, + { + "value": 0, + "key": "duration" + }, + { + "value": "195b4fe4-7b01-4814-abca-ffceb1f62c8f", + "key": "iKey" + }, + { + "value": 1, + "key": "itemCount" + }, + { + "value": "65863e6b-dd30-11ed-a808-002248268105", + "key": "itemId" + }, + { + "value": "trace", + "key": "itemType" + }, + { + "value": "github commits rate limiting info", + "key": "message" + }, + { + "value": "cfae497bfd7a44169f35643940820938", + "key": "operation_Id" + }, + { + "value": "GET /github/grafana/grafana/commits", + "key": "operation_Name" + }, + { + "value": "|cfae497bfd7a44169f35643940820938.", + "key": "operation_ParentId" + }, + { + "value": "node:1.8.9", + "key": "sdkVersion" + }, + { + "value": 1, + "key": "severityLevel" + }, + { + "value": "2023-04-17T14:58:10.1760000Z", + "key": "timestamp" + } + ] + ], + [ + "65863e6b-dd30-11ed-a808-002248268105" + ], + [ + "trace" + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json.single-trace.golden.jsonc b/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json.single-trace.golden.jsonc new file mode 100644 index 00000000000..9fd3477cb68 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/traces/2-traces-single-table.json.single-trace.golden.jsonc @@ -0,0 +1,192 @@ +// 🌟 This was machine generated. Do not edit. 🌟 +// +// Frame[0] { +// "typeVersion": [ +// 0, +// 0 +// ], +// "custom": { +// "azureColumnTypes": [ +// "string", +// "string", +// "string", +// "real", +// "string", +// "string", +// "datetime", +// "dynamic", +// "dynamic", +// "string", +// "string" +// ] +// } +// } +// Name: +// Dimensions: 11 Fields by 1 Rows +// +----------------------------------+--------------------------------------+------------------------------------+------------------+-------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// | Name: traceID | Name: spanID | Name: parentSpanID | Name: duration | Name: serviceName | Name: operationName | Name: startTime | Name: serviceTags | Name: tags | Name: itemId | Name: itemType | +// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | +// | Type: []*string | Type: []*string | Type: []*string | Type: []*float64 | Type: []*string | Type: []*string | Type: []*time.Time | Type: []*string | Type: []*string | Type: []*string | Type: []*string | +// +----------------------------------+--------------------------------------+------------------------------------+------------------+-------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// | cfae497bfd7a44169f35643940820938 | b52403c5-5b27-43a8-9bc6-5938667a4470 | |cfae497bfd7a44169f35643940820938. | 0 | | GET /github/grafana/grafana/commits | 2023-04-17 14:58:10.176 +0000 UTC | {"service":"github-test-data","limit":"5000","remaining":"4351","reset":"1681746512","used":"649","timestamp":"2023-04-17T14:58:10.0000000Z"} | {"client_IP":"0.0.0.0","operation_Id":"cfae497bfd7a44169f35643940820938","duration":0,"iKey":"195b4fe4-7b01-4814-abca-ffceb1f62c8f","size":null,"sdkVersion":"node:1.8.9","name":"","client_Model":"","cloud_RoleName":"Web","customMeasurements":null,"client_Browser":"","operation_Name":"GET /github/grafana/grafana/commits","performanceBucket":"","client_CountryOrRegion":"Ireland","cloud_RoleInstance":"test-vm","appName":"test-app","client_Type":"PC","operation_ParentId":"|cfae497bfd7a44169f35643940820938.","success":"","application_Version":"1.0.0","operation_SyntheticSource":"","itemType":"trace","user_AccountId":"","session_Id":"","timestamp":"2023-04-17T14:58:10.1760000Z","message":"github commits rate limiting info","client_City":"Dublin","client_StateOrProvince":"Dublin","itemId":"65863e6b-dd30-11ed-a808-002248268105","client_OS":"Linux 5.4.0-1036-azure","id":"","customDimensions":{"service":"github-test-data","limit":"5000","remaining":"4351","reset":"1681746512","used":"649","timestamp":"2023-04-17T14:58:10.0000000Z"},"itemCount":1,"location":"","user_AuthenticatedId":"","appId":"4ad5a808-11f7-49d5-9713-f6ede83141e4","user_Id":"","resultCode":"","type":"","data":"","target":"","assembly":"","outerType":"","innermostAssembly":"","innermostType":"","method":"","problemId":"","handledAt":"","outerMessage":"","details":null,"innermostMethod":"","innermostMessage":"","outerAssembly":"","outerMethod":"","severityLevel":1,"url":"","source":""} | 65863e6b-dd30-11ed-a808-002248268105 | trace | +// +----------------------------------+--------------------------------------+------------------------------------+------------------+-------------------+-------------------------------------+-----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------+-----------------+ +// +// +// 🌟 This was machine generated. Do not edit. 🌟 +{ + "status": 200, + "frames": [ + { + "schema": { + "meta": { + "typeVersion": [ + 0, + 0 + ], + "custom": { + "azureColumnTypes": [ + "string", + "string", + "string", + "real", + "string", + "string", + "datetime", + "dynamic", + "dynamic", + "string", + "string" + ] + } + }, + "fields": [ + { + "name": "traceID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "spanID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "parentSpanID", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "duration", + "type": "number", + "typeInfo": { + "frame": "float64", + "nullable": true + } + }, + { + "name": "serviceName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "operationName", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "startTime", + "type": "time", + "typeInfo": { + "frame": "time.Time", + "nullable": true + } + }, + { + "name": "serviceTags", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "tags", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "itemId", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + }, + { + "name": "itemType", + "type": "string", + "typeInfo": { + "frame": "string", + "nullable": true + } + } + ] + }, + "data": { + "values": [ + [ + "cfae497bfd7a44169f35643940820938" + ], + [ + "b52403c5-5b27-43a8-9bc6-5938667a4470" + ], + [ + "|cfae497bfd7a44169f35643940820938." + ], + [ + 0 + ], + [ + "" + ], + [ + "GET /github/grafana/grafana/commits" + ], + [ + 1681743490176 + ], + [ + "{\"service\":\"github-test-data\",\"limit\":\"5000\",\"remaining\":\"4351\",\"reset\":\"1681746512\",\"used\":\"649\",\"timestamp\":\"2023-04-17T14:58:10.0000000Z\"}" + ], + [ + "{\"client_IP\":\"0.0.0.0\",\"operation_Id\":\"cfae497bfd7a44169f35643940820938\",\"duration\":0,\"iKey\":\"195b4fe4-7b01-4814-abca-ffceb1f62c8f\",\"size\":null,\"sdkVersion\":\"node:1.8.9\",\"name\":\"\",\"client_Model\":\"\",\"cloud_RoleName\":\"Web\",\"customMeasurements\":null,\"client_Browser\":\"\",\"operation_Name\":\"GET /github/grafana/grafana/commits\",\"performanceBucket\":\"\",\"client_CountryOrRegion\":\"Ireland\",\"cloud_RoleInstance\":\"test-vm\",\"appName\":\"test-app\",\"client_Type\":\"PC\",\"operation_ParentId\":\"|cfae497bfd7a44169f35643940820938.\",\"success\":\"\",\"application_Version\":\"1.0.0\",\"operation_SyntheticSource\":\"\",\"itemType\":\"trace\",\"user_AccountId\":\"\",\"session_Id\":\"\",\"timestamp\":\"2023-04-17T14:58:10.1760000Z\",\"message\":\"github commits rate limiting info\",\"client_City\":\"Dublin\",\"client_StateOrProvince\":\"Dublin\",\"itemId\":\"65863e6b-dd30-11ed-a808-002248268105\",\"client_OS\":\"Linux 5.4.0-1036-azure\",\"id\":\"\",\"customDimensions\":{\"service\":\"github-test-data\",\"limit\":\"5000\",\"remaining\":\"4351\",\"reset\":\"1681746512\",\"used\":\"649\",\"timestamp\":\"2023-04-17T14:58:10.0000000Z\"},\"itemCount\":1,\"location\":\"\",\"user_AuthenticatedId\":\"\",\"appId\":\"4ad5a808-11f7-49d5-9713-f6ede83141e4\",\"user_Id\":\"\",\"resultCode\":\"\",\"type\":\"\",\"data\":\"\",\"target\":\"\",\"assembly\":\"\",\"outerType\":\"\",\"innermostAssembly\":\"\",\"innermostType\":\"\",\"method\":\"\",\"problemId\":\"\",\"handledAt\":\"\",\"outerMessage\":\"\",\"details\":null,\"innermostMethod\":\"\",\"innermostMessage\":\"\",\"outerAssembly\":\"\",\"outerMethod\":\"\",\"severityLevel\":1,\"url\":\"\",\"source\":\"\"}" + ], + [ + "65863e6b-dd30-11ed-a808-002248268105" + ], + [ + "trace" + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/tsdb/azuremonitor/testdata/utils.go b/pkg/tsdb/azuremonitor/testdata/utils.go new file mode 100644 index 00000000000..96820c18dd2 --- /dev/null +++ b/pkg/tsdb/azuremonitor/testdata/utils.go @@ -0,0 +1,29 @@ +package testdata + +import ( + "fmt" + "path/filepath" + "testing" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/experimental" +) + +func CheckGoldenFrame(t *testing.T, path string, name string, f *data.Frame) { + frames := data.Frames{f} + if f == nil { + frames = nil + } + dr := backend.DataResponse{ + Frames: frames, + } + experimental.CheckGoldenJSONResponse(t, filepath.Join(path), fmt.Sprintf("%s.golden", name), &dr, true) +} + +func CheckGoldenFrames(t *testing.T, path string, name string, f data.Frames) { + dr := backend.DataResponse{ + Frames: f, + } + experimental.CheckGoldenJSONResponse(t, filepath.Join(path), fmt.Sprintf("%s.golden", name), &dr, true) +} diff --git a/pkg/tsdb/azuremonitor/types/types.go b/pkg/tsdb/azuremonitor/types/types.go index 73fc3160a34..ab063400b99 100644 --- a/pkg/tsdb/azuremonitor/types/types.go +++ b/pkg/tsdb/azuremonitor/types/types.go @@ -11,10 +11,13 @@ import ( "github.com/grafana/grafana-azure-sdk-go/azcredentials" "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery" ) const ( TimeSeries = "time_series" + Table = "table" + Trace = "trace" ) var ( @@ -54,6 +57,9 @@ type DatasourceInfo struct { DecryptedSecureJSONData map[string]string DatasourceID int64 OrgID int64 + + DatasourceName string + DatasourceUID string } // AzureMonitorQuery is the query for all the services as they have similar queries @@ -183,6 +189,7 @@ type LogJSONQuery struct { Query string `json:"query"` ResultFormat string `json:"resultFormat"` Resources []string `json:"resources"` + OperationId string `json:"operationId"` // Deprecated: Queries should be migrated to use Resource instead Workspace string `json:"workspace"` @@ -191,6 +198,39 @@ type LogJSONQuery struct { } `json:"azureLogAnalytics"` } +type TracesJSONQuery struct { + AzureTraces struct { + // Filters for property values. + Filters []TracesFilters `json:"filters"` + + // Operation ID. Used only for Traces queries. + OperationId *string `json:"operationId"` + + // KQL query to be executed. + Query *string `json:"query"` + + // Array of resource URIs to be queried. + Resources []string `json:"resources"` + + // Specifies the format results should be returned as. + ResultFormat *dataquery.AzureMonitorQueryAzureTracesResultFormat `json:"resultFormat"` + + // Types of events to filter by. + TraceTypes []string `json:"traceTypes"` + } `json:"azureTraces"` +} + +type TracesFilters struct { + // Values to filter by. + Filters []string `json:"filters"` + + // Comparison operator to use. Either equals or not equals. + Operation string `json:"operation"` + + // Property name, auto-populated based on available traces. + Property string `json:"property"` +} + // MetricChartDefinition is the JSON model for a metrics chart definition type MetricChartDefinition struct { ResourceMetadata map[string]string `json:"resourceMetadata"` diff --git a/public/app/plugins/datasource/azuremonitor/__mocks__/datasource.ts b/public/app/plugins/datasource/azuremonitor/__mocks__/datasource.ts index da450501276..48864ab66b4 100644 --- a/public/app/plugins/datasource/azuremonitor/__mocks__/datasource.ts +++ b/public/app/plugins/datasource/azuremonitor/__mocks__/datasource.ts @@ -1,8 +1,13 @@ +import { ContextSrv } from 'app/core/services/context_srv'; +import { TimeSrv } from 'app/features/dashboard/services/TimeSrv'; + import Datasource from '../datasource'; type DeepPartial = { [P in keyof T]?: DeepPartial; }; +const contextSrv = new ContextSrv(); +const timeSrv = new TimeSrv(contextSrv); export default function createMockDatasource(overrides?: DeepPartial) { // We make this a partial so we get _some_ kind of type safety when making this, rather than @@ -46,6 +51,7 @@ export default function createMockDatasource(overrides?: DeepPartial azureLogAnalyticsDatasource: { getKustoSchema: () => Promise.resolve(), getDeprecatedDefaultWorkSpace: () => 'defaultWorkspaceId', + timeSrv, }, resourcePickerData: { getSubscriptions: () => jest.fn().mockResolvedValue([]), diff --git a/public/app/plugins/datasource/azuremonitor/__mocks__/query.ts b/public/app/plugins/datasource/azuremonitor/__mocks__/query.ts index aabc97f3d2b..b5f19425316 100644 --- a/public/app/plugins/datasource/azuremonitor/__mocks__/query.ts +++ b/public/app/plugins/datasource/azuremonitor/__mocks__/query.ts @@ -27,6 +27,16 @@ export default function createMockQuery(overrides?: Partial): ...overrides?.azureResourceGraph, }, + azureTraces: { + query: 'example traces query', + resultFormat: ResultFormat.Trace, + resources: ['test-resource'], + operationId: 'operationId', + traceTypes: ['traces'], + filters: [{ filters: ['filter'], operation: 'eq', property: 'property' }], + ...overrides?.azureTraces, + }, + azureMonitor: { // aggOptions: [], aggregation: 'Average', diff --git a/public/app/plugins/datasource/azuremonitor/__mocks__/resourcePickerRows.ts b/public/app/plugins/datasource/azuremonitor/__mocks__/resourcePickerRows.ts index 18f7ca495aa..3de04fd222d 100644 --- a/public/app/plugins/datasource/azuremonitor/__mocks__/resourcePickerRows.ts +++ b/public/app/plugins/datasource/azuremonitor/__mocks__/resourcePickerRows.ts @@ -88,7 +88,6 @@ export const mockResourcesByResourceGroup = (): ResourceRowGroup => [ type: ResourceRowType.Resource, location: 'northeurope', }, - { id: 'db-server', uri: '/subscriptions/def-456/resourceGroups/dev-3/providers/Microsoft.Compute/virtualMachines/db-server', @@ -106,6 +105,22 @@ export const mockResourcesByResourceGroup = (): ResourceRowGroup => [ type: ResourceRowType.Resource, location: 'northeurope', }, + { + id: 'app-insights-1', + uri: '/subscriptions/def-456/resourceGroups/dev-3/providers/microsoft.insights/components/app-insights-1', + name: 'app-insights-1', + typeLabel: 'Microsoft.Insights/components', + type: ResourceRowType.Resource, + location: 'northeurope', + }, + { + id: 'app-insights-2', + uri: '/subscriptions/def-456/resourceGroups/dev-3/providers/microsoft.insights/components/app-insights-2', + name: 'app-insights-2', + typeLabel: 'Microsoft.Insights/components', + type: ResourceRowType.Resource, + location: 'northeurope', + }, ]; export const mockSearchResults = (): ResourceRowGroup => [ diff --git a/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.test.ts b/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.test.ts index eab35ea8941..135e999dbbe 100644 --- a/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.test.ts +++ b/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.test.ts @@ -5,7 +5,7 @@ import createMockQuery from '../__mocks__/query'; import { createTemplateVariables } from '../__mocks__/utils'; import { singleVariable } from '../__mocks__/variables'; import AzureMonitorDatasource from '../datasource'; -import { AzureMonitorQuery, AzureQueryType } from '../types'; +import { AzureLogsQuery, AzureMonitorQuery, AzureQueryType, AzureTracesQuery } from '../types'; import FakeSchemaData from './__mocks__/schema'; import AzureLogAnalyticsDatasource from './azure_log_analytics_datasource'; @@ -330,6 +330,17 @@ describe('AzureLogAnalyticsDatasource', () => { expect(laDatasource.filterQuery(query)).toBeFalsy(); }); + + it('should not run traces queries missing a resource', () => { + const query: AzureMonitorQuery = { + refId: 'A', + azureTraces: { + resources: [], + }, + }; + + expect(laDatasource.filterQuery(query)).toBeFalsy(); + }); }); describe('When performing interpolateVariablesInQueries for azure_log_analytics', () => { @@ -344,12 +355,12 @@ describe('AzureLogAnalyticsDatasource', () => { expect(templatedQuery[0]).toEqual(query); }); - it('should return a query with any template variables replaced', () => { + it('should return a logs query with any template variables replaced', () => { const templateableProps = ['resource', 'workspace', 'query']; const templateVariables = createTemplateVariables(templateableProps); templateSrv.init(Array.from(templateVariables.values()).map((item) => item.templateVariable)); const query = createMockQuery(); - const azureLogAnalytics: { [index: string]: any } = {}; + const azureLogAnalytics: Partial = {}; azureLogAnalytics.query = '$query'; azureLogAnalytics.workspace = '$workspace'; azureLogAnalytics.resources = ['$resource']; @@ -366,5 +377,39 @@ describe('AzureLogAnalyticsDatasource', () => { resources: [templateVariables.get('resource')?.templateVariable.current.value], }); }); + + it('should return a traces query with any template variables replaced', () => { + const templateableProps = ['resource', 'query', 'traceTypes', 'property', 'operation', 'filter', 'operationId']; + const templateVariables = createTemplateVariables(templateableProps); + templateSrv.init(Array.from(templateVariables.values()).map((item) => item.templateVariable)); + const query = createMockQuery(); + const azureTraces: Partial = {}; + azureTraces.resources = ['$resource']; + azureTraces.query = '$query'; + azureTraces.traceTypes = ['$traceTypes']; + azureTraces.filters = [{ filters: ['$filter'], operation: 'eq', property: '$property' }]; + azureTraces.operationId = '$operationId'; + query.queryType = AzureQueryType.AzureTraces; + query.azureTraces = { + ...query.azureTraces, + ...azureTraces, + }; + + const templatedQuery = ctx.ds.interpolateVariablesInQueries([query], {}); + expect(templatedQuery[0]).toHaveProperty('datasource'); + expect(templatedQuery[0].azureTraces).toMatchObject({ + query: templateVariables.get('query')?.templateVariable.current.value, + resources: [templateVariables.get('resource')?.templateVariable.current.value], + operationId: templateVariables.get('operationId')?.templateVariable.current.value, + traceTypes: [templateVariables.get('traceTypes')?.templateVariable.current.value], + filters: [ + { + filters: [templateVariables.get('filter')?.templateVariable.current.value], + operation: 'eq', + property: templateVariables.get('property')?.templateVariable.current.value, + }, + ], + }); + }); }); }); diff --git a/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts b/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts index b98f18e0ddf..53ee7b8a7a6 100644 --- a/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts +++ b/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts @@ -2,6 +2,7 @@ import { map } from 'lodash'; import { DataSourceInstanceSettings, DataSourceRef, ScopedVars } from '@grafana/data'; import { DataSourceWithBackend, getTemplateSrv } from '@grafana/runtime'; +import { TimeSrv, getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { isGUIDish } from '../components/ResourcePicker/utils'; import { getAuthType, getAzureCloud, getAzurePortalUrl } from '../credentials'; @@ -36,6 +37,8 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend< azureMonitorPath: string; firstWorkspace?: string; + readonly timeSrv: TimeSrv = getTimeSrv(); + constructor(private instanceSettings: DataSourceInstanceSettings) { super(instanceSettings); @@ -55,8 +58,9 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend< filterQuery(item: AzureMonitorQuery): boolean { return ( item.hide !== true && - !!item.azureLogAnalytics?.query && - (!!item.azureLogAnalytics.resources?.length || !!item.azureLogAnalytics.workspace) + ((!!item.azureLogAnalytics?.query && + (!!item.azureLogAnalytics.resources?.length || !!item.azureLogAnalytics.workspace)) || + !!item.azureTraces?.resources?.length) ); } @@ -108,34 +112,66 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend< } applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery { - const item = target.azureLogAnalytics; - if (!item) { - return target; + let item; + if (target.queryType === AzureQueryType.LogAnalytics && target.azureLogAnalytics) { + item = target.azureLogAnalytics; + const templateSrv = getTemplateSrv(); + const resources = item.resources?.map((r) => templateSrv.replace(r, scopedVars)); + let workspace = templateSrv.replace(item.workspace, scopedVars); + + if (!workspace && !resources && this.firstWorkspace) { + workspace = this.firstWorkspace; + } + + const query = templateSrv.replace(item.query, scopedVars, interpolateVariable); + + return { + ...target, + queryType: target.queryType || AzureQueryType.LogAnalytics, + + azureLogAnalytics: { + resultFormat: item.resultFormat, + query, + resources, + // Workspace was removed in Grafana 8, but remains for backwards compat + workspace, + }, + }; } - const templateSrv = getTemplateSrv(); - const resources = item.resources?.map((r) => templateSrv.replace(r, scopedVars)); - let workspace = templateSrv.replace(item.workspace, scopedVars); + if (target.queryType === AzureQueryType.AzureTraces && target.azureTraces) { + item = target.azureTraces; + const templateSrv = getTemplateSrv(); + const resources = item.resources?.map((r) => templateSrv.replace(r, scopedVars)); + const query = templateSrv.replace(item.query, scopedVars, interpolateVariable); + const traceTypes = item.traceTypes?.map((t) => templateSrv.replace(t, scopedVars)); + const filters = (item.filters ?? []) + .filter((f) => !!f.property) + .map((f) => { + const filtersReplaced = f.filters?.map((filter) => templateSrv.replace(filter ?? '', scopedVars)); + return { + property: templateSrv.replace(f.property, scopedVars), + operation: f.operation || 'eq', + filters: filtersReplaced || [], + }; + }); - if (!workspace && !resources && this.firstWorkspace) { - workspace = this.firstWorkspace; + return { + ...target, + queryType: target.queryType || AzureQueryType.AzureTraces, + + azureTraces: { + resultFormat: item.resultFormat, + query, + resources, + operationId: templateSrv.replace(target.azureTraces?.operationId, scopedVars), + filters, + traceTypes, + }, + }; } - const query = templateSrv.replace(item.query, scopedVars, interpolateVariable); - - return { - ...target, - queryType: AzureQueryType.LogAnalytics, - - azureLogAnalytics: { - resultFormat: item.resultFormat, - query, - resources, - - // Workspace was removed in Grafana 8, but remains for backwards compat - workspace, - }, - }; + return target; } /* diff --git a/public/app/plugins/datasource/azuremonitor/components/FormatAsField.test.tsx b/public/app/plugins/datasource/azuremonitor/components/FormatAsField.test.tsx new file mode 100644 index 00000000000..944643e46a5 --- /dev/null +++ b/public/app/plugins/datasource/azuremonitor/components/FormatAsField.test.tsx @@ -0,0 +1,73 @@ +import { render, screen } from '@testing-library/react'; +import React from 'react'; + +import createMockDatasource from '../__mocks__/datasource'; +import createMockQuery from '../__mocks__/query'; +import { ResultFormat } from '../types'; + +import FormatAsField from './FormatAsField'; +import { setFormatAs } from './TracesQueryEditor/setQueryValue'; + +const options = [ + { label: 'Table', value: ResultFormat.Table }, + { label: 'Trace', value: ResultFormat.Trace }, + { label: 'Time Series', value: ResultFormat.TimeSeries }, +]; + +const props = { + query: createMockQuery(), + datasource: createMockDatasource(), + variableOptionGroup: { label: 'Templates', options: [] }, + onQueryChange: jest.fn(), + setError: jest.fn(), + isLoading: false, + inputId: 'input-id', + options, + defaultValue: ResultFormat.Table, + setFormatAs, + resultFormat: undefined, +}; + +describe('FormatAsField', () => { + it('should render the current value', async () => { + const query = { + ...props.query, + azureTraces: { + resultFormat: ResultFormat.Trace, + }, + }; + render(); + expect(screen.getByText('Trace')).toBeInTheDocument(); + }); + + it('should render the default value if selected is not in list of options', async () => { + const query = { + ...props.query, + azureTraces: { + resultFormat: ResultFormat.Trace, + }, + }; + + const shortOptions = options.slice(0, 1); + + const { rerender } = render( + + ); + + const newQuery = { + ...query, + azureTraces: { ...query.azureTraces, resultFormat: props.defaultValue }, + }; + expect(props.onQueryChange).toHaveBeenCalledWith(newQuery); + rerender( + + ); + expect(screen.getByText('Table')).toBeInTheDocument(); + expect(screen.queryByText('Trace')).not.toBeInTheDocument(); + }); +}); diff --git a/public/app/plugins/datasource/azuremonitor/components/FormatAsField.tsx b/public/app/plugins/datasource/azuremonitor/components/FormatAsField.tsx new file mode 100644 index 00000000000..884edb0ec0b --- /dev/null +++ b/public/app/plugins/datasource/azuremonitor/components/FormatAsField.tsx @@ -0,0 +1,60 @@ +import React, { useCallback, useMemo } from 'react'; +import { useEffectOnce } from 'react-use'; + +import { SelectableValue } from '@grafana/data'; +import { Select } from '@grafana/ui'; + +import { selectors } from '../e2e/selectors'; +import { FormatAsFieldProps, ResultFormat } from '../types'; + +import { Field } from './Field'; + +const FormatAsField = ({ + query, + variableOptionGroup, + onQueryChange, + inputId, + options: formatOptions, + defaultValue, + setFormatAs, + resultFormat, +}: FormatAsFieldProps) => { + const options = useMemo(() => [...formatOptions, variableOptionGroup], [variableOptionGroup, formatOptions]); + + const handleChange = useCallback( + (change: SelectableValue) => { + const { value } = change; + if (!value) { + return; + } + + const newQuery = setFormatAs(query, value); + onQueryChange(newQuery); + }, + [onQueryChange, query, setFormatAs] + ); + + useEffectOnce(() => { + if (!resultFormat) { + handleChange({ value: defaultValue }); + } else { + if (!formatOptions.find((item) => item.value === resultFormat)) { + handleChange({ value: defaultValue }); + } + } + }); + + return ( + + - - ); -}; - -export default FormatAsField; diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx index ee24b71b71e..0dc882bf9fa 100644 --- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx @@ -170,7 +170,7 @@ describe('LogsQueryEditor', () => { await userEvent.click(advancedSection); const advancedInput = await screen.findByTestId('input-advanced-resource-picker-1'); - // const advancedInput = await screen.findByLabelText('Resource URI(s)'); + await userEvent.type(advancedInput, '/subscriptions/def-123'); const applyButton = screen.getByRole('button', { name: 'Apply' }); diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.tsx index 4152dd37968..f967a0d8daa 100644 --- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.tsx @@ -4,14 +4,16 @@ import { EditorFieldGroup, EditorRow, EditorRows } from '@grafana/experimental'; import { Alert } from '@grafana/ui'; import Datasource from '../../datasource'; -import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery } from '../../types'; +import { selectors } from '../../e2e/selectors'; +import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery, ResultFormat } from '../../types'; +import FormatAsField from '../FormatAsField'; import ResourceField from '../ResourceField'; import { ResourceRow, ResourceRowGroup, ResourceRowType } from '../ResourcePicker/types'; import { parseResourceDetails } from '../ResourcePicker/utils'; import AdvancedResourcePicker from './AdvancedResourcePicker'; -import FormatAsField from './FormatAsField'; import QueryField from './QueryField'; +import { setFormatAs } from './setQueryValue'; import useMigrations from './useMigrations'; interface LogsQueryEditorProps { @@ -49,7 +51,7 @@ const LogsQueryEditor = ({ }; return ( - + @@ -99,6 +101,14 @@ const LogsQueryEditor = ({ variableOptionGroup={variableOptionGroup} onQueryChange={onChange} setError={setError} + inputId={'azure-monitor-logs'} + options={[ + { label: 'Time series', value: ResultFormat.TimeSeries }, + { label: 'Table', value: ResultFormat.Table }, + ]} + defaultValue={ResultFormat.Table} + setFormatAs={setFormatAs} + resultFormat={query.azureLogAnalytics?.resultFormat} /> )} diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx index eb786c5f209..d59a147e4e6 100644 --- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx @@ -13,6 +13,7 @@ import { mockGetValidLocations, mockResourcesByResourceGroup, } from '../../__mocks__/resourcePickerRows'; +import { selectors } from '../../e2e/selectors'; import ResourcePickerData from '../../resourcePicker/resourcePickerData'; import MetricsQueryEditor from './MetricsQueryEditor'; @@ -74,7 +75,9 @@ describe('MetricsQueryEditor', () => { /> ); - expect(await screen.findByTestId('azure-monitor-metrics-query-editor-with-experimental-ui')).toBeInTheDocument(); + expect( + await screen.findByTestId(selectors.components.queryEditor.metricsQueryEditor.container.input) + ).toBeInTheDocument(); }); it('should show the current resource in the ResourcePicker', async () => { diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.tsx index e86238655cb..e4dc2e2fed1 100644 --- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.tsx @@ -5,6 +5,7 @@ import { EditorRows, EditorRow, EditorFieldGroup } from '@grafana/experimental'; import { multiResourceCompatibleTypes } from '../../azureMetadata'; import type Datasource from '../../datasource'; +import { selectors } from '../../e2e/selectors'; import type { AzureMonitorQuery, AzureMonitorOption, AzureMonitorErrorish, AzureMonitorResource } from '../../types'; import ResourceField from '../ResourceField'; import { ResourceRow, ResourceRowGroup, ResourceRowType } from '../ResourcePicker/types'; @@ -85,7 +86,7 @@ const MetricsQueryEditor = ({ }; return ( - + diff --git a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.test.tsx index 4127b87ba20..74ec7c498d9 100644 --- a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.test.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.test.tsx @@ -7,6 +7,7 @@ import * as ui from '@grafana/ui'; import createMockDatasource from '../../__mocks__/datasource'; import { invalidNamespaceError } from '../../__mocks__/errors'; import createMockQuery from '../../__mocks__/query'; +import { selectors } from '../../e2e/selectors'; import { AzureQueryType } from '../../types'; import QueryEditor from './QueryEditor'; @@ -29,7 +30,9 @@ describe('Azure Monitor QueryEditor', () => { render( {}} onRunQuery={() => {}} />); await waitFor(() => - expect(screen.getByTestId('azure-monitor-metrics-query-editor-with-experimental-ui')).toBeInTheDocument() + expect( + screen.getByTestId(selectors.components.queryEditor.metricsQueryEditor.container.input) + ).toBeInTheDocument() ); }); @@ -42,7 +45,35 @@ describe('Azure Monitor QueryEditor', () => { render( {}} onRunQuery={() => {}} />); await waitFor(() => - expect(screen.queryByTestId('azure-monitor-logs-query-editor-with-experimental-ui')).toBeInTheDocument() + expect(screen.queryByTestId(selectors.components.queryEditor.logsQueryEditor.container.input)).toBeInTheDocument() + ); + }); + + it('renders the ARG query editor when the query type is ARG', async () => { + const mockDatasource = createMockDatasource(); + const mockQuery = { + ...createMockQuery(), + queryType: AzureQueryType.AzureResourceGraph, + }; + + render( {}} onRunQuery={() => {}} />); + await waitFor(() => + expect(screen.queryByTestId(selectors.components.queryEditor.argsQueryEditor.container.input)).toBeInTheDocument() + ); + }); + + it('renders the Traces query editor when the query type is Traces', async () => { + const mockDatasource = createMockDatasource(); + const mockQuery = { + ...createMockQuery(), + queryType: AzureQueryType.AzureTraces, + }; + + render( {}} onRunQuery={() => {}} />); + await waitFor(() => + expect( + screen.queryByTestId(selectors.components.queryEditor.tracesQueryEditor.container.input) + ).toBeInTheDocument() ); }); @@ -69,7 +100,9 @@ describe('Azure Monitor QueryEditor', () => { {}} onRunQuery={() => {}} /> ); await waitFor(() => - expect(screen.getByTestId('azure-monitor-metrics-query-editor-with-experimental-ui')).toBeInTheDocument() + expect( + screen.getByTestId(selectors.components.queryEditor.metricsQueryEditor.container.input) + ).toBeInTheDocument() ); expect(screen.getByText('An error occurred while requesting metadata from Azure Monitor')).toBeInTheDocument(); }); diff --git a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx index 1dcbab5b1a7..9ac7201c0c7 100644 --- a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx @@ -18,6 +18,7 @@ import LogsQueryEditor from '../LogsQueryEditor'; import NewMetricsQueryEditor from '../MetricsQueryEditor/MetricsQueryEditor'; import { QueryHeader } from '../QueryHeader'; import { Space } from '../Space'; +import TracesQueryEditor from '../TracesQueryEditor'; import usePreparedQuery from './usePreparedQuery'; @@ -131,6 +132,18 @@ const EditorForQueryType = ({ /> ); + case AzureQueryType.AzureTraces: + return ( + + ); + default: const type = query.queryType as unknown; return ( diff --git a/public/app/plugins/datasource/azuremonitor/components/QueryHeader.tsx b/public/app/plugins/datasource/azuremonitor/components/QueryHeader.tsx index 77d5b5490ab..3a3c77c81ea 100644 --- a/public/app/plugins/datasource/azuremonitor/components/QueryHeader.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/QueryHeader.tsx @@ -15,6 +15,7 @@ export const QueryHeader = ({ query, onQueryChange }: QueryTypeFieldProps) => { const queryTypes: Array<{ value: AzureQueryType; label: string }> = [ { value: AzureQueryType.AzureMonitor, label: 'Metrics' }, { value: AzureQueryType.LogAnalytics, label: 'Logs' }, + { value: AzureQueryType.AzureTraces, label: 'Traces' }, { value: AzureQueryType.AzureResourceGraph, label: 'Azure Resource Graph' }, ]; diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.test.ts b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.test.ts index c6b32fb71eb..119e9625bba 100644 --- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.test.ts +++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.test.ts @@ -198,12 +198,24 @@ describe('AzureMonitor ResourcePicker utils', () => { }); }); - it('ignores an empty resource URI', () => { + it('updates a resource with a resource URI for Traces', () => { + expect(setResources(createMockQuery(), 'traces', ['/subscription/sub'])).toMatchObject({ + azureTraces: { resources: ['/subscription/sub'] }, + }); + }); + + it('ignores an empty logs resource URI', () => { expect(setResources(createMockQuery(), 'logs', ['/subscription/sub', ''])).toMatchObject({ azureLogAnalytics: { resources: ['/subscription/sub'] }, }); }); + it('ignores an empty traces resource URI', () => { + expect(setResources(createMockQuery(), 'traces', ['/subscription/sub', ''])).toMatchObject({ + azureTraces: { resources: ['/subscription/sub'] }, + }); + }); + it('updates a resource with a resource parameters for Metrics', () => { expect( setResources(createMockQuery(), 'metrics', [ diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.ts b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.ts index 35c834324f7..33e02b5cef8 100644 --- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.ts +++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.ts @@ -169,6 +169,17 @@ export function setResources( }, }; } + if (type === 'traces') { + // Resource URI for Traces + return { + ...query, + azureTraces: { + ...query.azureTraces, + resources: resourcesToStrings(resources).filter((resource) => resource !== ''), + }, + }; + } + // Resource object for metrics const parsedResource = resources.length ? parseResourceDetails(resources[0]) : {}; return { diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filter.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filter.tsx new file mode 100644 index 00000000000..daca2da1125 --- /dev/null +++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filter.tsx @@ -0,0 +1,278 @@ +import { cx } from '@emotion/css'; +import React, { RefCallback, SyntheticEvent, useState } from 'react'; +import { lastValueFrom } from 'rxjs'; + +import { CoreApp, DataFrame, SelectableValue, TimeRange } from '@grafana/data'; +import { AccessoryButton } from '@grafana/experimental'; +import { + HorizontalGroup, + Select, + ButtonSelect, + AsyncMultiSelect, + getSelectStyles, + useTheme2, + Checkbox, +} from '@grafana/ui'; + +import { AzureMonitorQuery, AzureQueryType, AzureTracesFilter } from '../../dataquery.gen'; +import Datasource from '../../datasource'; +import { VariableOptionGroup } from '../../types'; +import { addValueToOptions } from '../../utils/common'; + +export interface FilterProps { + query: AzureMonitorQuery; + datasource: Datasource; + propertyMap: Map; + setPropertyMap: React.Dispatch>>>>; + timeRange: TimeRange; + queryTraceTypes: string[]; + properties: string[]; + variableOptionGroup: VariableOptionGroup; +} + +const onFieldChange = ( + fieldName: Key, + item: Partial, + selected: SelectableValue, + onChange: (item: Partial) => void +) => { + if (fieldName === 'filters') { + item[fieldName] = selected.map((item: SelectableValue) => item.value); + } else { + item[fieldName] = selected.value; + if (fieldName === 'property') { + item.filters = []; + } + } + onChange(item); +}; + +const getTraceProperties = async ( + query: AzureMonitorQuery, + datasource: Datasource, + timeRange: TimeRange, + traceTypes: string[], + propertyMap: Map, + setPropertyMap: React.Dispatch>>>>, + filter?: Partial +): Promise => { + const { azureTraces } = query; + if (!azureTraces) { + return []; + } + + const { resources } = azureTraces; + + if (!resources || !filter) { + return []; + } + + const property = filter.property; + if (!property) { + return []; + } + + const queryString = `let ${property} = toscalar(union isfuzzy=true ${traceTypes.join(',')} + | where $__timeFilter(timestamp) + | summarize count=count() by ${property} + | summarize make_list(pack_all())); + print properties = bag_pack("${property}", ${property});`; + + const results = await lastValueFrom( + datasource.azureLogAnalyticsDatasource.query({ + requestId: 'azure-traces-properties-req', + interval: '', + intervalMs: 0, + scopedVars: {}, + timezone: '', + startTime: 0, + app: CoreApp.Unknown, + targets: [ + { + ...query, + azureLogAnalytics: { + resources, + query: queryString, + }, + queryType: AzureQueryType.LogAnalytics, + }, + ], + range: timeRange, + }) + ); + if (results.data.length > 0) { + const result: DataFrame = results.data[0]; + if (result.fields.length > 0) { + const properties: { [key: string]: Array<{ [key: string]: string | number; count: number }> } = JSON.parse( + result.fields[0].values.toArray()[0] + ); + const values = properties[property].map((value) => { + let label = value[property]; + if (value[property] === '') { + label = ''; + } + return { label: label.toString(), value: value[property].toString(), count: value.count }; + }); + propertyMap.set(property, values); + setPropertyMap(propertyMap); + return values; + } + } + + return []; +}; + +export function makeRenderItem(props: FilterProps) { + function renderItem( + item: Partial, + onChange: (item: Partial) => void, + onDelete: () => void + ) { + return ; + } + + return renderItem; +} + +interface OptionProps { + isFocused: boolean; + isSelected: boolean; + innerProps: JSX.IntrinsicElements['div']; + innerRef: RefCallback; + data: SelectableValue; + selectOption: (data: SelectableValue) => void; +} + +const Option = (props: React.PropsWithChildren) => { + const { data, innerProps, innerRef, isFocused, isSelected } = props; + const theme = useTheme2(); + const styles = getSelectStyles(theme); + + const onClickMultiOption = (e: SyntheticEvent) => { + props.selectOption({ ...data }); + e.stopPropagation(); + e.preventDefault(); + }; + + return ( +
+
+ +
+
+ ); +}; + +const Filter = ( + props: FilterProps & { + item: Partial; + onChange: (item: Partial) => void; + onDelete: () => void; + } +) => { + const { + query, + datasource, + propertyMap, + setPropertyMap, + timeRange, + queryTraceTypes, + properties, + item, + onChange, + onDelete, + variableOptionGroup, + } = props; + const [loading, setLoading] = useState(false); + const [values, setValues] = useState | VariableOptionGroup>>( + addValueToOptions(propertyMap.get(item.property ?? '') ?? [], variableOptionGroup) + ); + const [selected, setSelected] = useState( + item.filters ? item.filters.map((filter) => ({ value: filter, label: filter === '' ? '' : filter })) : [] + ); + + const loadOptions = async () => { + setLoading(true); + if (item.property && item.property !== '') { + const vals = propertyMap.get(item.property ?? ''); + if (!vals) { + const promise = await getTraceProperties( + query, + datasource, + timeRange, + queryTraceTypes, + propertyMap, + setPropertyMap, + item + ); + setValues(addValueToOptions(promise, variableOptionGroup)); + setLoading(false); + return promise; + } else { + setValues(addValueToOptions(vals, variableOptionGroup)); + setLoading(false); + return Promise.resolve(vals); + } + } + const empty: Array> = []; + return Promise.resolve(empty); + }; + + return ( + + + +
+
+ + + + + + + + + + +
+
+ ); +}; + +export default TracesQueryEditor; diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/consts.ts b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/consts.ts new file mode 100644 index 00000000000..001bd0d6181 --- /dev/null +++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/consts.ts @@ -0,0 +1,167 @@ +import { omit } from 'lodash'; + +export const Tables = { + availabilityResults: { label: 'Availablity Results', description: 'Availability test results.' }, + dependencies: { + label: 'Dependencies', + description: 'Calls your application makes to other services such as databases or REST APIs.', + }, + customEvents: { label: 'Custom Events', description: 'Calls to TrackEvent that are inserted to monitor usage.' }, + exceptions: { + label: 'Exceptions', + description: 'Exceptions that are logged via TrackException, or uncaught exceptions.', + }, + pageViews: { label: 'Page Views', description: 'Web client telemetry to create page view reports.' }, + requests: { label: 'Requests', description: 'HTTP requests received by the application.' }, + traces: { + label: 'Traces', + description: + 'Diagnostic logs emitted using TrackTrace and similar methods. Note: Traces are not visualised if the result format is set to Trace', + }, +}; + +// Resource centric tables mapped to legacy tables +export const tables = { + AppAvailabilityResults: 'availabilityResults', + AppDependencies: 'dependencies', + AppEvents: 'events', + AppExceptions: 'exceptions', + AppPageViews: 'pageViews', + AppRequests: 'requests', + AppTraces: 'traces', +}; + +// Properties to omit when generating the attributes bag +export const attributesOmit = [ + 'operationId', + 'duration', + 'id', + 'name', + 'problemId', + 'operation_ParentId', + 'timestamp', + 'customDimensions', + 'operation_Name', +]; + +// Common resource centric properties mapped to legacy property names +export const common = { + appId: 'ResourceGUID', + application_Version: 'AppVersion', + appName: '_ResourceId', + client_Browser: 'ClientBrowser', + client_City: 'ClientCity', + client_CountryOrRegion: 'ClientCountryOrRegion', + client_IP: 'ClientIP', + client_Model: 'ClientModel', + client_OS: 'ClientOS', + client_StateOrProvince: 'ClientStateOrProvince', + client_Type: 'ClientType', + cloud_RoleInstance: 'AppRoleInstance', + cloud_RoleName: 'AppRoleName', + customDimensions: 'Properties', + customMeasurements: 'Measurements', + duration: 'DurationMs', + id: 'Id', + iKey: 'IKey', + itemCount: 'ItemCount', + itemId: '_ItemId', + itemType: 'Type', + name: 'Name', + operation_Id: 'OperationId', + operation_Name: 'OperationName', + operation_ParentId: 'OperationParentId', + operation_SyntheticSource: 'OperationSyntheticSource', + performanceBucket: 'PerformanceBucket', + sdkVersion: 'SDKVersion', + session_Id: 'SessionId', + success: 'Success', + timestamp: 'TimeGenerated', + user_AccountId: 'UserAccountId', + user_AuthenticatedId: 'UserAuthenticatedId', + user_Id: 'UserId', +}; + +// Additional properties for availabilityResults +export const availabilityResultsSchema = { + ...common, + location: 'Location', + message: 'Message', + size: 'Size', +}; + +// Additional properties for dependencies +export const dependenciesSchema = { + ...common, + data: 'Data', + resultCode: 'ResultCode', + target: 'Target', + type: 'DependencyType', +}; + +// Additional properties for events +export const eventsSchema = omit(common, ['duration', 'id', 'success', 'performanceBucket']); + +// Additional properties for pageVies +export const pageViewsSchema = omit( + { + ...common, + url: 'Url', + }, + ['success'] +); + +// Additional properties for requests +export const requestsSchema = { + resultCode: 'ResultCode', + source: 'Source', + url: 'Url', +}; + +// Additional properties for exceptions +export const exceptionsSchema = omit( + { + ...common, + assembly: 'Assembly', + details: 'Details', + handledAt: 'HandledAt', + innermostAssembly: 'InnermostAssembly', + innermostMessage: 'InnermostMessage', + innermostMethod: 'InnermostMethod', + innermostType: 'InnermostType', + message: 'Message', + method: 'Method', + outerAssembly: 'OuterAssembly', + outerMessage: 'OuterMessage', + outerMethod: 'OuterMethod', + outerType: 'OuterType', + problemId: 'ProblemId', + severityLevel: 'SeverityLevel', + type: 'ExceptionType', + }, + ['duration', 'id', 'name', 'performanceBucket', 'success'] +); + +// Additional properties for traces +export const tracesSchema = omit( + { + message: 'Message', + severityLevel: 'SeverityLevel', + }, + ['duration', 'id', 'name', 'performanceBucket', 'success'] +); + +export const tablesSchema: { [key: string]: { [key: string]: string } } = { + availabilityResults: availabilityResultsSchema, + dependencies: dependenciesSchema, + customEvents: eventsSchema, + exceptions: exceptionsSchema, + pageViews: pageViewsSchema, + requests: requestsSchema, + traces: tracesSchema, +}; + +export const tableTags = Object.entries(tablesSchema).reduce( + (val, [k, v]) => ({ ...val, [k]: Object.keys(omit(v, attributesOmit)).join(',') }), + {} +); diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/index.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/index.tsx new file mode 100644 index 00000000000..a052a53085f --- /dev/null +++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/index.tsx @@ -0,0 +1 @@ +export { default } from './TracesQueryEditor'; diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/setQueryValue.ts b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/setQueryValue.ts new file mode 100644 index 00000000000..fb9eaa86680 --- /dev/null +++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/setQueryValue.ts @@ -0,0 +1,41 @@ +import { AzureMonitorQuery, AzureTracesFilter, ResultFormat } from '../../types'; + +export function setQueryOperationId(query: AzureMonitorQuery, operationId?: string): AzureMonitorQuery { + return { + ...query, + azureTraces: { + ...query.azureTraces, + operationId, + }, + }; +} + +export function setFormatAs(query: AzureMonitorQuery, formatAs: ResultFormat): AzureMonitorQuery { + return { + ...query, + azureTraces: { + ...query.azureTraces, + resultFormat: formatAs, + }, + }; +} + +export function setTraceTypes(query: AzureMonitorQuery, traceTypes: string[]): AzureMonitorQuery { + return { + ...query, + azureTraces: { + ...query.azureTraces, + traceTypes, + }, + }; +} + +export function setFilters(query: AzureMonitorQuery, filters: AzureTracesFilter[]): AzureMonitorQuery { + return { + ...query, + azureTraces: { + ...query.azureTraces, + filters, + }, + }; +} diff --git a/public/app/plugins/datasource/azuremonitor/dataquery.cue b/public/app/plugins/datasource/azuremonitor/dataquery.cue index 747d323aa41..ed649cf642c 100644 --- a/public/app/plugins/datasource/azuremonitor/dataquery.cue +++ b/public/app/plugins/datasource/azuremonitor/dataquery.cue @@ -43,6 +43,8 @@ composableKinds: DataQuery: { azureLogAnalytics?: #AzureLogsQuery // Azure Resource Graph sub-query properties. azureResourceGraph?: #AzureResourceGraphQuery + // Application Insights Traces sub-query properties. + azureTraces?: #AzureTracesQuery // @deprecated Legacy template variable support. grafanaTemplateVariableFn?: #GrafanaTemplateVariableQuery @@ -56,7 +58,7 @@ composableKinds: DataQuery: { } @cuetsy(kind="interface") @grafana(TSVeneer="type") // Defines the supported queryTypes. GrafanaTemplateVariableFn is deprecated - #AzureQueryType: "Azure Monitor" | "Azure Log Analytics" | "Azure Resource Graph" | "Azure Subscriptions" | "Azure Resource Groups" | "Azure Namespaces" | "Azure Resource Names" | "Azure Metric Names" | "Azure Workspaces" | "Azure Regions" | "Grafana Template Variable Function" @cuetsy(kind="enum", memberNames="AzureMonitor|LogAnalytics|AzureResourceGraph|SubscriptionsQuery|ResourceGroupsQuery|NamespacesQuery|ResourceNamesQuery|MetricNamesQuery|WorkspacesQuery|LocationsQuery|GrafanaTemplateVariableFn") + #AzureQueryType: "Azure Monitor" | "Azure Log Analytics" | "Azure Resource Graph" | "Azure Traces" | "Azure Subscriptions" | "Azure Resource Groups" | "Azure Namespaces" | "Azure Resource Names" | "Azure Metric Names" | "Azure Workspaces" | "Azure Regions" | "Grafana Template Variable Function" @cuetsy(kind="enum", memberNames="AzureMonitor|LogAnalytics|AzureResourceGraph|AzureTraces|SubscriptionsQuery|ResourceGroupsQuery|NamespacesQuery|ResourceNamesQuery|MetricNamesQuery|WorkspacesQuery|LocationsQuery|GrafanaTemplateVariableFn") #AzureMetricQuery: { // Array of resource URIs to be queried. @@ -121,7 +123,32 @@ composableKinds: DataQuery: { resource?: string } @cuetsy(kind="interface") - #ResultFormat: "table" | "time_series" @cuetsy(kind="enum", memberNames="Table|TimeSeries") + // Application Insights Traces sub-query properties + #AzureTracesQuery: { + // Specifies the format results should be returned as. + resultFormat?: #ResultFormat + // Array of resource URIs to be queried. + resources?: [...string] + // Operation ID. Used only for Traces queries. + operationId?: string + // Types of events to filter by. + traceTypes?: [...string] + // Filters for property values. + filters?: [...#AzureTracesFilter] + // KQL query to be executed. + query?: string + } @cuetsy(kind="interface") + + #AzureTracesFilter: { + // Property name, auto-populated based on available traces. + property: string + // Comparison operator to use. Either equals or not equals. + operation: string + // Values to filter by. + filters: [...string] + } @cuetsy(kind="interface") + + #ResultFormat: "table" | "time_series" | "trace" @cuetsy(kind="enum", memberNames="Table|TimeSeries|Trace") #AzureResourceGraphQuery: { // Azure Resource Graph KQL query to be executed. diff --git a/public/app/plugins/datasource/azuremonitor/dataquery.gen.ts b/public/app/plugins/datasource/azuremonitor/dataquery.gen.ts index 8e65899f900..1a33491b3f5 100644 --- a/public/app/plugins/datasource/azuremonitor/dataquery.gen.ts +++ b/public/app/plugins/datasource/azuremonitor/dataquery.gen.ts @@ -25,6 +25,10 @@ export interface AzureMonitorQuery extends common.DataQuery { * Azure Resource Graph sub-query properties. */ azureResourceGraph?: AzureResourceGraphQuery; + /** + * Application Insights Traces sub-query properties. + */ + azureTraces?: AzureTracesQuery; /** * @deprecated Legacy template variable support. */ @@ -60,6 +64,7 @@ export const defaultAzureMonitorQuery: Partial = { export enum AzureQueryType { AzureMonitor = 'Azure Monitor', AzureResourceGraph = 'Azure Resource Graph', + AzureTraces = 'Azure Traces', GrafanaTemplateVariableFn = 'Grafana Template Variable Function', LocationsQuery = 'Azure Regions', LogAnalytics = 'Azure Log Analytics', @@ -184,9 +189,65 @@ export const defaultAzureLogsQuery: Partial = { resources: [], }; +/** + * Application Insights Traces sub-query properties + */ +export interface AzureTracesQuery { + /** + * Filters for property values. + */ + filters?: Array; + /** + * Operation ID. Used only for Traces queries. + */ + operationId?: string; + /** + * KQL query to be executed. + */ + query?: string; + /** + * Array of resource URIs to be queried. + */ + resources?: Array; + /** + * Specifies the format results should be returned as. + */ + resultFormat?: ResultFormat; + /** + * Types of events to filter by. + */ + traceTypes?: Array; +} + +export const defaultAzureTracesQuery: Partial = { + filters: [], + resources: [], + traceTypes: [], +}; + +export interface AzureTracesFilter { + /** + * Values to filter by. + */ + filters: Array; + /** + * Comparison operator to use. Either equals or not equals. + */ + operation: string; + /** + * Property name, auto-populated based on available traces. + */ + property: string; +} + +export const defaultAzureTracesFilter: Partial = { + filters: [], +}; + export enum ResultFormat { Table = 'table', TimeSeries = 'time_series', + Trace = 'trace', } export interface AzureResourceGraphQuery { diff --git a/public/app/plugins/datasource/azuremonitor/datasource.ts b/public/app/plugins/datasource/azuremonitor/datasource.ts index 36ba7dc8e70..2f6c444c25f 100644 --- a/public/app/plugins/datasource/azuremonitor/datasource.ts +++ b/public/app/plugins/datasource/azuremonitor/datasource.ts @@ -90,7 +90,8 @@ export default class Datasource extends DataSourceWithBackend> = Array.from(byType.entries()).map(([queryType, req]) => { - const ds = this.pseudoDatasource[queryType]; + const mappedQueryType = queryType === AzureQueryType.AzureTraces ? AzureQueryType.LogAnalytics : queryType; + const ds = this.pseudoDatasource[mappedQueryType]; if (!ds) { throw new Error('Data source not created for query type ' + queryType); } @@ -183,7 +184,8 @@ export default class Datasource extends DataSourceWithBackend { private resourcePath: string; diff --git a/public/app/plugins/datasource/azuremonitor/types/query.ts b/public/app/plugins/datasource/azuremonitor/types/query.ts index 34cabe059a6..0c4287928cd 100644 --- a/public/app/plugins/datasource/azuremonitor/types/query.ts +++ b/public/app/plugins/datasource/azuremonitor/types/query.ts @@ -5,8 +5,10 @@ export { AzureMetricQuery, AzureLogsQuery, AzureResourceGraphQuery, + AzureTracesQuery, AzureMonitorResource, AzureMetricDimension, + AzureTracesFilter, ResultFormat, } from '../dataquery.gen'; diff --git a/public/app/plugins/datasource/azuremonitor/types/types.ts b/public/app/plugins/datasource/azuremonitor/types/types.ts index 0fb66cd39ae..b727b37a9a0 100644 --- a/public/app/plugins/datasource/azuremonitor/types/types.ts +++ b/public/app/plugins/datasource/azuremonitor/types/types.ts @@ -3,12 +3,13 @@ import { DataSourceJsonData, DataSourceSettings, PanelData, + SelectableValue, TableData, } from '@grafana/data'; import Datasource from '../datasource'; -import { AzureMonitorQuery } from './query'; +import { AzureMonitorQuery, ResultFormat } from './query'; export type AzureDataSourceSettings = DataSourceSettings; export type AzureDataSourceInstanceSettings = DataSourceInstanceSettings; @@ -170,6 +171,14 @@ export interface AzureQueryEditorFieldProps { setError: (source: string, error: AzureMonitorErrorish | undefined) => void; } +export interface FormatAsFieldProps extends AzureQueryEditorFieldProps { + inputId: string; + options: Array>; + defaultValue: ResultFormat; + setFormatAs: (query: AzureMonitorQuery, formatAs: ResultFormat) => AzureMonitorQuery; + resultFormat?: ResultFormat; +} + export interface AzureResourceSummaryItem { subscriptionName: string; resourceGroupName: string | undefined; diff --git a/public/app/plugins/datasource/azuremonitor/utils/common.ts b/public/app/plugins/datasource/azuremonitor/utils/common.ts index 59e6f1d9b27..46b4e5f52e7 100644 --- a/public/app/plugins/datasource/azuremonitor/utils/common.ts +++ b/public/app/plugins/datasource/azuremonitor/utils/common.ts @@ -1,6 +1,6 @@ import { map } from 'lodash'; -import { rangeUtil } from '@grafana/data'; +import { rangeUtil, SelectableValue } from '@grafana/data'; import { VariableWithMultiSupport } from 'app/features/variables/types'; import TimegrainConverter from '../time_grain_converter'; @@ -23,7 +23,7 @@ export const findOptions = (options: AzureMonitorOption[], values: string[] = [] export const toOption = (v: { text: string; value: string }) => ({ value: v.value, label: v.text }); export const addValueToOptions = ( - values: AzureMonitorOption[], + values: Array, variableOptionGroup: VariableOptionGroup, value?: string ) => {