-
Notifications
You must be signed in to change notification settings - Fork 839
feat: simplify query related modules #3320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8d84b2a
95945b6
f72feb7
81a929b
a13a0c4
49ea64f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,34 @@ | ||
| package api | ||
|
|
||
| import ( | ||
| "context" | ||
| "html/template" | ||
| "net/http" | ||
| "path" | ||
| "regexp" | ||
| "sync" | ||
|
|
||
| "github.com/go-kit/kit/log" | ||
| "github.com/go-kit/kit/log/level" | ||
| "github.com/gorilla/mux" | ||
| "github.com/opentracing-contrib/go-stdlib/nethttp" | ||
| "github.com/opentracing/opentracing-go" | ||
| "github.com/pkg/errors" | ||
| "github.com/prometheus/client_golang/prometheus" | ||
| "github.com/prometheus/client_golang/prometheus/promauto" | ||
| dto "github.com/prometheus/client_model/go" | ||
| "github.com/prometheus/common/route" | ||
| "github.com/prometheus/prometheus/config" | ||
| "github.com/prometheus/prometheus/promql" | ||
| "github.com/prometheus/prometheus/storage" | ||
| v1 "github.com/prometheus/prometheus/web/api/v1" | ||
| "github.com/weaveworks/common/instrument" | ||
| "github.com/weaveworks/common/middleware" | ||
| "gopkg.in/yaml.v2" | ||
|
|
||
| "github.com/cortexproject/cortex/pkg/chunk/purger" | ||
| "github.com/cortexproject/cortex/pkg/distributor" | ||
| "github.com/cortexproject/cortex/pkg/querier" | ||
| "github.com/cortexproject/cortex/pkg/util" | ||
| ) | ||
|
|
||
|
|
@@ -109,3 +129,106 @@ func configHandler(cfg interface{}) http.HandlerFunc { | |
| } | ||
| } | ||
| } | ||
|
|
||
| // NewQuerierHandler returns a HTTP handler that can be used by the querier service to | ||
| // either register with the frontend worker query processor or with the external HTTP | ||
| // server to fulfill the Prometheus query API. | ||
| func NewQuerierHandler( | ||
| cfg Config, | ||
| queryable storage.SampleAndChunkQueryable, | ||
| engine *promql.Engine, | ||
| distributor *distributor.Distributor, | ||
| tombstonesLoader *purger.TombstonesLoader, | ||
| reg prometheus.Registerer, | ||
| logger log.Logger, | ||
| ) http.Handler { | ||
| // Prometheus histograms for requests to the querier. | ||
| querierRequestDuration := promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{ | ||
| Namespace: "cortex", | ||
| Name: "querier_request_duration_seconds", | ||
| Help: "Time (in seconds) spent serving HTTP requests to the querier.", | ||
| Buckets: instrument.DefBuckets, | ||
| }, []string{"method", "route", "status_code", "ws"}) | ||
|
|
||
| receivedMessageSize := promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{ | ||
| Namespace: "cortex", | ||
| Name: "querier_request_message_bytes", | ||
| Help: "Size (in bytes) of messages received in the request to the querier.", | ||
| Buckets: middleware.BodySizeBuckets, | ||
| }, []string{"method", "route"}) | ||
|
|
||
| sentMessageSize := promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{ | ||
| Namespace: "cortex", | ||
| Name: "querier_response_message_bytes", | ||
| Help: "Size (in bytes) of messages sent in response by the querier.", | ||
| Buckets: middleware.BodySizeBuckets, | ||
| }, []string{"method", "route"}) | ||
|
|
||
| inflightRequests := promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ | ||
| Namespace: "cortex", | ||
| Name: "querier_inflight_requests", | ||
| Help: "Current number of inflight requests to the querier.", | ||
| }, []string{"method", "route"}) | ||
|
|
||
| api := v1.NewAPI( | ||
| engine, | ||
| errorTranslateQueryable{queryable}, // Translate errors to errors expected by API. | ||
| func(context.Context) v1.TargetRetriever { return &querier.DummyTargetRetriever{} }, | ||
| func(context.Context) v1.AlertmanagerRetriever { return &querier.DummyAlertmanagerRetriever{} }, | ||
| func() config.Config { return config.Config{} }, | ||
| map[string]string{}, // TODO: include configuration flags | ||
| v1.GlobalURLOptions{}, | ||
| func(f http.HandlerFunc) http.HandlerFunc { return f }, | ||
| nil, // Only needed for admin APIs. | ||
| "", // This is for snapshots, which is disabled when admin APIs are disabled. Hence empty. | ||
| false, // Disable admin APIs. | ||
| logger, | ||
| func(context.Context) v1.RulesRetriever { return &querier.DummyRulesRetriever{} }, | ||
| 0, 0, 0, // Remote read samples and concurrency limit. | ||
| regexp.MustCompile(".*"), | ||
| func() (v1.RuntimeInfo, error) { return v1.RuntimeInfo{}, errors.New("not implemented") }, | ||
| &v1.PrometheusVersion{}, | ||
| // This is used for the stats API which we should not support. Or find other ways to. | ||
| prometheus.GathererFunc(func() ([]*dto.MetricFamily, error) { return nil, nil }), | ||
| ) | ||
|
|
||
| router := mux.NewRouter() | ||
|
|
||
| // Use a separate metric for the querier in order to differentiate requests from the query-frontend when | ||
| // running Cortex as a single binary. | ||
| inst := middleware.Instrument{ | ||
| RouteMatcher: router, | ||
| Duration: querierRequestDuration, | ||
| RequestBodySize: receivedMessageSize, | ||
| ResponseBodySize: sentMessageSize, | ||
| InflightRequests: inflightRequests, | ||
| } | ||
| cacheGenHeaderMiddleware := getHTTPCacheGenNumberHeaderSetterMiddleware(tombstonesLoader) | ||
| middlewares := middleware.Merge(inst, cacheGenHeaderMiddleware) | ||
| router.Use(middlewares.Wrap) | ||
|
|
||
| promRouter := route.New().WithPrefix(cfg.ServerPrefix + cfg.PrometheusHTTPPrefix + "/api/v1") | ||
|
||
| api.Register(promRouter) | ||
|
|
||
| legacyPromRouter := route.New().WithPrefix(cfg.ServerPrefix + cfg.LegacyHTTPPrefix + "/api/v1") | ||
| api.Register(legacyPromRouter) | ||
|
|
||
| //TODO(gotjosh): This custom handler is temporary until we're able to vendor the changes in: | ||
| // https://github.com/prometheus/prometheus/pull/7125/files | ||
| router.Path(cfg.PrometheusHTTPPrefix + "/api/v1/metadata").Handler(querier.MetadataHandler(distributor)) | ||
| router.Path(cfg.PrometheusHTTPPrefix + "/api/v1/read").Handler(querier.RemoteReadHandler(queryable)) | ||
| // A prefix is fine because external routes will be registered explicitly | ||
| router.PathPrefix(cfg.PrometheusHTTPPrefix + "/api/v1/").Handler(promRouter) | ||
|
|
||
| //TODO(gotjosh): This custom handler is temporary until we're able to vendor the changes in: | ||
| // https://github.com/prometheus/prometheus/pull/7125/files | ||
| router.Path(cfg.LegacyHTTPPrefix + "/api/v1/metadata").Handler(querier.MetadataHandler(distributor)) | ||
| router.Path(cfg.LegacyHTTPPrefix + "/api/v1/read").Handler(querier.RemoteReadHandler(queryable)) | ||
| // A prefix is fine because external routes will be registered explicitly | ||
| router.PathPrefix(cfg.LegacyHTTPPrefix + "/api/v1/").Handler(legacyPromRouter) | ||
|
|
||
| // Add a middleware to extract the trace context and add a header. | ||
| return nethttp.MiddlewareFunc(opentracing.GlobalTracer(), router.ServeHTTP, nethttp.OperationNameFunc(func(r *http.Request) string { | ||
| return "internalQuerier" | ||
| })) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Who register these now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These routes are registered with the two routers when we call api.Register on them. We end up having to register two routers because the upstream prometheus route library and registration function requires us to register separately for each path prefix.
Previously we explicitly registered every route in the Prometheus API to query handler. However, now we only explicitly register the
metadataandreadroutes because they aren't handled by the upstream API struct. For the rest we register the prefix and since thepromHandlerandlegacyPromHandlerare themselves routers, the requests should be forwarded correctly.Also I should note that the only way to hit these routes is by a request being routed to the
internalQuerierHandlerwhich can only happen if it hit's the routes registered inRegisterQueryAPI, so no new routes should have been exposed and no existing routes should have been removed. This PR just simplified the router that already was only acting as a middleman to the upstream Prometheus routers we already registered with the API struct.