initQuerier registers an internal HTTP router with a Prometheus API backed by the Cortex Queryable. Then it does one of the following: 1. Query-Frontend Enabled: If Cortex has an All or QueryFrontend target, the internal HTTP router is wrapped with Tenant ID parsing middleware and passed to the fro
()
| 386 | // │ │ |
| 387 | // └──────────────────┘ |
| 388 | func (t *Cortex) initQuerier() (serv services.Service, err error) { |
| 389 | // Create a internal HTTP handler that is configured with the Prometheus API routes and points |
| 390 | // to a Prometheus API struct instantiated with the Cortex Queryable. |
| 391 | internalQuerierRouter := api.NewQuerierHandler( |
| 392 | t.Cfg.API, |
| 393 | t.Cfg.Querier, |
| 394 | t.QuerierQueryable, |
| 395 | t.ExemplarQueryable, |
| 396 | t.QuerierEngine, |
| 397 | t.MetadataQuerier, |
| 398 | prometheus.DefaultRegisterer, |
| 399 | util_log.Logger, |
| 400 | ) |
| 401 | |
| 402 | // If the querier is running standalone without the query-frontend or query-scheduler, we must register it's internal |
| 403 | // HTTP handler externally and provide the external Cortex Server HTTP handler to the frontend worker |
| 404 | // to ensure requests it processes use the default middleware instrumentation. |
| 405 | if !t.Cfg.isModuleEnabled(QueryFrontend) && !t.Cfg.isModuleEnabled(QueryScheduler) && !t.Cfg.isModuleEnabled(All) { |
| 406 | // First, register the internal querier handler with the external HTTP server |
| 407 | t.API.RegisterQueryAPI(internalQuerierRouter) |
| 408 | |
| 409 | // Second, set the http.Handler that the frontend worker will use to process requests to point to |
| 410 | // the external HTTP server. This will allow the querier to consolidate query metrics both external |
| 411 | // and internal using the default instrumentation when running as a standalone service. |
| 412 | internalQuerierRouter = t.Server.HTTPServer.Handler |
| 413 | } else { |
| 414 | // Single binary mode requires a query frontend endpoint for the worker. If no frontend and scheduler endpoint |
| 415 | // is configured, Cortex will default to using frontend on localhost on it's own GRPC listening port. |
| 416 | if t.Cfg.Worker.FrontendAddress == "" && t.Cfg.Worker.SchedulerAddress == "" { |
| 417 | address := fmt.Sprintf("127.0.0.1:%d", t.Cfg.Server.GRPCListenPort) |
| 418 | level.Warn(util_log.Logger).Log("msg", "Worker address is empty in single binary mode. Attempting automatic worker configuration. If queries are unresponsive consider configuring the worker explicitly.", "address", address) |
| 419 | t.Cfg.Worker.FrontendAddress = address |
| 420 | } |
| 421 | |
| 422 | // Add a middleware to extract the trace context and add a header. |
| 423 | internalQuerierRouter = nethttp.MiddlewareFunc(opentracing.GlobalTracer(), internalQuerierRouter.ServeHTTP, nethttp.OperationNameFunc(func(r *http.Request) string { |
| 424 | return "internalQuerier" |
| 425 | })) |
| 426 | |
| 427 | // If queries are processed using the external HTTP Server, we need wrap the internal querier with |
| 428 | // HTTP router with middleware to parse the tenant ID from the HTTP header and inject it into the |
| 429 | // request context. |
| 430 | internalQuerierRouter = t.API.AuthMiddleware.Wrap(internalQuerierRouter) |
| 431 | |
| 432 | internalQuerierRouter = t.API.HTTPHeaderMiddleware.Wrap(internalQuerierRouter) |
| 433 | } |
| 434 | |
| 435 | // If neither frontend address or scheduler address is configured, no worker is needed. |
| 436 | if t.Cfg.Worker.FrontendAddress == "" && t.Cfg.Worker.SchedulerAddress == "" { |
| 437 | return nil, nil |
| 438 | } |
| 439 | |
| 440 | t.Cfg.Worker.MaxConcurrentRequests = t.Cfg.Querier.MaxConcurrent |
| 441 | t.Cfg.Worker.TargetHeaders = t.Cfg.API.HTTPRequestHeadersToLog |
| 442 | |
| 443 | t.Cfg.Worker.ListenPort = t.Cfg.Server.GRPCListenPort |
| 444 | |
| 445 | return querier_worker.NewQuerierWorker(t.Cfg.Worker, httpgrpc_server.NewServer(internalQuerierRouter), util_log.Logger, prometheus.DefaultRegisterer) |
nothing calls this directly
no test coverage detected