mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: Parse non-fatal errors for Logs (#51320)
This commit is contained in:
parent
9e80e44b45
commit
b10ddfdf8c
@ -148,7 +148,7 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, query *A
|
||||
|
||||
// If azureLogAnalyticsSameAs is defined and set to false, return an error
|
||||
if sameAs, ok := dsInfo.JSONData["azureLogAnalyticsSameAs"]; ok && !sameAs.(bool) {
|
||||
return dataResponseErrorWithExecuted(fmt.Errorf("Log Analytics credentials are no longer supported. Go to the data source configuration to update Azure Monitor credentials")) //nolint:golint,stylecheck
|
||||
return dataResponseErrorWithExecuted(fmt.Errorf("credentials for Log Analytics are no longer supported. Go to the data source configuration to update Azure Monitor credentials"))
|
||||
}
|
||||
|
||||
req, err := e.createRequest(ctx, dsInfo, url)
|
||||
@ -187,7 +187,7 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, query *A
|
||||
return dataResponseErrorWithExecuted(err)
|
||||
}
|
||||
|
||||
frame, err := ResponseTableToFrame(t)
|
||||
frame, err := ResponseTableToFrame(t, logResponse)
|
||||
if err != nil {
|
||||
return dataResponseErrorWithExecuted(err)
|
||||
}
|
||||
@ -234,9 +234,31 @@ func (e *AzureLogAnalyticsDatasource) createRequest(ctx context.Context, dsInfo
|
||||
return req, 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 {
|
||||
Details *[]AzureLogAnalyticsAPIErrorBase `json:"details,omitempty"`
|
||||
Code *string `json:"code,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
type AzureLogAnalyticsAPIErrorBase struct {
|
||||
Code *string `json:"code,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
Innererror *AzureLogAnalyticsInnerError `json:"innererror,omitempty"`
|
||||
}
|
||||
|
||||
type AzureLogAnalyticsInnerError struct {
|
||||
Code *string `json:"code,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
Severity *int `json:"severity,omitempty"`
|
||||
SeverityName *string `json:"severityName,omitempty"`
|
||||
}
|
||||
|
||||
// AzureLogAnalyticsResponse is the json response object from the Azure Log Analytics API.
|
||||
type AzureLogAnalyticsResponse struct {
|
||||
Tables []types.AzureResponseTable `json:"tables"`
|
||||
Error *AzureLogAnalyticsAPIError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// GetPrimaryResultTable returns the first table in the response named "PrimaryResult", or an
|
||||
|
@ -235,7 +235,7 @@ func Test_executeQueryErrorWithDifferentLogAnalyticsCreds(t *testing.T) {
|
||||
if res.Error == nil {
|
||||
t.Fatal("expecting an error")
|
||||
}
|
||||
if !strings.Contains(res.Error.Error(), "Log Analytics credentials are no longer supported") {
|
||||
if !strings.Contains(res.Error.Error(), "credentials for Log Analytics are no longer supported") {
|
||||
t.Error("expecting the error to inform of bad credentials")
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,45 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
||||
)
|
||||
|
||||
func apiErrorToNotice(err *AzureLogAnalyticsAPIError) data.Notice {
|
||||
message := []string{}
|
||||
severity := data.NoticeSeverityWarning
|
||||
if err.Message != nil {
|
||||
message = append(message, *err.Message)
|
||||
}
|
||||
if err.Details != nil && len(*err.Details) > 0 {
|
||||
for _, detail := range *err.Details {
|
||||
if detail.Message != nil {
|
||||
message = append(message, *detail.Message)
|
||||
}
|
||||
if detail.Innererror != nil {
|
||||
if detail.Innererror.Message != nil {
|
||||
message = append(message, *detail.Innererror.Message)
|
||||
}
|
||||
if detail.Innererror.SeverityName != nil && *detail.Innererror.SeverityName == "Error" {
|
||||
// Severity names are not documented in the API response format
|
||||
// https://docs.microsoft.com/en-us/azure/azure-monitor/logs/api/response-format
|
||||
// so assuming either an error or a warning
|
||||
severity = data.NoticeSeverityError
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return data.Notice{
|
||||
Severity: severity,
|
||||
Text: strings.Join(message, " "),
|
||||
}
|
||||
}
|
||||
|
||||
// ResponseTableToFrame converts an AzureResponseTable to a data.Frame.
|
||||
func ResponseTableToFrame(table *types.AzureResponseTable) (*data.Frame, error) {
|
||||
func ResponseTableToFrame(table *types.AzureResponseTable, res AzureLogAnalyticsResponse) (*data.Frame, error) {
|
||||
converterFrame, err := converterFrameForTable(table)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -25,6 +56,11 @@ func ResponseTableToFrame(table *types.AzureResponseTable) (*data.Frame, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if res.Error != nil {
|
||||
converterFrame.Frame.AppendNotices(apiErrorToNotice(res.Error))
|
||||
}
|
||||
|
||||
return converterFrame.Frame, nil
|
||||
}
|
||||
|
||||
|
@ -139,12 +139,42 @@ func TestLogTableToFrame(t *testing.T) {
|
||||
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{pointer.String("Create or Update Virtual Machine")}),
|
||||
data.NewField("Level", nil, []*string{pointer.String("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{pointer.String("Create or Update Virtual Machine")}),
|
||||
data.NewField("Level", nil, []*string{pointer.String("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
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
res := loadLogAnalyticsTestFileWithNumber(t, tt.testFile)
|
||||
frame, err := ResponseTableToFrame(&res.Tables[0])
|
||||
frame, err := ResponseTableToFrame(&res.Tables[0], res)
|
||||
require.NoError(t, err)
|
||||
|
||||
if diff := cmp.Diff(tt.expectedFrame(), frame, data.FrameTestCompareOptions()...); diff != "" {
|
||||
|
@ -188,7 +188,7 @@ func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, query *
|
||||
return dataResponseErrorWithExecuted(err)
|
||||
}
|
||||
|
||||
frame, err := loganalytics.ResponseTableToFrame(&argResponse.Data)
|
||||
frame, err := loganalytics.ResponseTableToFrame(&argResponse.Data, loganalytics.AzureLogAnalyticsResponse{})
|
||||
if err != nil {
|
||||
return dataResponseErrorWithExecuted(err)
|
||||
}
|
||||
|
40
pkg/tsdb/azuremonitor/testdata/loganalytics/10-log-analytics-response-warning.json
vendored
Normal file
40
pkg/tsdb/azuremonitor/testdata/loganalytics/10-log-analytics-response-warning.json
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"tables": [
|
||||
{
|
||||
"name": "PrimaryResult",
|
||||
"columns": [
|
||||
{
|
||||
"name": "OperationName",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "Level",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"rows": [
|
||||
[
|
||||
"Create or Update Virtual Machine",
|
||||
"Informational"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"error": {
|
||||
"code": "PartialError",
|
||||
"message": "There were some errors when processing your query.",
|
||||
"details": [
|
||||
{
|
||||
"code": "EngineError",
|
||||
"message": "Something went wrong processing your query on the server.",
|
||||
"innererror": {
|
||||
"code": "-2133196797",
|
||||
"message": "Not sure what happened.",
|
||||
"severity": 2,
|
||||
"severityName": "Warning"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
40
pkg/tsdb/azuremonitor/testdata/loganalytics/9-log-analytics-response-error.json
vendored
Normal file
40
pkg/tsdb/azuremonitor/testdata/loganalytics/9-log-analytics-response-error.json
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"tables": [
|
||||
{
|
||||
"name": "PrimaryResult",
|
||||
"columns": [
|
||||
{
|
||||
"name": "OperationName",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "Level",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"rows": [
|
||||
[
|
||||
"Create or Update Virtual Machine",
|
||||
"Informational"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"error": {
|
||||
"code": "PartialError",
|
||||
"message": "There were some errors when processing your query.",
|
||||
"details": [
|
||||
{
|
||||
"code": "EngineError",
|
||||
"message": "Something went wrong processing your query on the server.",
|
||||
"innererror": {
|
||||
"code": "-2133196797",
|
||||
"message": "The results of this query exceed the set limit of 1 records.",
|
||||
"severity": 2,
|
||||
"severityName": "Error"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user