From 00ace4678c8819846358d099db1fbdf6881ba319 Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Tue, 10 Sep 2024 19:34:20 +0100 Subject: [PATCH] GCM: Add errorsource (#92151) * Add errorsource * Minor lint fixes --- pkg/tsdb/cloud-monitoring/annotation_query.go | 7 ++++ pkg/tsdb/cloud-monitoring/cloudmonitoring.go | 13 ++++++-- pkg/tsdb/cloud-monitoring/promql_query.go | 9 +++--- .../cloud-monitoring/promql_query_test.go | 8 ++--- .../cloud-monitoring/time_series_filter.go | 2 +- pkg/tsdb/cloud-monitoring/utils.go | 32 +++++++++---------- 6 files changed, 41 insertions(+), 30 deletions(-) diff --git a/pkg/tsdb/cloud-monitoring/annotation_query.go b/pkg/tsdb/cloud-monitoring/annotation_query.go index a3c14572c9b..17591906731 100644 --- a/pkg/tsdb/cloud-monitoring/annotation_query.go +++ b/pkg/tsdb/cloud-monitoring/annotation_query.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource" ) type annotationEvent struct { @@ -24,6 +25,7 @@ func (s *Service) executeAnnotationQuery(ctx context.Context, req *backend.Query resp := backend.NewQueryDataResponse() queryRes, dr, _, err := queries[0].run(ctx, req, s, dsInfo, logger) if err != nil { + errorsource.AddErrorToResponse(queries[0].getRefID(), resp, err) return resp, err } @@ -42,6 +44,11 @@ func (s *Service) executeAnnotationQuery(ctx context.Context, req *backend.Query err = parseToAnnotations(req.Queries[0].RefID, queryRes, dr.(cloudMonitoringResponse), tslq.TimeSeriesList.Title, tslq.TimeSeriesList.Text) resp.Responses[firstQuery.RefID] = *queryRes + if err != nil { + errorsource.AddErrorToResponse(firstQuery.RefID, resp, err) + return resp, err + } + return resp, err } diff --git a/pkg/tsdb/cloud-monitoring/cloudmonitoring.go b/pkg/tsdb/cloud-monitoring/cloudmonitoring.go index c8218bb2959..1ff0fcf9747 100644 --- a/pkg/tsdb/cloud-monitoring/cloudmonitoring.go +++ b/pkg/tsdb/cloud-monitoring/cloudmonitoring.go @@ -22,6 +22,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource" "github.com/grafana/grafana/pkg/tsdb/cloud-monitoring/kinds/dataquery" ) @@ -342,6 +343,7 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) return nil, err } + // There aren't any possible downstream errors here queries, err := s.buildQueryExecutors(logger, req) if err != nil { return nil, err @@ -361,11 +363,15 @@ func (s *Service) executeTimeSeriesQuery(ctx context.Context, req *backend.Query for _, queryExecutor := range queries { queryRes, dr, executedQueryString, err := queryExecutor.run(ctx, req, s, dsInfo, logger) if err != nil { + errorsource.AddErrorToResponse(queryExecutor.getRefID(), resp, err) return resp, err } err = queryExecutor.parseResponse(queryRes, dr, executedQueryString, logger) if err != nil { - queryRes.Error = err + // Default to a plugin error if there's no source + errWithSource := errorsource.SourceError(backend.ErrorSourcePlugin, err, false) + queryRes.Error = errWithSource.Unwrap() + queryRes.ErrorSource = errWithSource.ErrorSource() } resp.Responses[queryExecutor.getRefID()] = *queryRes @@ -583,7 +589,8 @@ func (s *Service) ensureProject(ctx context.Context, dsInfo datasourceInfo, proj func (s *Service) getDefaultProject(ctx context.Context, dsInfo datasourceInfo) (string, error) { if dsInfo.authenticationType == gceAuthentication { - return s.gceDefaultProjectGetter(ctx, cloudMonitorScope) + project, err := s.gceDefaultProjectGetter(ctx, cloudMonitorScope) + return project, errorsource.DownstreamError(err, false) } return dsInfo.defaultProject, nil } @@ -602,7 +609,7 @@ func unmarshalResponse(res *http.Response, logger log.Logger) (cloudMonitoringRe if res.StatusCode/100 != 2 { logger.Error("Request failed", "status", res.Status, "body", string(body)) - return cloudMonitoringResponse{}, fmt.Errorf("query failed: %s", string(body)) + return cloudMonitoringResponse{}, errorsource.SourceError(backend.ErrorSourceFromHTTPStatus(res.StatusCode), fmt.Errorf("query failed: %s", string(body)), false) } var data cloudMonitoringResponse diff --git a/pkg/tsdb/cloud-monitoring/promql_query.go b/pkg/tsdb/cloud-monitoring/promql_query.go index 16efb08e154..1dc6923bb0d 100644 --- a/pkg/tsdb/cloud-monitoring/promql_query.go +++ b/pkg/tsdb/cloud-monitoring/promql_query.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource" "github.com/grafana/grafana/pkg/tsdb/cloud-monitoring/converter" jsoniter "github.com/json-iterator/go" ) @@ -22,8 +23,7 @@ func (promQLQ *cloudMonitoringProm) run(ctx context.Context, req *backend.QueryD dr := &backend.DataResponse{} projectName, err := s.ensureProject(ctx, dsInfo, promQLQ.parameters.ProjectName) if err != nil { - dr.Error = err - return dr, backend.DataResponse{}, "", nil + return dr, backend.DataResponse{}, "", err } r, err := createRequest(ctx, &dsInfo, path.Join("/v1/projects", projectName, "location/global/prometheus/api/v1/query_range"), nil) if err != nil { @@ -43,8 +43,7 @@ func (promQLQ *cloudMonitoringProm) run(ctx context.Context, req *backend.QueryD res, err := doRequestProm(r, dsInfo, requestBody) if err != nil { - dr.Error = err - return dr, backend.DataResponse{}, "", nil + return dr, backend.DataResponse{}, "", err } defer func() { @@ -67,7 +66,7 @@ func doRequestProm(r *http.Request, dsInfo datasourceInfo, body map[string]any) } res, err := dsInfo.services[cloudMonitor].client.Do(r) if err != nil { - return res, err + return res, errorsource.DownstreamError(err, false) } return res, nil diff --git a/pkg/tsdb/cloud-monitoring/promql_query_test.go b/pkg/tsdb/cloud-monitoring/promql_query_test.go index 3b6af147f77..a21d6dce793 100644 --- a/pkg/tsdb/cloud-monitoring/promql_query_test.go +++ b/pkg/tsdb/cloud-monitoring/promql_query_test.go @@ -58,11 +58,11 @@ func TestPromqlQuery(t *testing.T) { }, } - dr, parsedProm, _, _ := query.run(context.Background(), &backend.QueryDataRequest{}, service, dsInfo, service.logger) - require.Error(t, dr.Error) - require.Equal(t, "not found!", dr.Error.Error()) + dr, parsedProm, _, err := query.run(context.Background(), &backend.QueryDataRequest{}, service, dsInfo, service.logger) + require.Error(t, err) + require.Equal(t, "not found!", err.Error()) - err := query.parseResponse(dr, parsedProm, "", service.logger) + err = query.parseResponse(dr, parsedProm, "", service.logger) require.NoError(t, err) }) } diff --git a/pkg/tsdb/cloud-monitoring/time_series_filter.go b/pkg/tsdb/cloud-monitoring/time_series_filter.go index 8725c7223df..5a387f8990d 100644 --- a/pkg/tsdb/cloud-monitoring/time_series_filter.go +++ b/pkg/tsdb/cloud-monitoring/time_series_filter.go @@ -21,7 +21,7 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesList) run(ctx context.Context, } func parseTimeSeriesResponse(queryRes *backend.DataResponse, - response cloudMonitoringResponse, executedQueryString string, query cloudMonitoringQueryExecutor, params url.Values, groupBys []string, logger log.Logger) error { + response cloudMonitoringResponse, executedQueryString string, query cloudMonitoringQueryExecutor, params url.Values, groupBys []string, _ log.Logger) error { frames := data.Frames{} for _, series := range response.TimeSeries { diff --git a/pkg/tsdb/cloud-monitoring/utils.go b/pkg/tsdb/cloud-monitoring/utils.go index 3b719ff2c7e..f9d10808228 100644 --- a/pkg/tsdb/cloud-monitoring/utils.go +++ b/pkg/tsdb/cloud-monitoring/utils.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana-plugin-sdk-go/backend/tracing" "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) @@ -28,15 +29,15 @@ func addInterval(period string, field *data.Field) error { if err != nil { return err } - if err == nil { - if field.Config != nil { - field.Config.Interval = float64(p.Milliseconds()) - } else { - field.SetConfig(&data.FieldConfig{ - Interval: float64(p.Milliseconds()), - }) - } + + if field.Config != nil { + field.Config.Interval = float64(p.Milliseconds()) + } else { + field.SetConfig(&data.FieldConfig{ + Interval: float64(p.Milliseconds()), + }) } + return nil } @@ -70,7 +71,7 @@ func createRequest(ctx context.Context, dsInfo *datasourceInfo, proxyPass string return req, nil } -func doRequestPage(ctx context.Context, r *http.Request, dsInfo datasourceInfo, params url.Values, body map[string]any, logger log.Logger) (cloudMonitoringResponse, error) { +func doRequestPage(_ context.Context, r *http.Request, dsInfo datasourceInfo, params url.Values, body map[string]any, logger log.Logger) (cloudMonitoringResponse, error) { if params != nil { r.URL.RawQuery = params.Encode() } @@ -84,7 +85,7 @@ func doRequestPage(ctx context.Context, r *http.Request, dsInfo datasourceInfo, } res, err := dsInfo.services[cloudMonitor].client.Do(r) if err != nil { - return cloudMonitoringResponse{}, err + return cloudMonitoringResponse{}, errorsource.DownstreamError(err, false) } defer func() { @@ -124,7 +125,7 @@ func doRequestWithPagination(ctx context.Context, r *http.Request, dsInfo dataso return d, nil } -func traceReq(ctx context.Context, req *backend.QueryDataRequest, dsInfo datasourceInfo, r *http.Request, target string) trace.Span { +func traceReq(ctx context.Context, req *backend.QueryDataRequest, dsInfo datasourceInfo, _ *http.Request, target string) trace.Span { _, span := tracing.DefaultTracer().Start(ctx, "cloudMonitoring query", trace.WithAttributes( attribute.String("target", target), attribute.String("from", req.Queries[0].TimeRange.From.String()), @@ -141,8 +142,7 @@ func runTimeSeriesRequest(ctx context.Context, req *backend.QueryDataRequest, dr := &backend.DataResponse{} projectName, err := s.ensureProject(ctx, dsInfo, projectName) if err != nil { - dr.Error = err - return dr, cloudMonitoringResponse{}, "", nil + return dr, cloudMonitoringResponse{}, "", err } timeSeriesMethod := "timeSeries" if body != nil { @@ -150,8 +150,7 @@ func runTimeSeriesRequest(ctx context.Context, req *backend.QueryDataRequest, } r, err := createRequest(ctx, &dsInfo, path.Join("/v3/projects", projectName, timeSeriesMethod), nil) if err != nil { - dr.Error = err - return dr, cloudMonitoringResponse{}, "", nil + return dr, cloudMonitoringResponse{}, "", err } span := traceReq(ctx, req, dsInfo, r, params.Encode()) @@ -159,8 +158,7 @@ func runTimeSeriesRequest(ctx context.Context, req *backend.QueryDataRequest, d, err := doRequestWithPagination(ctx, r, dsInfo, params, body, logger) if err != nil { - dr.Error = err - return dr, cloudMonitoringResponse{}, "", nil + return dr, cloudMonitoringResponse{}, "", err } return dr, d, r.URL.RawQuery, nil