github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/querier/remote_read.go (about)

     1  package querier
     2  
     3  import (
     4  	"net/http"
     5  
     6  	"github.com/go-kit/log"
     7  	"github.com/go-kit/log/level"
     8  	"github.com/prometheus/prometheus/storage"
     9  
    10  	"github.com/cortexproject/cortex/pkg/cortexpb"
    11  	"github.com/cortexproject/cortex/pkg/ingester/client"
    12  	"github.com/cortexproject/cortex/pkg/util"
    13  	util_log "github.com/cortexproject/cortex/pkg/util/log"
    14  )
    15  
    16  // Queries are a set of matchers with time ranges - should not get into megabytes
    17  const maxRemoteReadQuerySize = 1024 * 1024
    18  
    19  // RemoteReadHandler handles Prometheus remote read requests.
    20  func RemoteReadHandler(q storage.Queryable, logger log.Logger) http.Handler {
    21  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    22  		ctx := r.Context()
    23  		var req client.ReadRequest
    24  		logger := util_log.WithContext(r.Context(), logger)
    25  		if err := util.ParseProtoReader(ctx, r.Body, int(r.ContentLength), maxRemoteReadQuerySize, &req, util.RawSnappy); err != nil {
    26  			level.Error(logger).Log("msg", "failed to parse proto", "err", err.Error())
    27  			http.Error(w, err.Error(), http.StatusBadRequest)
    28  			return
    29  		}
    30  
    31  		// Fetch samples for all queries in parallel.
    32  		resp := client.ReadResponse{
    33  			Results: make([]*client.QueryResponse, len(req.Queries)),
    34  		}
    35  		errors := make(chan error)
    36  		for i, qr := range req.Queries {
    37  			go func(i int, qr *client.QueryRequest) {
    38  				from, to, matchers, err := client.FromQueryRequest(qr)
    39  				if err != nil {
    40  					errors <- err
    41  					return
    42  				}
    43  
    44  				querier, err := q.Querier(ctx, int64(from), int64(to))
    45  				if err != nil {
    46  					errors <- err
    47  					return
    48  				}
    49  
    50  				params := &storage.SelectHints{
    51  					Start: int64(from),
    52  					End:   int64(to),
    53  				}
    54  				seriesSet := querier.Select(false, params, matchers...)
    55  				resp.Results[i], err = seriesSetToQueryResponse(seriesSet)
    56  				errors <- err
    57  			}(i, qr)
    58  		}
    59  
    60  		var lastErr error
    61  		for range req.Queries {
    62  			err := <-errors
    63  			if err != nil {
    64  				lastErr = err
    65  			}
    66  		}
    67  		if lastErr != nil {
    68  			http.Error(w, lastErr.Error(), http.StatusBadRequest)
    69  			return
    70  		}
    71  		w.Header().Add("Content-Type", "application/x-protobuf")
    72  		if err := util.SerializeProtoResponse(w, &resp, util.RawSnappy); err != nil {
    73  			level.Error(logger).Log("msg", "error sending remote read response", "err", err)
    74  		}
    75  	})
    76  }
    77  
    78  func seriesSetToQueryResponse(s storage.SeriesSet) (*client.QueryResponse, error) {
    79  	result := &client.QueryResponse{}
    80  
    81  	for s.Next() {
    82  		series := s.At()
    83  		samples := []cortexpb.Sample{}
    84  		it := series.Iterator()
    85  		for it.Next() {
    86  			t, v := it.At()
    87  			samples = append(samples, cortexpb.Sample{
    88  				TimestampMs: t,
    89  				Value:       v,
    90  			})
    91  		}
    92  		if err := it.Err(); err != nil {
    93  			return nil, err
    94  		}
    95  		result.Timeseries = append(result.Timeseries, cortexpb.TimeSeries{
    96  			Labels:  cortexpb.FromLabelsToLabelAdapters(series.Labels()),
    97  			Samples: samples,
    98  		})
    99  	}
   100  
   101  	return result, s.Err()
   102  }