AzureMonitor: Application Insights Traces (#64859)

* Build out barebones Traces editor

- Add Traces query type and operation ID prop to query type
- Add necessary header types
- Update resource picker to appropriately work with traces query type
- Build out TracesQueryEditor component
- Include logic to retrieve operationId's for AI Workspaces
- Add backend route mapping
- Update macro to use timestamp as default time field for traces

* AzureMonitor: Traces - Response parsing (#65442)

* Update FormatAsField component

- Add trace ResultFormat type
- Generalise FormatAsField component
- Add component to TracesQueryEditor
- Remove duplicate code in setQueryValue

* Add custom filter function to improve performance

* Add basic conversion for logs to trace

- Add serviceTags converter
- Pass through required parameters (queryType and resultFormat)
- Appropriately set visualisation

* Update parsing to also fill trace tags

- Add constant values for each table schema (include legacy mapping for now if needed)
- Add constant for list of table tags
- Set the foundation for dynamic query building
- Update query to build tags value
- Appropriately set operationName
- Update tagsConverter to filter empty values

* Fix lint and test issues

* AzureMonitor: Traces - Data links (#65566)

* Add portal link for traces

- Pull out necessary values (itemId and itemType)
- Appropriately construct
- Fix ordering

* Set default format as value

- Also set default visualisation

* Fix event schema

* Set default formatAsField value

* Include logs link on traces results

- Adapt config links to allow custom title to be set

* Correctly set operationId for query

* Update backend types

- Include OperationID in query
- Pass forward datasource name and UID

* Ensure setTime doesn't consistently get called if operationID is defined

* Add explore link

- Update util functions to allow setting custom datalinks

* Fix tests

* AzureMonitor: Traces - Query and Editor updates (#66076)

* Add initial query

- Will query the resource as soon as a resource has been selected
- Updates the data links for the query without operationId
- Remove initial operationId query and timeRange dependency
- Update query building

* Add entirely separate traces query property

- Update shared types (also including future types for Azure traces)
- Update backend log analytics datasource to accept both azureLogAnalytics and azureTraces queries
- Update backend specific types
- Update frontend datasource for new properties
- Update mock query

* Update FormatAsField to be entirely generic

* Update query building to be done in backend

- Add required mappings in backend
- Update frontend querying

* Fix query and explore data link

* Add trace type selection

* Better method for setting explore link

* Fix operationId updating

* Run go mod tidy

* Unnecessary changes

* Fix tests

* AzureMonitor: Traces - Add correlation API support (#65855)

Add correlation API support

- Add necessary types
- Add correlation API request when conditions are met
- Update query

* Fix property from merge

* AzureMonitor: Traces - Filtering (#66303)

* Add initial query

- Will query the resource as soon as a resource has been selected
- Updates the data links for the query without operationId
- Remove initial operationId query and timeRange dependency
- Update query building

* Add entirely separate traces query property

- Update shared types (also including future types for Azure traces)
- Update backend log analytics datasource to accept both azureLogAnalytics and azureTraces queries
- Update backend specific types
- Update frontend datasource for new properties
- Update mock query

* Update FormatAsField to be entirely generic

* Update query building to be done in backend

- Add required mappings in backend
- Update frontend querying

* Fix query and explore data link

* Add trace type selection

* Better method for setting explore link

* Fix operationId updating

* Run go mod tidy

* Unnecessary changes

* Fix tests

* Start building out Filters component

- Configure component to query for Filter property values when a filter property is set
- Add setFilters function
- Add typing to tablesSchema
- Use component in TracesQueryEditor

* Update Filters

- Asynchronously pull property options
- Setup list of Filter components

* Update filters component

- Remove unused imports
- Have local filters state and query filters
- Correctly set filters values
- Don't update query every time a filter property changes (not performant)

* Update properties query

- Use current timeRange
- Get count to provide informative labels

* Reset map when time changes

* Add operation selection

* Reset filters when property changes

* Appropriate label name for empty values

* Add filtering to query

* Update filter components

- Fix rendering issue
- Correctly compare and update timeRange
- Split out files for simplicity

* Add checkbox option to multiselect

- Add custom option component
- Correctly call onChange
- Add variableOptionGroup for template variable selection

* Fix adding template vars

* Improve labels and refresh labels on query prop changes

* AzureMonitor: Traces - Testing (#66474)

* Select ds for template variable interpolation

* Update az logs ds tests

- Add templateVariables test
- Add filter test
- Update mock
- Remove anys

* Update QueryEditor test

- Update mocks with timeSrv for log analytics datasource
- Fix query mock
- Use appropriate and consistent selectors

* Add TracesQueryEditor test

- Update resourcePickerRows mock to include app insights resources
- Remove comments and extra new line

* Add FormatAsField test

- Remove unneeded condition

* Update resourcePicker utils test

* Don't hide selected options in filters

* Fix multi-selection on filters

* Add TraceTypeField test

- Add test file
- Update selectors (remove copy/paste mistake)
- Update placeholder text for select and add label

* Add basic filters test

* Begin filters test

* Update filters test

* Add final tests and simplify/generalise addFilter helper

* Minor update to datasource test

* Update macros test

* Update selectors in tests

* Add response-table-frame tests

* Add datasource tests

- Use sorting where JSON models are inconsistent
- Update filters clause
- Dedupe tags
- Correct operationId conditions

* Don't set a default value for blurInputOnSelect

* Simplify datasource test

* Update to use CheckGoldenJSON utils

- Update with generated frame files
- Remove redundant expected frame code
- Update all usages

* Fix lint

* AzureMonitor: Traces feedback (#67292)

* Filter traces if the visualisation is set to trace

- Update build query logic
- Added additional test cases
- Return an error if the traces type is set by itself with the trace visualisation
- Add descriptions to event types
- Update tests

* Fix bug for error displaying traces

* Update mappings and add error field

- Update tests
- Remove unnecessary comments

* Switch location of Operation ID field

* Re-order fields

* Update link title

* Update label for event type selection

* Update correct link title

* Update logs datalink to link to Azure Logs in explore

* Fix lint
This commit is contained in:
Andreas Christou 2023-04-27 20:24:11 +01:00 committed by GitHub
parent 60c4e71962
commit 63383ef545
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
83 changed files with 7586 additions and 561 deletions

View File

@ -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"],

View File

@ -93,6 +93,7 @@ export function SelectBase<T>({
'aria-label': ariaLabel,
autoFocus = false,
backspaceRemovesValue = true,
blurInputOnSelect,
cacheOptions,
className,
closeMenuOnSelect = true,
@ -213,6 +214,7 @@ export function SelectBase<T>({
'aria-label': ariaLabel,
autoFocus,
backspaceRemovesValue,
blurInputOnSelect,
captureMenuScroll: false,
closeMenuOnSelect,
// We don't want to close if we're actually scrolling the menu

View File

@ -23,6 +23,7 @@ export interface SelectCommonProps<T> {
/** 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` */

View File

@ -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
}

View File

@ -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},
},

View File

@ -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"`

View File

@ -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")
}

View File

@ -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)
}
})
}

View File

@ -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) {

View File

@ -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

View File

@ -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
}

View File

@ -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:

View File

@ -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)

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)
})
}
}

