mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Adjust to logging convention (#74531)
* adjust Loki to logging convention * Fix call resource logging * Update dataquery * Update * Remove redundant logging * Fix TODO * Rename action to stage and use variables * `resp` might be `nil` * `resp` might be `nil` here as well * change to `statusCode` * use correct logger * also here * add query information to logging --------- Co-authored-by: Ivana Huckova <ivana.huckova@gmail.com>
This commit is contained in:
parent
8d04f1daea
commit
d14851c877
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -158,26 +159,35 @@ func (api *LokiAPI) DataQuery(ctx context.Context, query lokiQuery, responseOpts
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
api.log.Debug("Sending query to loki", "start", query.Start, "end", query.End, "step", query.Step, "query", query.Expr, "queryType", query.QueryType, "direction", query.Direction, "maxLines", query.MaxLines, "supportingQueryType", query.SupportingQueryType, "lokiHost", req.URL.Host, "lokiPath", req.URL.Path)
|
queryAttrs := []any{"start", query.Start, "end", query.End, "step", query.Step, "query", query.Expr, "queryType", query.QueryType, "direction", query.Direction, "maxLines", query.MaxLines, "supportingQueryType", query.SupportingQueryType, "lokiHost", req.URL.Host, "lokiPath", req.URL.Path}
|
||||||
|
api.log.Debug("Sending query to loki", queryAttrs...)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
resp, err := api.client.Do(req)
|
resp, err := api.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
status := "error"
|
||||||
|
if errors.Is(err, context.Canceled) {
|
||||||
|
status = "cancelled"
|
||||||
|
}
|
||||||
|
lp := []any{"error", err, "status", status, "duration", time.Since(start), "stage", stageDatabaseRequest}
|
||||||
|
lp = append(lp, queryAttrs...)
|
||||||
|
if resp != nil {
|
||||||
|
lp = append(lp, "statusCode", resp.StatusCode)
|
||||||
|
}
|
||||||
|
api.log.Error("Error received from Loki", lp...)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
took := time.Since(start)
|
api.log.Info("Response received from loki", "duration", time.Since(start), "statusCode", resp.StatusCode, "contentLength", resp.Header.Get("Content-Length"), "stage", stageDatabaseRequest, "status", "ok")
|
||||||
api.log.Debug("Response received from loki", "took", took, "status", resp.StatusCode, "length", resp.Header.Get("Content-Length"))
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := resp.Body.Close(); err != nil {
|
if err := resp.Body.Close(); err != nil {
|
||||||
api.log.Warn("Failed to close response body", "err", err)
|
api.log.Warn("Failed to close response body", "error", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if resp.StatusCode/100 != 2 {
|
if resp.StatusCode/100 != 2 {
|
||||||
err := readLokiError(resp.Body)
|
err := readLokiError(resp.Body)
|
||||||
api.log.Error("Error received from loki", "err", err, "status", resp.StatusCode)
|
api.log.Error("Error received from loki", "error", err, "status", resp.StatusCode)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,16 +198,15 @@ func (api *LokiAPI) DataQuery(ctx context.Context, query lokiQuery, responseOpts
|
|||||||
|
|
||||||
iter := jsoniter.Parse(jsoniter.ConfigDefault, resp.Body, 1024)
|
iter := jsoniter.Parse(jsoniter.ConfigDefault, resp.Body, 1024)
|
||||||
res := converter.ReadPrometheusStyleResult(iter, converter.Options{Dataplane: responseOpts.metricDataplane})
|
res := converter.ReadPrometheusStyleResult(iter, converter.Options{Dataplane: responseOpts.metricDataplane})
|
||||||
took = time.Since(start)
|
|
||||||
|
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
span.RecordError(res.Error)
|
span.RecordError(res.Error)
|
||||||
span.SetStatus(codes.Error, err.Error())
|
span.SetStatus(codes.Error, err.Error())
|
||||||
logger.Error("Error parsing response from loki", "err", res.Error, "metricDataplane", responseOpts.metricDataplane, "took", took)
|
api.log.Error("Error parsing response from loki", "error", res.Error, "metricDataplane", responseOpts.metricDataplane, "duration", time.Since(start), "stage", stageParseResponse)
|
||||||
return nil, res.Error
|
return nil, res.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("Response parsed from loki", "took", took, "metricDataplane", responseOpts.metricDataplane, "framesLength", len(res.Frames))
|
api.log.Info("Response parsed from loki", "duration", time.Since(start), "metricDataplane", responseOpts.metricDataplane, "framesLength", len(res.Frames), "stage", stageParseResponse)
|
||||||
|
|
||||||
return res.Frames, nil
|
return res.Frames, nil
|
||||||
}
|
}
|
||||||
@ -228,25 +237,33 @@ func makeRawRequest(ctx context.Context, lokiDsUrl string, resourcePath string)
|
|||||||
|
|
||||||
func (api *LokiAPI) RawQuery(ctx context.Context, resourcePath string) (RawLokiResponse, error) {
|
func (api *LokiAPI) RawQuery(ctx context.Context, resourcePath string) (RawLokiResponse, error) {
|
||||||
api.log.Debug("Sending raw query to loki", "resourcePath", resourcePath)
|
api.log.Debug("Sending raw query to loki", "resourcePath", resourcePath)
|
||||||
start := time.Now()
|
|
||||||
req, err := makeRawRequest(ctx, api.url, resourcePath)
|
req, err := makeRawRequest(ctx, api.url, resourcePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.log.Error("Failed to prepare request to loki", "err", err, "resourcePath", resourcePath)
|
api.log.Error("Failed to prepare request to loki", "error", err, "resourcePath", resourcePath)
|
||||||
return RawLokiResponse{}, err
|
return RawLokiResponse{}, err
|
||||||
}
|
}
|
||||||
|
start := time.Now()
|
||||||
resp, err := api.client.Do(req)
|
resp, err := api.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
status := "error"
|
||||||
|
if errors.Is(err, context.Canceled) {
|
||||||
|
status = "cancelled"
|
||||||
|
}
|
||||||
|
lp := []any{"error", err, "resourcePath", resourcePath, "status", status, "duration", time.Since(start), "stage", stageDatabaseRequest}
|
||||||
|
if resp != nil {
|
||||||
|
lp = append(lp, "statusCode", resp.StatusCode)
|
||||||
|
}
|
||||||
|
api.log.Error("Error received from Loki", lp...)
|
||||||
return RawLokiResponse{}, err
|
return RawLokiResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := resp.Body.Close(); err != nil {
|
if err := resp.Body.Close(); err != nil {
|
||||||
api.log.Warn("Failed to close response body", "err", err)
|
api.log.Warn("Failed to close response body", "error", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
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"))
|
api.log.Info("Response received from loki", "status", "ok", "statusCode", resp.StatusCode, "contentLength", resp.Header.Get("Content-Length"), "duration", time.Since(start), "contentEncoding", resp.Header.Get("Content-Encoding"), "stage", stageDatabaseRequest)
|
||||||
|
|
||||||
// server errors are handled by the plugin-proxy to hide the error message
|
// server errors are handled by the plugin-proxy to hide the error message
|
||||||
if resp.StatusCode/100 == 5 {
|
if resp.StatusCode/100 == 5 {
|
||||||
@ -255,13 +272,14 @@ func (api *LokiAPI) RawQuery(ctx context.Context, resourcePath string) (RawLokiR
|
|||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
api.log.Error("Error reading response body bytes", "error", err)
|
||||||
return RawLokiResponse{}, err
|
return RawLokiResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// client errors are passed as a json struct to the client
|
// client errors are passed as a json struct to the client
|
||||||
if resp.StatusCode/100 != 2 {
|
if resp.StatusCode/100 != 2 {
|
||||||
lokiResponseErr := lokiResponseError{Message: makeLokiError(body).Error()}
|
lokiResponseErr := lokiResponseError{Message: makeLokiError(body).Error()}
|
||||||
api.log.Warn("Non 200 HTTP status received from loki", "err", lokiResponseErr.Message, "status", resp.StatusCode, "resourcePath", resourcePath)
|
api.log.Warn("Non 200 HTTP status received from loki", "error", lokiResponseErr.Message, "statusCode", resp.StatusCode, "resourcePath", resourcePath)
|
||||||
traceID := tracing.TraceIDFromContext(ctx, false)
|
traceID := tracing.TraceIDFromContext(ctx, false)
|
||||||
if traceID != "" {
|
if traceID != "" {
|
||||||
lokiResponseErr.TraceID = traceID
|
lokiResponseErr.TraceID = traceID
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
||||||
@ -52,6 +53,13 @@ var (
|
|||||||
legendFormat = regexp.MustCompile(`\{\{\s*(.+?)\s*\}\}`)
|
legendFormat = regexp.MustCompile(`\{\{\s*(.+?)\s*\}\}`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Used in logging to mark a stage
|
||||||
|
var (
|
||||||
|
stagePrepareRequest = "prepareRequest"
|
||||||
|
stageDatabaseRequest = "databaseRequest"
|
||||||
|
stageParseResponse = "parseResponse"
|
||||||
|
)
|
||||||
|
|
||||||
type datasourceInfo struct {
|
type datasourceInfo struct {
|
||||||
HTTPClient *http.Client
|
HTTPClient *http.Client
|
||||||
URL string
|
URL string
|
||||||
@ -101,9 +109,9 @@ func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst
|
|||||||
|
|
||||||
func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
|
func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
|
||||||
dsInfo, err := s.getDSInfo(ctx, req.PluginContext)
|
dsInfo, err := s.getDSInfo(ctx, req.PluginContext)
|
||||||
logger := logger.FromContext(ctx).New("api", "CallResource")
|
logger := s.logger.FromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to get data source info", "err", err)
|
logger.Error("Failed to get data source info", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return callResource(ctx, req, sender, dsInfo, logger, s.tracer)
|
return callResource(ctx, req, sender, dsInfo, logger, s.tracer)
|
||||||
@ -154,7 +162,7 @@ func callResource(ctx context.Context, req *backend.CallResourceRequest, sender
|
|||||||
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||||
dsInfo, err := s.getDSInfo(ctx, req.PluginContext)
|
dsInfo, err := s.getDSInfo(ctx, req.PluginContext)
|
||||||
_, fromAlert := req.Headers[ngalertmodels.FromAlertHeaderName]
|
_, fromAlert := req.Headers[ngalertmodels.FromAlertHeaderName]
|
||||||
logger := logger.FromContext(ctx).New("api", "QueryData", "fromAlert", fromAlert)
|
logger := logger.FromContext(ctx).New("fromAlert", fromAlert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to get data source info", "err", err)
|
logger.Error("Failed to get data source info", "err", err)
|
||||||
result := backend.NewQueryDataResponse()
|
result := backend.NewQueryDataResponse()
|
||||||
@ -174,11 +182,13 @@ func queryData(ctx context.Context, req *backend.QueryDataRequest, dsInfo *datas
|
|||||||
|
|
||||||
api := newLokiAPI(dsInfo.HTTPClient, dsInfo.URL, plog, tracer)
|
api := newLokiAPI(dsInfo.HTTPClient, dsInfo.URL, plog, tracer)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
queries, err := parseQuery(req)
|
queries, err := parseQuery(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plog.Error("Failed to parse queries", "err", err)
|
plog.Error("Failed to prepare request to Loki", "error", err, "duration", time.Since(start), "queriesLength", len(queries), "stage", stagePrepareRequest)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
plog.Info("Prepared request to Loki", "duration", time.Since(start), "queriesLength", len(queries), "stage", stagePrepareRequest)
|
||||||
|
|
||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
ctx, span := tracer.Start(ctx, "datasource.loki.queryData.runQuery")
|
ctx, span := tracer.Start(ctx, "datasource.loki.queryData.runQuery")
|
||||||
@ -212,7 +222,7 @@ func queryData(ctx context.Context, req *backend.QueryDataRequest, dsInfo *datas
|
|||||||
func runQuery(ctx context.Context, api *LokiAPI, query *lokiQuery, responseOpts ResponseOpts) (data.Frames, error) {
|
func runQuery(ctx context.Context, api *LokiAPI, query *lokiQuery, responseOpts ResponseOpts) (data.Frames, error) {
|
||||||
frames, err := api.DataQuery(ctx, *query, responseOpts)
|
frames, err := api.DataQuery(ctx, *query, responseOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error querying loki", "err", err)
|
logger.Error("Error querying loki", "error", err)
|
||||||
return data.Frames{}, err
|
return data.Frames{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +230,7 @@ func runQuery(ctx context.Context, api *LokiAPI, query *lokiQuery, responseOpts
|
|||||||
err = adjustFrame(frame, query, !responseOpts.metricDataplane, responseOpts.logsDataplane)
|
err = adjustFrame(frame, query, !responseOpts.metricDataplane, responseOpts.logsDataplane)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error adjusting frame", "err", err)
|
logger.Error("Error adjusting frame", "error", err)
|
||||||
return data.Frames{}, err
|
return data.Frames{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user