web: cleanup initialization of web service.

This commit is contained in:
Fabian Reinartz 2015-06-02 13:07:46 +02:00
parent 3247052563
commit 78047326b4
4 changed files with 56 additions and 43 deletions

12
main.go
View file

@ -81,6 +81,7 @@ type prometheus struct {
ruleManager *rules.Manager ruleManager *rules.Manager
targetManager *retrieval.TargetManager targetManager *retrieval.TargetManager
notificationHandler *notification.NotificationHandler notificationHandler *notification.NotificationHandler
statusHandler *web.PrometheusStatusHandler
storage local.Storage storage local.Storage
remoteStorageQueues []*remote.StorageQueueManager remoteStorageQueues []*remote.StorageQueueManager
@ -189,25 +190,26 @@ func NewPrometheus() *prometheus {
QueryEngine: queryEngine, QueryEngine: queryEngine,
} }
webService := &web.WebService{ webService := web.NewWebService(&web.WebServiceOptions{
PathPrefix: *pathPrefix,
StatusHandler: prometheusStatus, StatusHandler: prometheusStatus,
MetricsHandler: metricsService, MetricsHandler: metricsService,
ConsolesHandler: consolesHandler, ConsolesHandler: consolesHandler,
AlertsHandler: alertsHandler, AlertsHandler: alertsHandler,
GraphsHandler: graphsHandler, GraphsHandler: graphsHandler,
} })
p := &prometheus{ p := &prometheus{
queryEngine: queryEngine, queryEngine: queryEngine,
ruleManager: ruleManager, ruleManager: ruleManager,
targetManager: targetManager, targetManager: targetManager,
notificationHandler: notificationHandler, notificationHandler: notificationHandler,
statusHandler: prometheusStatus,
storage: memStorage, storage: memStorage,
remoteStorageQueues: remoteStorageQueues, remoteStorageQueues: remoteStorageQueues,
webService: webService, webService: webService,
} }
webService.QuitChan = make(chan struct{})
if !p.reloadConfig() { if !p.reloadConfig() {
os.Exit(1) os.Exit(1)
@ -227,7 +229,7 @@ func (p *prometheus) reloadConfig() bool {
} }
success := true success := true
success = success && p.webService.StatusHandler.ApplyConfig(conf) success = success && p.statusHandler.ApplyConfig(conf)
success = success && p.targetManager.ApplyConfig(conf) success = success && p.targetManager.ApplyConfig(conf)
success = success && p.ruleManager.ApplyConfig(conf) success = success && p.ruleManager.ApplyConfig(conf)
@ -268,7 +270,7 @@ func (p *prometheus) Serve() {
defer p.queryEngine.Stop() defer p.queryEngine.Stop()
go p.webService.ServeForever(*pathPrefix) go p.webService.Run()
// Wait for reload or termination signals. // Wait for reload or termination signals.
hup := make(chan os.Signal) hup := make(chan os.Signal)

View file

@ -33,19 +33,19 @@ type MetricsService struct {
} }
// RegisterHandler registers the handler for the various endpoints below /api. // RegisterHandler registers the handler for the various endpoints below /api.
func (msrv *MetricsService) RegisterHandler(pathPrefix string) { func (msrv *MetricsService) RegisterHandler(mux *http.ServeMux, pathPrefix string) {
handler := func(h func(http.ResponseWriter, *http.Request)) http.Handler { handler := func(h func(http.ResponseWriter, *http.Request)) http.Handler {
return httputil.CompressionHandler{ return httputil.CompressionHandler{
Handler: http.HandlerFunc(h), Handler: http.HandlerFunc(h),
} }
} }
http.Handle(pathPrefix+"/api/query", prometheus.InstrumentHandler( mux.Handle(pathPrefix+"/api/query", prometheus.InstrumentHandler(
pathPrefix+"/api/query", handler(msrv.Query), pathPrefix+"/api/query", handler(msrv.Query),
)) ))
http.Handle(pathPrefix+"/api/query_range", prometheus.InstrumentHandler( mux.Handle(pathPrefix+"/api/query_range", prometheus.InstrumentHandler(
pathPrefix+"/api/query_range", handler(msrv.QueryRange), pathPrefix+"/api/query_range", handler(msrv.QueryRange),
)) ))
http.Handle(pathPrefix+"/api/metrics", prometheus.InstrumentHandler( mux.Handle(pathPrefix+"/api/metrics", prometheus.InstrumentHandler(
pathPrefix+"/api/metrics", handler(msrv.Metrics), pathPrefix+"/api/metrics", handler(msrv.Metrics),
)) ))
} }

View file

@ -97,7 +97,7 @@ func TestQuery(t *testing.T) {
Storage: storage, Storage: storage,
QueryEngine: promql.NewEngine(storage), QueryEngine: promql.NewEngine(storage),
} }
api.RegisterHandler("") api.RegisterHandler(http.DefaultServeMux, "")
server := httptest.NewServer(http.DefaultServeMux) server := httptest.NewServer(http.DefaultServeMux)
defer server.Close() defer server.Close()