View File

@ -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{}
}

View File

@ -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{
{

View File

@ -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,

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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"
]
]
}
}
]
}

View File

@ -0,0 +1,5 @@
// 🌟 This was machine generated. Do not edit. 🌟
// 🌟 This was machine generated. Do not edit. 🌟
{
"status": 200
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
]
}
}
]
}

View File

@ -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
]
}
]
}
}
]
}

View File

@ -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"
]
]
}
}
]
}

View File

@ -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"
]
]
}
]
}

View File

@ -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"
]
]
}
}
]
}

View File

@ -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"
]
]
}
}
]
}

View File

@ -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"
]
]
}
]
}

View File

@ -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"
]
]
}
}
]
}

View File

@ -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"
]
]
}
}
]
}

29
pkg/tsdb/azuremonitor/testdata/utils.go vendored Normal file
View File

@ -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)
}

View File

@ -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"`

View File

@ -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<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
const contextSrv = new ContextSrv();
const timeSrv = new TimeSrv(contextSrv);
export default function createMockDatasource(overrides?: DeepPartial<Datasource>) {
// 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<Datasource>
azureLogAnalyticsDatasource: {
getKustoSchema: () => Promise.resolve(),
getDeprecatedDefaultWorkSpace: () => 'defaultWorkspaceId',
timeSrv,
},
resourcePickerData: {
getSubscriptions: () => jest.fn().mockResolvedValue([]),

View File

@ -27,6 +27,16 @@ export default function createMockQuery(overrides?: Partial<AzureMonitorQuery>):
...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',

View File

@ -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 => [

View File

@ -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<AzureLogsQuery> = {};
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<AzureTracesQuery> = {};
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,
},
],
});
});
});
});

View File

