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 }