diff --git a/pkg/tsdb/loki/api.go b/pkg/tsdb/loki/api.go index 5ec928a4fdf..cd5b863f0d3 100644 --- a/pkg/tsdb/loki/api.go +++ b/pkg/tsdb/loki/api.go @@ -227,8 +227,11 @@ func makeRawRequest(ctx context.Context, lokiDsUrl string, resourcePath string) } func (api *LokiAPI) RawQuery(ctx context.Context, resourcePath string) (RawLokiResponse, error) { + api.log.Debug("Sending raw query to loki", "resourcePath", resourcePath) + start := time.Now() req, err := makeRawRequest(ctx, api.url, resourcePath) if err != nil { + api.log.Error("Failed to prepare request to loki", "err", err, "resourcePath", resourcePath) return RawLokiResponse{}, err } @@ -243,6 +246,8 @@ func (api *LokiAPI) RawQuery(ctx context.Context, resourcePath string) (RawLokiR } }() + api.log.Debug("Response received from loki", "status", resp.StatusCode, "length", resp.Header.Get("Content-Length"), "took", time.Since(start), "encoding", resp.Header.Get("Content-Encoding")) + // server errors are handled by the plugin-proxy to hide the error message if resp.StatusCode/100 == 5 { return RawLokiResponse{}, readLokiError(resp.Body) @@ -256,6 +261,7 @@ func (api *LokiAPI) RawQuery(ctx context.Context, resourcePath string) (RawLokiR // client errors are passed as a json struct to the client if resp.StatusCode/100 != 2 { lokiResponseErr := lokiResponseError{Message: makeLokiError(body).Error()} + api.log.Warn("Non 200 HTTP status received from loki", "err", lokiResponseErr.Message, "status", resp.StatusCode, "resourcePath", resourcePath) traceID := tracing.TraceIDFromContext(ctx, false) if traceID != "" { lokiResponseErr.TraceID = traceID diff --git a/pkg/tsdb/loki/loki.go b/pkg/tsdb/loki/loki.go index b481a736465..f5f007a4fa2 100644 --- a/pkg/tsdb/loki/loki.go +++ b/pkg/tsdb/loki/loki.go @@ -99,24 +99,27 @@ func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { dsInfo, err := s.getDSInfo(ctx, req.PluginContext) + logger := logger.FromContext(ctx).New("api", "CallResource") if err != nil { + logger.Error("failed to get data source info", "err", err) return err } - return callResource(ctx, req, sender, dsInfo, logger.FromContext(ctx), s.tracer) + return callResource(ctx, req, sender, dsInfo, logger, s.tracer) } func callResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender, dsInfo *datasourceInfo, plog log.Logger, tracer tracing.Tracer) error { url := req.URL - // a very basic is-this-url-valid check if req.Method != "GET" { - return fmt.Errorf("invalid resource method: %s", req.Method) + plog.Error("Invalid HTTP method", "method", req.Method) + return fmt.Errorf("invalid HTTP method: %s", req.Method) } if (!strings.HasPrefix(url, "labels?")) && (!strings.HasPrefix(url, "label/")) && // the `/label/$label_name/values` form (!strings.HasPrefix(url, "series?")) && (!strings.HasPrefix(url, "index/stats?")) { - return fmt.Errorf("invalid resource URL: %s", url) + plog.Error("Invalid URL", "url", url) + return fmt.Errorf("invalid URL: %s", url) } lokiURL := fmt.Sprintf("/loki/api/v1/%s", url) @@ -125,12 +128,14 @@ func callResource(ctx context.Context, req *backend.CallResourceRequest, sender defer span.End() api := newLokiAPI(dsInfo.HTTPClient, dsInfo.URL, plog, tracer) - rawLokiResponse, err := api.RawQuery(ctx, lokiURL) + rawLokiResponse, err := api.RawQuery(ctx, lokiURL) if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + plog.Error("Failed resource call from loki", "err", err, "url", lokiURL) return err } - respHeaders := map[string][]string{ "content-type": {"application/json"}, }