From 49258b135a16d37b1a5f727ffa544a82fe7f771e Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Tue, 31 Jan 2023 19:26:45 +0100 Subject: [PATCH] Prometheus: Refactor error handling logic (#62254) * Refactor error handling logic - Enable query inspector to show error information - Update naming * Change fetch method return signature * update the snapshot * Revert "update the snapshot" This reverts commit 28b26ce426b31ccefe905254edd580e6ba03ada0. --- pkg/tsdb/prometheus/querydata/request.go | 55 ++++++++++++----------- pkg/tsdb/prometheus/querydata/response.go | 15 ++++--- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/pkg/tsdb/prometheus/querydata/request.go b/pkg/tsdb/prometheus/querydata/request.go index 7834c699491..3da374fccd4 100644 --- a/pkg/tsdb/prometheus/querydata/request.go +++ b/pkg/tsdb/prometheus/querydata/request.go @@ -97,10 +97,7 @@ func (s *QueryData) Execute(ctx context.Context, req *backend.QueryDataRequest) if err != nil { return &result, err } - r, err := s.fetch(ctx, s.client, query, req.Headers) - if err != nil { - return &result, err - } + r := s.fetch(ctx, s.client, query, req.Headers) if r == nil { s.log.FromContext(ctx).Debug("Received nilresponse from runQuery", "query", query.Expr) continue @@ -111,69 +108,75 @@ func (s *QueryData) Execute(ctx context.Context, req *backend.QueryDataRequest) return &result, nil } -func (s *QueryData) fetch(ctx context.Context, client *client.Client, q *models.Query, headers map[string]string) (*backend.DataResponse, error) { +func (s *QueryData) fetch(ctx context.Context, client *client.Client, q *models.Query, headers map[string]string) *backend.DataResponse { traceCtx, end := s.trace(ctx, q) defer end() logger := s.log.FromContext(traceCtx) logger.Debug("Sending query", "start", q.Start, "end", q.End, "step", q.Step, "query", q.Expr) - response := &backend.DataResponse{ + dr := &backend.DataResponse{ Frames: data.Frames{}, Error: nil, } if q.InstantQuery { - res, err := s.instantQuery(traceCtx, client, q, headers) - response.Error = err - response.Frames = res.Frames + res := s.instantQuery(traceCtx, client, q, headers) + dr.Error = res.Error + dr.Frames = res.Frames } if q.RangeQuery { - res, err := s.rangeQuery(traceCtx, client, q, headers) - if err != nil { - if response.Error == nil { - response.Error = err + res := s.rangeQuery(traceCtx, client, q, headers) + if res.Error != nil { + if dr.Error == nil { + dr.Error = res.Error } else { - response.Error = fmt.Errorf("%v %w", response.Error, err) + dr.Error = fmt.Errorf("%v %w", dr.Error, res.Error) } } - response.Frames = append(response.Frames, res.Frames...) + dr.Frames = append(dr.Frames, res.Frames...) } if q.ExemplarQuery { - res, err := s.exemplarQuery(traceCtx, client, q, headers) - if err != nil { + res := s.exemplarQuery(traceCtx, client, q, headers) + if res.Error != nil { // If exemplar query returns error, we want to only log it and // continue with other results processing - logger.Error("Exemplar query failed", "query", q.Expr, "err", err) + logger.Error("Exemplar query failed", "query", q.Expr, "err", res.Error) } - response.Frames = append(response.Frames, res.Frames...) + dr.Frames = append(dr.Frames, res.Frames...) } - return response, nil + return dr } -func (s *QueryData) rangeQuery(ctx context.Context, c *client.Client, q *models.Query, headers map[string]string) (backend.DataResponse, error) { +func (s *QueryData) rangeQuery(ctx context.Context, c *client.Client, q *models.Query, headers map[string]string) backend.DataResponse { res, err := c.QueryRange(ctx, q) if err != nil { - return backend.DataResponse{}, err + return backend.DataResponse{ + Error: err, + } } return s.parseResponse(ctx, q, res) } -func (s *QueryData) instantQuery(ctx context.Context, c *client.Client, q *models.Query, headers map[string]string) (backend.DataResponse, error) { +func (s *QueryData) instantQuery(ctx context.Context, c *client.Client, q *models.Query, headers map[string]string) backend.DataResponse { res, err := c.QueryInstant(ctx, q) if err != nil { - return backend.DataResponse{}, err + return backend.DataResponse{ + Error: err, + } } return s.parseResponse(ctx, q, res) } -func (s *QueryData) exemplarQuery(ctx context.Context, c *client.Client, q *models.Query, headers map[string]string) (backend.DataResponse, error) { +func (s *QueryData) exemplarQuery(ctx context.Context, c *client.Client, q *models.Query, headers map[string]string) backend.DataResponse { res, err := c.QueryExemplars(ctx, q) if err != nil { - return backend.DataResponse{}, err + return backend.DataResponse{ + Error: err, + } } return s.parseResponse(ctx, q, res) } diff --git a/pkg/tsdb/prometheus/querydata/response.go b/pkg/tsdb/prometheus/querydata/response.go index 55745272109..6864e5814b5 100644 --- a/pkg/tsdb/prometheus/querydata/response.go +++ b/pkg/tsdb/prometheus/querydata/response.go @@ -17,7 +17,7 @@ import ( "github.com/grafana/grafana/pkg/util/converter" ) -func (s *QueryData) parseResponse(ctx context.Context, q *models.Query, res *http.Response) (backend.DataResponse, error) { +func (s *QueryData) parseResponse(ctx context.Context, q *models.Query, res *http.Response) backend.DataResponse { defer func() { if err := res.Body.Close(); err != nil { s.log.FromContext(ctx).Error("Failed to close response body", "err", err) @@ -30,6 +30,12 @@ func (s *QueryData) parseResponse(ctx context.Context, q *models.Query, res *htt VectorWideSeries: s.enableWideSeries, }) + // Add frame to attach metadata + if len(r.Frames) == 0 && !q.ExemplarQuery { + r.Frames = append(r.Frames, data.NewFrame("")) + } + + // The ExecutedQueryString can be viewed in QueryInspector in UI for _, frame := range r.Frames { if s.enableWideSeries { addMetadataToWideFrame(q, frame) @@ -38,12 +44,11 @@ func (s *QueryData) parseResponse(ctx context.Context, q *models.Query, res *htt } } - if r.Error != nil { - return r, r.Error + if r.Error == nil { + r = s.processExemplars(q, r) } - r = s.processExemplars(q, r) - return r, nil + return r } func (s *QueryData) processExemplars(q *models.Query, dr backend.DataResponse) backend.DataResponse {