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

     1  package querier
     2  
     3  import (
     4  	"archive/tar"
     5  	"compress/gzip"
     6  	"net/http"
     7  
     8  	"github.com/prometheus/common/model"
     9  	"github.com/prometheus/prometheus/promql/parser"
    10  	"github.com/prometheus/prometheus/storage"
    11  
    12  	"github.com/cortexproject/cortex/pkg/querier/chunkstore"
    13  	"github.com/cortexproject/cortex/pkg/tenant"
    14  	"github.com/cortexproject/cortex/pkg/util"
    15  )
    16  
    17  // ChunksHandler allows you to fetch a compressed tar of all the chunks for a
    18  // given time range and set of matchers.
    19  // Only works with the new unified chunk querier, which is enabled when you turn
    20  // on ingester chunk query streaming.
    21  func ChunksHandler(queryable storage.Queryable) http.Handler {
    22  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    23  		userID, err := tenant.TenantID(r.Context())
    24  		if err != nil {
    25  			http.Error(w, err.Error(), http.StatusBadRequest)
    26  			return
    27  		}
    28  		mint, err := util.ParseTime(r.FormValue("start"))
    29  		if err != nil {
    30  			http.Error(w, err.Error(), http.StatusBadRequest)
    31  			return
    32  		}
    33  
    34  		maxt, err := util.ParseTime(r.FormValue("end"))
    35  		if err != nil {
    36  			http.Error(w, err.Error(), http.StatusBadRequest)
    37  			return
    38  		}
    39  
    40  		matchers, err := parser.ParseMetricSelector(r.FormValue("matcher"))
    41  		if err != nil {
    42  			http.Error(w, err.Error(), http.StatusBadRequest)
    43  			return
    44  		}
    45  
    46  		querier, err := queryable.Querier(r.Context(), mint, maxt)
    47  		if err != nil {
    48  			http.Error(w, err.Error(), http.StatusInternalServerError)
    49  			return
    50  		}
    51  
    52  		store, ok := querier.(chunkstore.ChunkStore)
    53  		if !ok {
    54  			http.Error(w, "not supported", http.StatusServiceUnavailable)
    55  			return
    56  		}
    57  
    58  		chunks, err := store.Get(r.Context(), userID, model.Time(mint), model.Time(maxt), matchers...)
    59  		if err != nil {
    60  			http.Error(w, err.Error(), http.StatusInternalServerError)
    61  			return
    62  		}
    63  
    64  		w.Header().Add("Content-Type", "application/tar+gzip")
    65  		gw := gzip.NewWriter(w)
    66  		defer gw.Close()
    67  
    68  		writer := tar.NewWriter(gw)
    69  		defer writer.Close()
    70  
    71  		for _, chunk := range chunks {
    72  			buf, err := chunk.Encoded()
    73  			if err != nil {
    74  				http.Error(w, err.Error(), http.StatusInternalServerError)
    75  				return
    76  			}
    77  
    78  			if err := writer.WriteHeader(&tar.Header{
    79  				Name: chunk.ExternalKey(),
    80  				Size: int64(len(buf)),
    81  				Mode: 0600,
    82  			}); err != nil {
    83  				http.Error(w, err.Error(), http.StatusInternalServerError)
    84  				return
    85  			}
    86  
    87  			if _, err := writer.Write(buf); err != nil {
    88  				http.Error(w, err.Error(), http.StatusInternalServerError)
    89  				return
    90  			}
    91  		}
    92  	})
    93  }