@ -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<AzureDataSourceJsonData>) {
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;
}
/*

View File

@ -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(<FormatAsField {...props} resultFormat={query.azureTraces.resultFormat} query={query} />);
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(
<FormatAsField {...props} resultFormat={query.azureTraces.resultFormat} options={shortOptions} query={query} />
);
const newQuery = {
...query,
azureTraces: { ...query.azureTraces, resultFormat: props.defaultValue },
};
expect(props.onQueryChange).toHaveBeenCalledWith(newQuery);
rerender(
<FormatAsField
{...props}
resultFormat={newQuery.azureTraces.resultFormat}
options={shortOptions}
query={newQuery}
/>
);
expect(screen.getByText('Table')).toBeInTheDocument();
expect(screen.queryByText('Trace')).not.toBeInTheDocument();
});
});

View File

@ -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<ResultFormat>) => {
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 (
<Field label="Format as" data-testid={selectors.components.queryEditor.logsQueryEditor.formatSelection.input}>
<Select
inputId={`${inputId}-format-as-field`}
value={resultFormat ?? defaultValue}
onChange={handleChange}
options={options}
width={38}
/>
</Field>
);
};
export default FormatAsField;

View File

@ -1,46 +0,0 @@
import React, { useCallback, useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
import { selectors } from '../../e2e/selectors';
import { AzureQueryEditorFieldProps, ResultFormat } from '../../types';
import { Field } from '../Field';
import { setFormatAs } from './setQueryValue';
const FORMAT_OPTIONS: Array<SelectableValue<ResultFormat>> = [
{ label: 'Time series', value: ResultFormat.TimeSeries },
{ label: 'Table', value: ResultFormat.Table },
];
const FormatAsField = ({ query, variableOptionGroup, onQueryChange }: AzureQueryEditorFieldProps) => {
const options = useMemo(() => [...FORMAT_OPTIONS, variableOptionGroup], [variableOptionGroup]);
const handleChange = useCallback(
(change: SelectableValue<ResultFormat>) => {
const { value } = change;
if (!value) {
return;
}
const newQuery = setFormatAs(query, value);
onQueryChange(newQuery);
},
[onQueryChange, query]
);
return (
<Field label="Format as" data-testid={selectors.components.queryEditor.logsQueryEditor.formatSelection.input}>
<Select
inputId="azure-monitor-logs-workspaces-field"
value={query.azureLogAnalytics?.resultFormat}
onChange={handleChange}
options={options}
width={38}
/>
</Field>
);
};
export default FormatAsField;

View File

@ -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' });

View File

@ -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 (
<span data-testid="azure-monitor-logs-query-editor-with-experimental-ui">
<span data-testid={selectors.components.queryEditor.logsQueryEditor.container.input}>
<EditorRows>
<EditorRow>
<EditorFieldGroup>
@ -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}
/>
)}

View File

@ -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 () => {

View File

@ -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 (
<span data-testid="azure-monitor-metrics-query-editor-with-experimental-ui">
<span data-testid={selectors.components.queryEditor.metricsQueryEditor.container.input}>
<EditorRows>
<EditorRow>
<EditorFieldGroup>

View File

@ -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(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} 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(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} 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(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} 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(<QueryEditor query={mockQuery} datasource={mockDatasource} onChange={() => {}} onRunQuery={() => {}} />);
await waitFor(() =>
expect(
screen.queryByTestId(selectors.components.queryEditor.tracesQueryEditor.container.input)
).toBeInTheDocument()
);
});
@ -69,7 +100,9 @@ describe('Azure Monitor QueryEditor', () => {
<QueryEditor query={createMockQuery()} datasource={mockDatasource} onChange={() => {}} 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();
});

View File

@ -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 (
<TracesQueryEditor
subscriptionId={subscriptionId}
query={query}
datasource={datasource}
onChange={onChange}
variableOptionGroup={variableOptionGroup}
setError={setError}
/>
);
default:
const type = query.queryType as unknown;
return (

View File

@ -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' },
];

View File

@ -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', [

View File

@ -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 {

View File

@ -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<string, SelectableValue[]>;
setPropertyMap: React.Dispatch<React.SetStateAction<Map<string, Array<SelectableValue<string>>>>>;
timeRange: TimeRange;
queryTraceTypes: string[];
properties: string[];
variableOptionGroup: VariableOptionGroup;
}
const onFieldChange = <Key extends keyof AzureTracesFilter>(
fieldName: Key,
item: Partial<AzureTracesFilter>,
selected: SelectableValue<AzureTracesFilter[Key]>,
onChange: (item: Partial<AzureTracesFilter>) => void
) => {
if (fieldName === 'filters') {
item[fieldName] = selected.map((item: SelectableValue<string>) => 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<string, SelectableValue[]>,
setPropertyMap: React.Dispatch<React.SetStateAction<Map<string, Array<SelectableValue<string>>>>>,
filter?: Partial<AzureTracesFilter>
): Promise<SelectableValue[]> => {
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 = '<Empty>';
}
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<AzureTracesFilter>,
onChange: (item: Partial<AzureTracesFilter>) => void,
onDelete: () => void
) {
return <Filter {...props} item={item} onChange={onChange} onDelete={onDelete} />;
}
return renderItem;
}
interface OptionProps {
isFocused: boolean;
isSelected: boolean;
innerProps: JSX.IntrinsicElements['div'];
innerRef: RefCallback<HTMLDivElement>;
data: SelectableValue<string>;
selectOption: (data: SelectableValue<string>) => void;
}
const Option = (props: React.PropsWithChildren<OptionProps>) => {
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 (
<div
ref={innerRef}
className={cx(
styles.option,
isFocused && styles.optionFocused,
isSelected && styles.optionSelected,
data.isDisabled && styles.optionDisabled
)}
{...innerProps}
aria-label="Select option"
title={data.title}
onClick={onClickMultiOption}
>
<div className={styles.optionBody}>
<Checkbox value={isSelected} label={data.label ? `${data.label} - (${data.count})` : ''} />
</div>
</div>
);
};
const Filter = (
props: FilterProps & {
item: Partial<AzureTracesFilter>;
onChange: (item: Partial<AzureTracesFilter>) => 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<Array<SelectableValue<string> | VariableOptionGroup>>(
addValueToOptions(propertyMap.get(item.property ?? '') ?? [], variableOptionGroup)
);
const [selected, setSelected] = useState<SelectableValue[]>(
item.filters ? item.filters.map((filter) => ({ value: filter, label: filter === '' ? '<Empty>' : 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<SelectableValue<string>> = [];
return Promise.resolve(empty);
};
return (
<HorizontalGroup spacing="none">
<Select
menuShouldPortal
placeholder="Property"
value={item.property ? { value: item.property, label: item.property } : null}
options={addValueToOptions(
properties.map((type) => ({ label: type, value: type })),
variableOptionGroup
)}
onChange={(e) => onFieldChange('property', item, e, onChange)}
width={25}
/>
<ButtonSelect<string>
placeholder="Operator"
value={item.operation ? { label: item.operation === 'eq' ? '=' : '!=', value: item.operation } : undefined}
options={[
{ label: '=', value: 'eq' },
{ label: '!=', value: 'ne' },
]}
onChange={(e) => onFieldChange('operation', item, e, onChange)}
defaultValue={'eq'}
/>
<AsyncMultiSelect
blurInputOnSelect={false}
menuShouldPortal
placeholder="Value"
value={selected}
loadOptions={loadOptions}
isLoading={loading}
onOpenMenu={loadOptions}
onChange={(e: Array<SelectableValue<string>>) => setSelected(e)}
width={35}
defaultOptions={values}
isClearable
components={{ Option }}
closeMenuOnSelect={false}
onCloseMenu={() => onFieldChange('filters', item, selected, onChange)}
hideSelectedOptions={false}
/>
<AccessoryButton aria-label="Remove" icon="times" variant="secondary" onClick={onDelete} type="button" />
</HorizontalGroup>
);
};
export default Filter;

View File

@ -0,0 +1,411 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
import React from 'react';
import { of } from 'rxjs';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { ArrayVector, CoreApp } from '@grafana/data';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
import { AzureQueryType } from '../../dataquery.gen';
import Datasource from '../../datasource';
import { AzureMonitorQuery } from '../../types';
import Filters from './Filters';
import { setFilters } from './setQueryValue';
const variableOptionGroup = {
label: 'Template variables',
options: [],
};
let user: UserEvent;
let mockDatasource: Datasource;
const onQueryChange = jest.fn();
const addFilter = async (
mockQuery: AzureMonitorQuery,
filter: {
property: string;
operation: string;
index: number;
filters: Array<{
count: number;
value: string;
}>;
},
rerender: (ui: React.ReactElement) => void
) => {
const { property, operation, index } = filter;
const resultVector = new ArrayVector([
`{"${property}":[${filter.filters.map(({ count, value }) => `{"${property}":"${value}", "count":${count}}`)}]}`,
]);
mockDatasource.azureLogAnalyticsDatasource.query = jest.fn().mockReturnValue(
of({
data: [
{
refId: 'A',
meta: {
typeVersion: [0, 0],
custom: {
azureColumnTypes: ['dynamic'],
},
},
fields: [
{
name: 'properties',
type: 'string',
typeInfo: {
frame: 'string',
nullable: true,
},
config: {
links: [
{
title: 'View in Azure Portal',
targetBlank: true,
url: 'https://portal.azure.com/#blade/Microsoft_OperationsManagementSuite_Workspace/AnalyticsBlade/initiator/AnalyticsShareLinkToQuery/isQueryEditorVisible/true/scope/%7B%22resources%22%3A%5B%7B%22resourceId%22%3A%22%2Fsubscriptions%2F44693801-6ee6-49de-9b2d-9106972f9572%2FresourceGroups%2Fcloud-datasources%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2FAppInsightsTestData%22%7D%5D%7D/query/H4sIAAAAAAAA%2F3zPz0rDQBAG8HufYuglu2ChTQtqa3wIEQ+KhEk66tD9x86skuDDS+qthF7m8DG%2F+RhHCpiS4x6VY2hfKAvHAA1olB4dZlPCFLB8lHEcGs2FAL+RHXbsWIcnkuJUFgC%2F8PNFmeCtUvYkij5V7%2FDYwBGVpshU9brerta71aZ+3tztt%2FV+d%2F9aWcBwvFAPV9Ttvzo3SvEeM48EfSxBm%2FM0Frph7q0L4vFErWNRk7A%2FteicsdYeFgApc1BIOSbKyiTQQIef7bRmljOHlzdzdfbwFwAA%2F%2F8vPrTNXwEAAA==/isQueryBase64Compressed/true/timespanInIsoFormat/P1D',
},
],
},
values: resultVector,
entities: {},
},
],
length: 1,
},
],
state: 'Done',
})
);
const operationLabel = operation === 'eq' ? '=' : '!=';
const addFilter = await screen.findByLabelText('Add');
await act(() => {
userEvent.click(addFilter);
if (mockQuery.azureTraces?.filters && mockQuery.azureTraces.filters.length < 1) {
expect(onQueryChange).not.toHaveBeenCalled();
}
});
await waitFor(() => expect(screen.getByText('Property')).toBeInTheDocument());
const propertySelect = await screen.findByText('Property');
selectOptionInTest(propertySelect, property);
await waitFor(() => expect(screen.getByText(property)).toBeInTheDocument());
await waitFor(() => expect(screen.getByText('Property')).toBeInTheDocument());
const operationSelect = await screen.getAllByText('=');
selectOptionInTest(operationSelect[index], operationLabel);
await waitFor(() => expect(screen.getByText(operationLabel)).toBeInTheDocument());
const valueSelect = await screen.findByText('Value');
await waitFor(() => user.click(valueSelect));
const query = `let ${property} = toscalar(union isfuzzy=true ${mockQuery.azureTraces?.traceTypes?.join(',')}
| where $__timeFilter(timestamp)
| summarize count=count() by ${property}
| summarize make_list(pack_all()));
print properties = bag_pack("${property}", ${property});`;
expect(mockDatasource.azureLogAnalyticsDatasource.query).toHaveBeenCalledWith(
expect.objectContaining({
requestId: 'azure-traces-properties-req',
interval: '',
intervalMs: 0,
scopedVars: {},
timezone: '',
startTime: 0,
app: CoreApp.Unknown,
targets: [
{
...mockQuery,
azureLogAnalytics: {
resources: mockQuery.azureTraces?.resources,
query,
},
queryType: AzureQueryType.LogAnalytics,
},
],
})
);
const values = [];
for (const currFilter of filter.filters) {
const label = `${currFilter.value} - (${currFilter.count})`;
await waitFor(() => expect(screen.getByText(label)).toBeInTheDocument());
selectOptionInTest(valueSelect, label);
await waitFor(() => expect(screen.getByText(currFilter.value)).toBeInTheDocument());
values.push(currFilter.value);
}
if (mockQuery.azureTraces?.filters && mockQuery.azureTraces.filters.length === 0) {
expect(onQueryChange).not.toHaveBeenCalled();
}
const newQuery = setFilters(mockQuery, [
...(mockQuery.azureTraces?.filters ?? []),
{ property, operation, filters: values },
]);
await waitFor(() => {
userEvent.type(valueSelect, '{Escape}');
expect(onQueryChange).toHaveBeenCalledWith(newQuery);
});
rerender(
<Filters
datasource={mockDatasource}
onQueryChange={onQueryChange}
query={newQuery}
setError={jest.fn()}
variableOptionGroup={variableOptionGroup}
/>
);
return newQuery;
};
describe(`Traces Filters`, () => {
beforeEach(() => {
mockDatasource = createMockDatasource();
user = userEvent.setup();
});
it('should render a trace filter', async () => {
let mockQuery = createMockQuery();
mockQuery.azureTraces = {
...mockQuery.azureTraces,
filters: [
{
filters: ['test-filter'],
operation: 'eq',
property: 'test-property',
},
],
};
render(
<Filters
subscriptionId="123"
query={mockQuery}
onQueryChange={onQueryChange}
datasource={mockDatasource}
variableOptionGroup={variableOptionGroup}
setError={jest.fn()}
/>
);
expect(screen.getByText('test-property')).toBeInTheDocument();
expect(screen.getByText('=')).toBeInTheDocument();
expect(screen.getByText('test-filter')).toBeInTheDocument();
});
it('should add a trace filter', async () => {
let mockQuery = createMockQuery({ azureTraces: { traceTypes: ['customEvents'] } });
mockQuery.azureTraces = {
...mockQuery.azureTraces,
filters: undefined,
};
const { rerender } = render(
<Filters
datasource={mockDatasource}
onQueryChange={onQueryChange}
query={mockQuery}
setError={jest.fn()}
variableOptionGroup={variableOptionGroup}
/>
);
await addFilter(
mockQuery,
{ property: 'appId', filters: [{ count: 10, value: 'test-app-id' }], operation: 'eq', index: 0 },
rerender
);
});
it('should add multiple trace filters', async () => {
let mockQuery = createMockQuery({ azureTraces: { traceTypes: ['customEvents'] } });
mockQuery.azureTraces = {
...mockQuery.azureTraces,
filters: undefined,
};
const { rerender } = render(
<Filters
datasource={mockDatasource}
onQueryChange={onQueryChange}
query={mockQuery}
setError={jest.fn()}
variableOptionGroup={variableOptionGroup}
/>
);
mockQuery = await addFilter(
mockQuery,
{ property: 'appId', filters: [{ count: 10, value: 'test-app-id' }], operation: 'eq', index: 0 },
rerender
);
mockQuery = await addFilter(
mockQuery,
{ property: 'client_Browser', filters: [{ count: 100, value: 'test-client' }], operation: 'ne', index: 1 },
rerender
);
});
it('should delete a trace filter', async () => {
let mockQuery = createMockQuery({ azureTraces: { traceTypes: ['customEvents'] } });
mockQuery.azureTraces = {
...mockQuery.azureTraces,
filters: undefined,
};
const { rerender } = render(
<Filters
datasource={mockDatasource}
onQueryChange={onQueryChange}
query={mockQuery}
setError={jest.fn()}
variableOptionGroup={variableOptionGroup}
/>
);
mockQuery = await addFilter(
mockQuery,
{ property: 'appId', filters: [{ count: 10, value: 'test-app-id' }], operation: 'eq', index: 0 },
rerender
);
mockQuery = await addFilter(
mockQuery,
{ property: 'client_Browser', filters: [{ count: 100, value: 'test-client' }], operation: 'ne', index: 1 },
rerender
);
const removeButtons = screen.getAllByLabelText('Remove');
mockQuery = {
...mockQuery,
azureTraces: {
...mockQuery.azureTraces,
filters: mockQuery.azureTraces?.filters?.slice(0, 1),
},
};
await act(async () => {
await userEvent.click(removeButtons[1]);
});
rerender(
<Filters
datasource={mockDatasource}
onQueryChange={onQueryChange}
query={mockQuery}
setError={jest.fn()}
variableOptionGroup={variableOptionGroup}
/>
);
expect(screen.getByText('appId')).toBeInTheDocument();
expect(screen.getByText('=')).toBeInTheDocument();
expect(screen.getByText('test-app-id')).toBeInTheDocument();
expect(screen.queryByText('client_Browser')).not.toBeInTheDocument();
expect(screen.queryByText('!=')).not.toBeInTheDocument();
expect(screen.queryByText('test-client')).not.toBeInTheDocument();
});
it('should add a trace filter and select multiple values', async () => {
let mockQuery = createMockQuery({ azureTraces: { traceTypes: ['customEvents'] } });
mockQuery.azureTraces = {
...mockQuery.azureTraces,
filters: undefined,
};
const { rerender } = render(
<Filters
datasource={mockDatasource}
onQueryChange={onQueryChange}
query={mockQuery}
setError={jest.fn()}
variableOptionGroup={variableOptionGroup}
/>
);
await addFilter(
mockQuery,
{
property: 'appId',
filters: [
{ count: 10, value: 'test-app-id' },
{ count: 20, value: 'test-app-id-2' },
],
operation: 'eq',
index: 0,
},
rerender
);
});
it('should remove a value from a trace filter with multiple values', async () => {
let mockQuery = createMockQuery({ azureTraces: { traceTypes: ['customEvents'] } });
mockQuery.azureTraces = {
...mockQuery.azureTraces,
filters: undefined,
};
const { rerender } = render(
<Filters
datasource={mockDatasource}
onQueryChange={onQueryChange}
query={mockQuery}
setError={jest.fn()}
variableOptionGroup={variableOptionGroup}
/>
);
mockQuery = await addFilter(
mockQuery,
{
property: 'appId',
filters: [
{ count: 10, value: 'test-app-id' },
{ count: 20, value: 'test-app-id-2' },
],
operation: 'eq',
index: 0,
},
rerender
);
const currFilter = mockQuery.azureTraces?.filters![0]!;
mockQuery = {
...mockQuery,
azureTraces: {
...mockQuery.azureTraces,
filters: [
{
...currFilter,
filters: currFilter.filters.slice(0, 1),
},
],
},
};
const removeLabel = screen.getByLabelText(`Remove test-app-id-2`);
await act(async () => {
await userEvent.click(removeLabel);
});
rerender(
<Filters
datasource={mockDatasource}
onQueryChange={onQueryChange}
query={mockQuery}
setError={jest.fn()}
variableOptionGroup={variableOptionGroup}
/>
);
expect(screen.getByText('appId')).toBeInTheDocument();
expect(screen.getByText('=')).toBeInTheDocument();
expect(screen.getByText('test-app-id')).toBeInTheDocument();
expect(screen.queryByText('test-app-id-2')).not.toBeInTheDocument();
});
});

View File

@ -0,0 +1,95 @@
import { uniq } from 'lodash';
import React, { useEffect, useMemo, useState } from 'react';
import { SelectableValue, TimeRange } from '@grafana/data';
import { EditorList } from '@grafana/experimental';
import { Field } from '@grafana/ui';
import { AzureQueryEditorFieldProps, AzureTracesFilter } from '../../types';
import { makeRenderItem } from './Filter';
import { tablesSchema } from './consts';
import { setFilters } from './setQueryValue';
const Filters = ({ query, datasource, onQueryChange, variableOptionGroup }: AzureQueryEditorFieldProps) => {
const { azureTraces } = query;
const queryTraceTypes = azureTraces?.traceTypes ? azureTraces.traceTypes : Object.keys(tablesSchema);
const excludedProperties = new Set([
'customDimensions',
'customMeasurements',
'details',
'duration',
'id',
'itemId',
'operation_Id',
'operation_ParentId',
'timestamp',
]);
const properties = uniq(queryTraceTypes.map((type) => Object.keys(tablesSchema[type])).flat()).filter(
(item) => !excludedProperties.has(item)
);
const [propertyMap, setPropertyMap] = useState(new Map<string, Array<SelectableValue<string>>>());
const queryFilters = useMemo(() => query.azureTraces?.filters ?? [], [query.azureTraces?.filters]);
const [filters, updateFilters] = useState(queryFilters);
const timeSrv = datasource.azureLogAnalyticsDatasource.timeSrv;
const [timeRange, setTimeRange] = useState(timeSrv.timeRange());
const useTime = (time: TimeRange) => {
if (
timeRange !== null &&
(timeRange.raw.from.toString() !== time.raw.from.toString() ||
timeRange.raw.to.toString() !== time.raw.to.toString())
) {
setTimeRange({ ...time });
}
};
useTime(timeSrv.timeRange());
useEffect(() => {
setPropertyMap(new Map<string, Array<SelectableValue<string>>>());
}, [timeRange, query.azureTraces?.resources, query.azureTraces?.traceTypes, query.azureTraces?.operationId]);
const changedFunc = (changed: Array<Partial<AzureTracesFilter>>) => {
let updateQuery = false;
const properData: AzureTracesFilter[] = changed.map((x) => {
if (x.property !== '' && x.filters && x.filters.length > 0 && x.operation !== '') {
updateQuery = true;
} else {
updateQuery = false;
}
return {
property: x.property ?? '',
filters: x.filters ?? [],
operation: x.operation ?? 'eq',
};
});
updateFilters(properData);
if (updateQuery || (queryFilters.length > 0 && properData.length === 0)) {
onQueryChange(setFilters(query, properData));
}
};
return (
<Field label="Filters">
<EditorList
items={filters}
onChange={changedFunc}
renderItem={makeRenderItem({
query,
datasource,
propertyMap,
setPropertyMap,
timeRange,
queryTraceTypes,
properties,
variableOptionGroup,
})}
/>
</Field>
);
};
export default Filters;

View File

@ -0,0 +1,64 @@
import { render, screen, act } from '@testing-library/react';
import React from 'react';
import { openMenu } from 'react-select-event';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
import { selectors } from '../../e2e/selectors';
import TraceTypeField from './TraceTypeField';
import { Tables } from './consts';
import { setTraceTypes } from './setQueryValue';
const props = {
query: createMockQuery(),
datasource: createMockDatasource(),
variableOptionGroup: { label: 'Templates', options: [] },
onQueryChange: jest.fn(),
setError: jest.fn(),
};
describe('TraceTypeField', () => {
it('should render with default types', async () => {
const query = {
...props.query,
azureTraces: {
...props.query.azureTraces,
traceTypes: [],
},
};
render(<TraceTypeField {...props} query={query} />);
expect(screen.getByText('Choose event types')).toBeInTheDocument();
const menu = screen.getByLabelText(selectors.components.queryEditor.tracesQueryEditor.traceTypes.select);
openMenu(menu);
Object.values(Tables).forEach((table) => {
expect(screen.getByText(table.label)).toBeInTheDocument();
});
});
it('should render the value defined in the query', async () => {
render(<TraceTypeField {...props} />);
expect(screen.getByText('Traces')).toBeInTheDocument();
});
it('should update the query', async () => {
const { rerender } = render(<TraceTypeField {...props} />);
expect(screen.getByText('Traces')).toBeInTheDocument();
const menu = screen.getByLabelText(selectors.components.queryEditor.tracesQueryEditor.traceTypes.select);
openMenu(menu);
act(() => {
screen.getByText('Dependencies').click();
});
const newQuery = setTraceTypes(props.query, [...props.query.azureTraces?.traceTypes!, 'dependencies']);
expect(props.onQueryChange).toHaveBeenCalledWith(newQuery);
rerender(<TraceTypeField {...props} query={newQuery} />);
expect(screen.getByText('Dependencies')).toBeInTheDocument();
});
});

View File

@ -0,0 +1,49 @@
import React, { useCallback, useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { MultiSelect } from '@grafana/ui';
import { selectors } from '../../e2e/selectors';
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
import { findOptions } from '../../utils/common';
import { Field } from '../Field';
import { Tables } from './consts';
import { setTraceTypes } from './setQueryValue';
const TraceTypeField = ({ query, variableOptionGroup, onQueryChange }: AzureQueryEditorFieldProps) => {
const tables: AzureMonitorOption[] = Object.entries(Tables).map(([key, value]) => ({
label: value.label,
description: value.description,
value: key,
}));
const handleChange = useCallback(
(change: Array<SelectableValue<string>>) => {
const newQuery = setTraceTypes(
query,
change.map((type) => type.value ?? '')
);
onQueryChange(newQuery);
},
[onQueryChange, query]
);
const options = useMemo(() => [...tables, variableOptionGroup], [tables, variableOptionGroup]);
return (
<Field label="Event Type">
<MultiSelect
placeholder="Choose event types"
inputId="azure-monitor-traces-type-field"
value={findOptions([...tables, ...variableOptionGroup.options], query.azureTraces?.traceTypes ?? [])}
onChange={handleChange}
options={options}
allowCustomValue
isClearable
aria-label={selectors.components.queryEditor.tracesQueryEditor.traceTypes.select}
/>
</Field>
);
};
export default TraceTypeField;

View File

@ -0,0 +1,187 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
import { createMockResourcePickerData } from '../MetricsQueryEditor/MetricsQueryEditor.test';
import TracesQueryEditor from './TracesQueryEditor';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
getTemplateSrv: () => ({
replace: (val: string) => {
return val;
},
}),
}));
const variableOptionGroup = {
label: 'Template variables',
options: [],
};
describe('TracesQueryEditor', () => {
const originalScrollIntoView = window.HTMLElement.prototype.scrollIntoView;
beforeEach(() => {
window.HTMLElement.prototype.scrollIntoView = function () {};
});
afterEach(() => {
window.HTMLElement.prototype.scrollIntoView = originalScrollIntoView;
});
it('should select multiple resources', async () => {
const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() });
const query = createMockQuery();
delete query?.subscription;
delete query?.azureTraces?.resources;
const onChange = jest.fn();
render(
<TracesQueryEditor
query={query}
datasource={mockDatasource}
variableOptionGroup={variableOptionGroup}
onChange={onChange}
setError={() => {}}
/>
);
const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' });
await userEvent.click(resourcePickerButton);
const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' });
await userEvent.click(subscriptionButton);
const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' });
await userEvent.click(resourceGroupButton);
const checkbox = await screen.findByLabelText('app-insights-1');
await userEvent.click(checkbox);
expect(checkbox).toBeChecked();
const checkbox2 = await screen.findByLabelText('app-insights-2');
await userEvent.click(checkbox2);
expect(checkbox2).toBeChecked();
await userEvent.click(await screen.findByRole('button', { name: 'Apply' }));
expect(onChange).toBeCalledWith(
expect.objectContaining({
azureTraces: expect.objectContaining({
resources: [
'/subscriptions/def-456/resourceGroups/dev-3/providers/microsoft.insights/components/app-insights-1',
'/subscriptions/def-456/resourceGroups/dev-3/providers/microsoft.insights/components/app-insights-2',
],
}),
})
);
});
it('should disable other resource types when selecting multiple resources', async () => {
const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() });
const query = createMockQuery();
delete query?.subscription;
delete query?.azureTraces?.resources;
const onChange = jest.fn();
render(
<TracesQueryEditor
query={query}
datasource={mockDatasource}
variableOptionGroup={variableOptionGroup}
onChange={onChange}
setError={() => {}}
/>
);
const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' });
await userEvent.click(resourcePickerButton);
const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' });
await userEvent.click(subscriptionButton);
const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' });
await userEvent.click(resourceGroupButton);
const checkbox = await screen.findByLabelText('app-insights-1');
await userEvent.click(checkbox);
expect(checkbox).toBeChecked();
expect(await screen.findByLabelText('web-server_DataDisk')).toBeDisabled();
});
it('should show info about multiple selection', async () => {
const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() });
const query = createMockQuery();
delete query?.subscription;
delete query?.azureTraces?.resources;
const onChange = jest.fn();
render(
<TracesQueryEditor
query={query}
datasource={mockDatasource}
variableOptionGroup={variableOptionGroup}
onChange={onChange}
setError={() => {}}
/>
);
const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' });
await userEvent.click(resourcePickerButton);
const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' });
await userEvent.click(subscriptionButton);
const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' });
await userEvent.click(resourceGroupButton);
const checkbox = await screen.findByLabelText('app-insights-1');
await userEvent.click(checkbox);
expect(checkbox).toBeChecked();
expect(await screen.findByText('You may only choose items of the same resource type.')).toBeInTheDocument();
});
it('should call onApply with a new subscription uri when a user types it in the selection box', async () => {
const mockDatasource = createMockDatasource({ resourcePickerData: createMockResourcePickerData() });
const query = createMockQuery();
delete query?.subscription;
delete query?.azureTraces?.resources;
const onChange = jest.fn();
render(
<TracesQueryEditor
query={query}
datasource={mockDatasource}
variableOptionGroup={variableOptionGroup}
onChange={onChange}
setError={() => {}}
/>
);
const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' });
await userEvent.click(resourcePickerButton);
const advancedSection = screen.getByText('Advanced');
await userEvent.click(advancedSection);
const advancedInput = await screen.findByTestId('input-advanced-resource-picker-1');
await userEvent.type(advancedInput, '/subscriptions/def-123');
const applyButton = screen.getByRole('button', { name: 'Apply' });
await userEvent.click(applyButton);
expect(onChange).toBeCalledWith(
expect.objectContaining({
azureTraces: expect.objectContaining({
resources: ['/subscriptions/def-123'],
}),
})
);
});
});

View File

@ -0,0 +1,163 @@
import React, { useCallback, useEffect, useState } from 'react';
import { usePrevious } from 'react-use';
import { EditorFieldGroup, EditorRow, EditorRows } from '@grafana/experimental';
import { Input } from '@grafana/ui';
import Datasource from '../../datasource';
import { selectors } from '../../e2e/selectors';
import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery, ResultFormat } from '../../types';
import { Field } from '../Field';
import FormatAsField from '../FormatAsField';
import AdvancedResourcePicker from '../LogsQueryEditor/AdvancedResourcePicker';
import ResourceField from '../ResourceField';
import { ResourceRow, ResourceRowGroup, ResourceRowType } from '../ResourcePicker/types';
import { parseResourceDetails } from '../ResourcePicker/utils';
import Filters from './Filters';
import TraceTypeField from './TraceTypeField';
import { setFormatAs, setQueryOperationId } from './setQueryValue';
interface TracesQueryEditorProps {
query: AzureMonitorQuery;
datasource: Datasource;
subscriptionId?: string;
onChange: (newQuery: AzureMonitorQuery) => void;
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;
}
const TracesQueryEditor = ({
query,
datasource,
subscriptionId,
variableOptionGroup,
onChange,
setError,
}: TracesQueryEditorProps) => {
const disableRow = (row: ResourceRow, selectedRows: ResourceRowGroup) => {
if (selectedRows.length === 0) {
// Only if there is some resource(s) selected we should disable rows
return false;
}
const rowResourceNS = parseResourceDetails(row.uri, row.location).metricNamespace?.toLowerCase();
const selectedRowSampleNs = parseResourceDetails(
selectedRows[0].uri,
selectedRows[0].location
).metricNamespace?.toLowerCase();
// Only resources with the same metricNamespace can be selected
return rowResourceNS !== selectedRowSampleNs;
};
const [operationId, setOperationId] = useState<string>(query.azureTraces?.operationId ?? '');
const previousOperationId = usePrevious(query.azureTraces?.operationId);
useEffect(() => {
if (query.azureTraces?.operationId) {
if (previousOperationId !== query.azureTraces.operationId) {
setOperationId(query.azureTraces.operationId);
}
}
}, [setOperationId, previousOperationId, query, operationId]);
const handleChange = useCallback((ev: React.FormEvent) => {
if (ev.target instanceof HTMLInputElement) {
setOperationId(ev.target.value);
}
}, []);
const handleBlur = useCallback(
(ev: React.FormEvent) => {
const newQuery = setQueryOperationId(query, operationId);
onChange(newQuery);
},
[onChange, operationId, query]
);
return (
<span data-testid={selectors.components.queryEditor.tracesQueryEditor.container.input}>
<EditorRows>
<EditorRow>
<EditorFieldGroup>
<ResourceField
query={query}
datasource={datasource}
subscriptionId={subscriptionId}
variableOptionGroup={variableOptionGroup}
onQueryChange={onChange}
setError={setError}
selectableEntryTypes={[
ResourceRowType.Subscription,
ResourceRowType.ResourceGroup,
ResourceRowType.Resource,
ResourceRowType.Variable,
]}
resources={query.azureTraces?.resources ?? []}
queryType="traces"
disableRow={disableRow}
renderAdvanced={(resources, onChange) => (
// It's required to cast resources because the resource picker
// specifies the type to string | AzureMonitorResource.
// eslint-disable-next-line
<AdvancedResourcePicker resources={resources as string[]} onChange={onChange} />
)}
selectionNotice={() => 'You may only choose items of the same resource type.'}
/>
</EditorFieldGroup>
</EditorRow>
<EditorRow>
<EditorFieldGroup>
<TraceTypeField
datasource={datasource}
onQueryChange={onChange}
query={query}
setError={setError}
variableOptionGroup={variableOptionGroup}
/>
<Field label="Operation ID">
<Input
id="azure-monitor-traces-operation-id-field"
value={operationId}
onChange={handleChange}
onBlur={handleBlur}
width={40}
/>
</Field>
</EditorFieldGroup>
</EditorRow>
<EditorRow>
<EditorFieldGroup>
<Filters
datasource={datasource}
onQueryChange={onChange}
query={query}
setError={setError}
variableOptionGroup={variableOptionGroup}
/>
</EditorFieldGroup>
</EditorRow>
<EditorRow>
<EditorFieldGroup>
<FormatAsField
datasource={datasource}
setError={setError}
query={query}
variableOptionGroup={variableOptionGroup}
onQueryChange={onChange}
inputId="azure-monitor-traces"
options={[
{ label: 'Table', value: ResultFormat.Table },
{ label: 'Trace', value: ResultFormat.Trace },
]}
defaultValue={ResultFormat.Table}
setFormatAs={setFormatAs}
resultFormat={query.azureTraces?.resultFormat}
/>
</EditorFieldGroup>
</EditorRow>
</EditorRows>
</span>
);
};
export default TracesQueryEditor;

View File

@ -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(',') }),
{}
);

View File

@ -0,0 +1 @@
export { default } from './TracesQueryEditor';

View File

@ -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,
},
};
}

View File

@ -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.

View File

@ -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<AzureMonitorQuery> = {
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<AzureLogsQuery> = {
resources: [],
};
/**
* Application Insights Traces sub-query properties
*/
export interface AzureTracesQuery {
/**
* Filters for property values.
*/
filters?: Array<AzureTracesFilter>;
/**
* 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<string>;
/**
* Specifies the format results should be returned as.
*/
resultFormat?: ResultFormat;
/**
* Types of events to filter by.
*/
traceTypes?: Array<string>;
}
export const defaultAzureTracesQuery: Partial<AzureTracesQuery> = {
filters: [],
resources: [],
traceTypes: [],
};
export interface AzureTracesFilter {
/**
* Values to filter by.
*/
filters: Array<string>;
/**
* 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<AzureTracesFilter> = {
filters: [],
};
export enum ResultFormat {
Table = 'table',
TimeSeries = 'time_series',
Trace = 'trace',
}
export interface AzureResourceGraphQuery {

View File

@ -90,7 +90,8 @@ export default class Datasource extends DataSourceWithBackend<AzureMonitorQuery,
}
const observables: Array<Observable<DataQueryResponse>> = 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<AzureMonitorQuery,
return query;
}
const ds = this.pseudoDatasource[query.queryType];
const queryType = query.queryType === AzureQueryType.AzureTraces ? AzureQueryType.LogAnalytics : query.queryType;
const ds = this.pseudoDatasource[queryType];
return {
datasource: ds?.getRef(),
...(ds?.applyTemplateVariables(query, scopedVars) ?? query),
@ -213,6 +215,9 @@ function hasQueryForType(query: AzureMonitorQuery): boolean {
case AzureQueryType.AzureResourceGraph:
return !!query.azureResourceGraph;
case AzureQueryType.AzureTraces:
return !!query.azureTraces;
case AzureQueryType.GrafanaTemplateVariableFn:
return !!query.grafanaTemplateVariableFn;

View File

@ -61,11 +61,13 @@ export const components = {
},
},
metricsQueryEditor: {
container: { input: 'data-testid azure-monitor-metrics-query-editor-with-experimental-ui' },
metricName: {
input: 'data-testid metric-name',
},
},
logsQueryEditor: {
container: { input: 'data-testid azure-monitor-logs-query-editor-with-experimental-ui' },
formatSelection: {
input: 'data-testid format-selection',
},
@ -78,6 +80,14 @@ export const components = {
input: 'data-testid azure-monitor-args-subscription',
},
},
tracesQueryEditor: {
container: {
input: 'data-testid azure-monitor-traces-query-editor-with-experimental-ui',
},
traceTypes: {
select: 'data-testid azure-monitor-traces-query-editor-trace-types',
},
},
},
variableEditor: {
queryType: {

View File

@ -32,7 +32,7 @@ const RESOURCE_GRAPH_URL = '/providers/Microsoft.ResourceGraph/resources?api-ver
const logsSupportedResourceTypesKusto = logsResourceTypes.map((v) => `"${v}"`).join(',');
export type ResourcePickerQueryType = 'logs' | 'metrics';
export type ResourcePickerQueryType = 'logs' | 'metrics' | 'traces';
export default class ResourcePickerData extends DataSourceWithBackend<AzureMonitorQuery, AzureDataSourceJsonData> {
private resourcePath: string;

View File

@ -5,8 +5,10 @@ export {
AzureMetricQuery,
AzureLogsQuery,
AzureResourceGraphQuery,
AzureTracesQuery,
AzureMonitorResource,
AzureMetricDimension,
AzureTracesFilter,
ResultFormat,
} from '../dataquery.gen';

View File

@ -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<AzureDataSourceJsonData, AzureDataSourceSecureJsonData>;
export type AzureDataSourceInstanceSettings = DataSourceInstanceSettings<AzureDataSourceJsonData>;
@ -170,6 +171,14 @@ export interface AzureQueryEditorFieldProps {
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;
}
export interface FormatAsFieldProps extends AzureQueryEditorFieldProps {
inputId: string;
options: Array<SelectableValue<ResultFormat>>;
defaultValue: ResultFormat;
setFormatAs: (query: AzureMonitorQuery, formatAs: ResultFormat) => AzureMonitorQuery;
resultFormat?: ResultFormat;
}
export interface AzureResourceSummaryItem {
subscriptionName: string;
resourceGroupName: string | undefined;

View File

@ -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<AzureMonitorOption | SelectableValue>,
variableOptionGroup: VariableOptionGroup,
value?: string
) => {