github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/queryrange/queryrangebase/roundtrip.go (about) 1 // Copyright 2016 The Prometheus Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // 14 // Mostly lifted from prometheus/web/api/v1/api.go. 15 16 package queryrangebase 17 18 import ( 19 "context" 20 "flag" 21 "io" 22 "io/ioutil" 23 "net/http" 24 "time" 25 26 "github.com/grafana/dskit/flagext" 27 "github.com/opentracing/opentracing-go" 28 "github.com/pkg/errors" 29 "github.com/weaveworks/common/httpgrpc" 30 "github.com/weaveworks/common/user" 31 ) 32 33 const day = 24 * time.Hour 34 35 // PassthroughMiddleware is a noop middleware 36 var PassthroughMiddleware = MiddlewareFunc(func(next Handler) Handler { 37 return next 38 }) 39 40 // Config for query_range middleware chain. 41 type Config struct { 42 // Deprecated: SplitQueriesByInterval will be removed in the next major release 43 SplitQueriesByInterval time.Duration `yaml:"split_queries_by_interval"` 44 45 AlignQueriesWithStep bool `yaml:"align_queries_with_step"` 46 ResultsCacheConfig `yaml:"results_cache"` 47 CacheResults bool `yaml:"cache_results"` 48 MaxRetries int `yaml:"max_retries"` 49 ShardedQueries bool `yaml:"parallelise_shardable_queries"` 50 // List of headers which query_range middleware chain would forward to downstream querier. 51 ForwardHeaders flagext.StringSlice `yaml:"forward_headers_list"` 52 } 53 54 // RegisterFlags adds the flags required to config this to the given FlagSet. 55 func (cfg *Config) RegisterFlags(f *flag.FlagSet) { 56 f.IntVar(&cfg.MaxRetries, "querier.max-retries-per-request", 5, "Maximum number of retries for a single request; beyond this, the downstream error is returned.") 57 f.BoolVar(&cfg.AlignQueriesWithStep, "querier.align-querier-with-step", false, "Mutate incoming queries to align their start and end with their step.") 58 f.BoolVar(&cfg.CacheResults, "querier.cache-results", false, "Cache query results.") 59 f.BoolVar(&cfg.ShardedQueries, "querier.parallelise-shardable-queries", true, "Perform query parallelisations based on storage sharding configuration and query ASTs. This feature is supported only by the chunks storage engine.") 60 f.Var(&cfg.ForwardHeaders, "frontend.forward-headers-list", "List of headers forwarded by the query Frontend to downstream querier.") 61 cfg.ResultsCacheConfig.RegisterFlags(f) 62 } 63 64 // Validate validates the config. 65 func (cfg *Config) Validate() error { 66 if cfg.SplitQueriesByInterval != 0 { 67 return errors.New("the yaml flag `split_queries_by_interval` must now be set in the `limits_config` section instead of the `query_range` config section") 68 } 69 if cfg.CacheResults { 70 if err := cfg.ResultsCacheConfig.Validate(); err != nil { 71 return errors.Wrap(err, "invalid ResultsCache config") 72 } 73 } 74 return nil 75 } 76 77 // HandlerFunc is like http.HandlerFunc, but for Handler. 78 type HandlerFunc func(context.Context, Request) (Response, error) 79 80 // Do implements Handler. 81 func (q HandlerFunc) Do(ctx context.Context, req Request) (Response, error) { 82 return q(ctx, req) 83 } 84 85 // Handler is like http.Handle, but specifically for Prometheus query_range calls. 86 type Handler interface { 87 Do(context.Context, Request) (Response, error) 88 } 89 90 // MiddlewareFunc is like http.HandlerFunc, but for Middleware. 91 type MiddlewareFunc func(Handler) Handler 92 93 // Wrap implements Middleware. 94 func (q MiddlewareFunc) Wrap(h Handler) Handler { 95 return q(h) 96 } 97 98 // Middleware is a higher order Handler. 99 type Middleware interface { 100 Wrap(Handler) Handler 101 } 102 103 // MergeMiddlewares produces a middleware that applies multiple middleware in turn; 104 // ie Merge(f,g,h).Wrap(handler) == f.Wrap(g.Wrap(h.Wrap(handler))) 105 func MergeMiddlewares(middleware ...Middleware) Middleware { 106 return MiddlewareFunc(func(next Handler) Handler { 107 for i := len(middleware) - 1; i >= 0; i-- { 108 next = middleware[i].Wrap(next) 109 } 110 return next 111 }) 112 } 113 114 // Tripperware is a signature for all http client-side middleware. 115 type Tripperware func(http.RoundTripper) http.RoundTripper 116 117 // RoundTripFunc is to http.RoundTripper what http.HandlerFunc is to http.Handler. 118 type RoundTripFunc func(*http.Request) (*http.Response, error) 119 120 // RoundTrip implements http.RoundTripper. 121 func (f RoundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) { 122 return f(r) 123 } 124 125 type roundTripper struct { 126 next http.RoundTripper 127 handler Handler 128 codec Codec 129 headers []string 130 } 131 132 // NewRoundTripper merges a set of middlewares into an handler, then inject it into the `next` roundtripper 133 // using the codec to translate requests and responses. 134 func NewRoundTripper(next http.RoundTripper, codec Codec, headers []string, middlewares ...Middleware) http.RoundTripper { 135 transport := roundTripper{ 136 next: next, 137 codec: codec, 138 headers: headers, 139 } 140 transport.handler = MergeMiddlewares(middlewares...).Wrap(&transport) 141 return transport 142 } 143 144 func (q roundTripper) RoundTrip(r *http.Request) (*http.Response, error) { 145 // include the headers specified in the roundTripper during decoding the request. 146 request, err := q.codec.DecodeRequest(r.Context(), r, q.headers) 147 if err != nil { 148 return nil, err 149 } 150 151 if span := opentracing.SpanFromContext(r.Context()); span != nil { 152 request.LogToSpan(span) 153 } 154 155 response, err := q.handler.Do(r.Context(), request) 156 if err != nil { 157 return nil, err 158 } 159 160 return q.codec.EncodeResponse(r.Context(), response) 161 } 162 163 // Do implements Handler. 164 func (q roundTripper) Do(ctx context.Context, r Request) (Response, error) { 165 request, err := q.codec.EncodeRequest(ctx, r) 166 if err != nil { 167 return nil, err 168 } 169 170 if err := user.InjectOrgIDIntoHTTPRequest(ctx, request); err != nil { 171 return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error()) 172 } 173 174 response, err := q.next.RoundTrip(request) 175 if err != nil { 176 return nil, err 177 } 178 defer func() { 179 _, _ = io.Copy(ioutil.Discard, io.LimitReader(response.Body, 1024)) //nolint:errcheck 180 response.Body.Close() 181 }() 182 183 return q.codec.DecodeResponse(ctx, response, r) 184 }