View file

@ -49,77 +49,88 @@ var (
// WebService handles the HTTP endpoints with the exception of /api. // WebService handles the HTTP endpoints with the exception of /api.
type WebService struct { type WebService struct {
QuitChan chan struct{}
mux *http.ServeMux
}
type WebServiceOptions struct {
PathPrefix string
StatusHandler *PrometheusStatusHandler StatusHandler *PrometheusStatusHandler
MetricsHandler *api.MetricsService MetricsHandler *api.MetricsService
AlertsHandler *AlertsHandler AlertsHandler *AlertsHandler
ConsolesHandler *ConsolesHandler ConsolesHandler *ConsolesHandler
GraphsHandler *GraphsHandler GraphsHandler *GraphsHandler
QuitChan chan struct{}
} }
// ServeForever serves the HTTP endpoints and only returns upon errors. // NewWebService returns a new WebService.
func (ws WebService) ServeForever(pathPrefix string) { func NewWebService(o *WebServiceOptions) *WebService {
mux := http.NewServeMux()
http.Handle("/favicon.ico", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ws := &WebService{
http.Error(w, "", 404) mux: mux,
})) QuitChan: make(chan struct{}),
}
http.HandleFunc("/", prometheus.InstrumentHandlerFunc(pathPrefix, func(rw http.ResponseWriter, req *http.Request) { mux.HandleFunc("/", prometheus.InstrumentHandlerFunc(o.PathPrefix, func(rw http.ResponseWriter, req *http.Request) {
// The "/" pattern matches everything, so we need to check // The "/" pattern matches everything, so we need to check
// that we're at the root here. // that we're at the root here.
if req.URL.Path == pathPrefix+"/" { if req.URL.Path == o.PathPrefix+"/" {
ws.StatusHandler.ServeHTTP(rw, req) o.StatusHandler.ServeHTTP(rw, req)
} else if req.URL.Path == pathPrefix { } else if req.URL.Path == o.PathPrefix {
http.Redirect(rw, req, pathPrefix+"/", http.StatusFound) http.Redirect(rw, req, o.PathPrefix+"/", http.StatusFound)
} else if !strings.HasPrefix(req.URL.Path, pathPrefix+"/") { } else if !strings.HasPrefix(req.URL.Path, o.PathPrefix+"/") {
// We're running under a prefix but the user requested something // We're running under a prefix but the user requested something
// outside of it. Let's see if this page exists under the prefix. // outside of it. Let's see if this page exists under the prefix.
http.Redirect(rw, req, pathPrefix+req.URL.Path, http.StatusFound) http.Redirect(rw, req, o.PathPrefix+req.URL.Path, http.StatusFound)
} else { } else {
http.NotFound(rw, req) http.NotFound(rw, req)
} }
})) }))
http.Handle(pathPrefix+"/alerts", prometheus.InstrumentHandler( mux.Handle(o.PathPrefix+"/alerts", prometheus.InstrumentHandler(
pathPrefix+"/alerts", ws.AlertsHandler, o.PathPrefix+"/alerts", o.AlertsHandler,
)) ))
http.Handle(pathPrefix+"/consoles/", prometheus.InstrumentHandler( mux.Handle(o.PathPrefix+"/consoles/", prometheus.InstrumentHandler(
pathPrefix+"/consoles/", http.StripPrefix(pathPrefix+"/consoles/", ws.ConsolesHandler), o.PathPrefix+"/consoles/", http.StripPrefix(o.PathPrefix+"/consoles/", o.ConsolesHandler),
)) ))
http.Handle(pathPrefix+"/graph", prometheus.InstrumentHandler( mux.Handle(o.PathPrefix+"/graph", prometheus.InstrumentHandler(
pathPrefix+"/graph", ws.GraphsHandler, o.PathPrefix+"/graph", o.GraphsHandler,
)) ))
http.Handle(pathPrefix+"/heap", prometheus.InstrumentHandler( mux.Handle(o.PathPrefix+"/heap", prometheus.InstrumentHandler(
pathPrefix+"/heap", http.HandlerFunc(dumpHeap), o.PathPrefix+"/heap", http.HandlerFunc(dumpHeap),
)) ))
ws.MetricsHandler.RegisterHandler(pathPrefix) o.MetricsHandler.RegisterHandler(mux, o.PathPrefix)
http.Handle(pathPrefix+*metricsPath, prometheus.Handler()) mux.Handle(o.PathPrefix+*metricsPath, prometheus.Handler())
if *useLocalAssets { if *useLocalAssets {
http.Handle(pathPrefix+"/static/", prometheus.InstrumentHandler( mux.Handle(o.PathPrefix+"/static/", prometheus.InstrumentHandler(
pathPrefix+"/static/", http.StripPrefix(pathPrefix+"/static/", http.FileServer(http.Dir("web/static"))), o.PathPrefix+"/static/", http.StripPrefix(o.PathPrefix+"/static/", http.FileServer(http.Dir("web/static"))),
)) ))
} else { } else {
http.Handle(pathPrefix+"/static/", prometheus.InstrumentHandler( mux.Handle(o.PathPrefix+"/static/", prometheus.InstrumentHandler(
pathPrefix+"/static/", http.StripPrefix(pathPrefix+"/static/", new(blob.Handler)), o.PathPrefix+"/static/", http.StripPrefix(o.PathPrefix+"/static/", new(blob.Handler)),
)) ))
} }
if *userAssetsPath != "" { if *userAssetsPath != "" {
http.Handle(pathPrefix+"/user/", prometheus.InstrumentHandler( mux.Handle(o.PathPrefix+"/user/", prometheus.InstrumentHandler(
pathPrefix+"/user/", http.StripPrefix(pathPrefix+"/user/", http.FileServer(http.Dir(*userAssetsPath))), o.PathPrefix+"/user/", http.StripPrefix(o.PathPrefix+"/user/", http.FileServer(http.Dir(*userAssetsPath))),
)) ))
} }
if *enableQuit { if *enableQuit {
http.Handle(pathPrefix+"/-/quit", http.HandlerFunc(ws.quitHandler)) mux.Handle(o.PathPrefix+"/-/quit", http.HandlerFunc(ws.quitHandler))
} }
return ws
}
// Run serves the HTTP endpoints.
func (ws *WebService) Run() {
log.Infof("Listening on %s", *listenAddress) log.Infof("Listening on %s", *listenAddress)
// If we cannot bind to a port, retry after 30 seconds. // If we cannot bind to a port, retry after 30 seconds.
for { for {
err := http.ListenAndServe(*listenAddress, nil) err := http.ListenAndServe(*listenAddress, ws.mux)
if err != nil { if err != nil {
log.Errorf("Could not listen on %s: %s", *listenAddress, err) log.Errorf("Could not listen on %s: %s", *listenAddress, err)
} }
@ -127,7 +138,7 @@ func (ws WebService) ServeForever(pathPrefix string) {
} }
} }
func (ws WebService) quitHandler(w http.ResponseWriter, r *http.Request) { func (ws *WebService) quitHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" { if r.Method != "POST" {
w.Header().Add("Allow", "POST") w.Header().Add("Allow", "POST")
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)