github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/queryrange/split_by_range.go (about)

     1  package queryrange
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/go-kit/log"
     9  	"github.com/go-kit/log/level"
    10  	"github.com/grafana/dskit/tenant"
    11  	"github.com/prometheus/prometheus/promql/parser"
    12  	"github.com/weaveworks/common/httpgrpc"
    13  
    14  	"github.com/grafana/loki/pkg/loghttp"
    15  	"github.com/grafana/loki/pkg/logql"
    16  	"github.com/grafana/loki/pkg/querier/queryrange/queryrangebase"
    17  	util_log "github.com/grafana/loki/pkg/util/log"
    18  	"github.com/grafana/loki/pkg/util/marshal"
    19  	"github.com/grafana/loki/pkg/util/validation"
    20  )
    21  
    22  type splitByRange struct {
    23  	logger  log.Logger
    24  	next    queryrangebase.Handler
    25  	limits  Limits
    26  	ng      *logql.DownstreamEngine
    27  	metrics *logql.MapperMetrics
    28  }
    29  
    30  // NewSplitByRangeMiddleware creates a new Middleware that splits log requests by the range interval.
    31  func NewSplitByRangeMiddleware(logger log.Logger, limits Limits, metrics *logql.MapperMetrics) queryrangebase.Middleware {
    32  	return queryrangebase.MiddlewareFunc(func(next queryrangebase.Handler) queryrangebase.Handler {
    33  		return &splitByRange{
    34  			logger: log.With(logger, "middleware", "InstantQuery.splitByRangeVector"),
    35  			next:   next,
    36  			limits: limits,
    37  			ng: logql.NewDownstreamEngine(logql.EngineOpts{}, DownstreamHandler{
    38  				limits: limits,
    39  				next:   next,
    40  			}, limits, logger),
    41  			metrics: metrics,
    42  		}
    43  	})
    44  }
    45  
    46  func (s *splitByRange) Do(ctx context.Context, request queryrangebase.Request) (queryrangebase.Response, error) {
    47  	logger := util_log.WithContext(ctx, s.logger)
    48  
    49  	tenants, err := tenant.TenantIDs(ctx)
    50  	if err != nil {
    51  		return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error())
    52  	}
    53  
    54  	interval := validation.SmallestPositiveNonZeroDurationPerTenant(tenants, s.limits.QuerySplitDuration)
    55  	// if no interval configured, continue to the next middleware
    56  	if interval == 0 {
    57  		return s.next.Do(ctx, request)
    58  	}
    59  
    60  	mapper, err := logql.NewRangeMapper(interval, s.metrics)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	noop, parsed, err := mapper.Parse(request.GetQuery())
    66  	if err != nil {
    67  		level.Warn(logger).Log("msg", "failed mapping AST", "err", err.Error(), "query", request.GetQuery())
    68  		return nil, err
    69  	}
    70  	level.Debug(logger).Log("msg", "mapped instant query", "interval", interval.String(), "noop", noop, "original", request.GetQuery(), "mapped", parsed.String())
    71  
    72  	if noop {
    73  		// the query cannot be split, so continue
    74  		return s.next.Do(ctx, request)
    75  	}
    76  
    77  	params, err := paramsFromRequest(request)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	if _, ok := request.(*LokiInstantRequest); !ok {
    83  		return nil, fmt.Errorf("expected *LokiInstantRequest")
    84  	}
    85  
    86  	query := s.ng.Query(ctx, params, parsed)
    87  
    88  	res, err := query.Exec(ctx)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	value, err := marshal.NewResultValue(res.Data)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	switch res.Data.Type() {
    99  	case parser.ValueTypeMatrix:
   100  		return &LokiPromResponse{
   101  			Response: &queryrangebase.PrometheusResponse{
   102  				Status: loghttp.QueryStatusSuccess,
   103  				Data: queryrangebase.PrometheusData{
   104  					ResultType: loghttp.ResultTypeMatrix,
   105  					Result:     toProtoMatrix(value.(loghttp.Matrix)),
   106  				},
   107  			},
   108  			Statistics: res.Statistics,
   109  		}, nil
   110  	case parser.ValueTypeVector:
   111  		return &LokiPromResponse{
   112  			Statistics: res.Statistics,
   113  			Response: &queryrangebase.PrometheusResponse{
   114  				Status: loghttp.QueryStatusSuccess,
   115  				Data: queryrangebase.PrometheusData{
   116  					ResultType: loghttp.ResultTypeVector,
   117  					Result:     toProtoVector(value.(loghttp.Vector)),
   118  				},
   119  			},
   120  		}, nil
   121  	default:
   122  		return nil, fmt.Errorf("unexpected downstream response type (%T)", res.Data.Type())
   123  	}
   124  }