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

View file

@ -33,19 +33,19 @@ type MetricsService struct {
}
// 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 {
return httputil.CompressionHandler{
Handler: http.HandlerFunc(h),
}
}
http.Handle(pathPrefix+"/api/query", prometheus.InstrumentHandler(
mux.Handle(pathPrefix+"/api/query", prometheus.InstrumentHandler(
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),
))
http.Handle(pathPrefix+"/api/metrics", prometheus.InstrumentHandler(
mux.Handle(pathPrefix+"/api/metrics", prometheus.InstrumentHandler(
pathPrefix+"/api/metrics", handler(msrv.Metrics),
))
}

View file

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

View file

@ -49,77 +49,88 @@ var (
// WebService handles the HTTP endpoints with the exception of /api.
type WebService struct {
QuitChan chan struct{}
mux *http.ServeMux
}
type WebServiceOptions struct {
PathPrefix string
StatusHandler *PrometheusStatusHandler
MetricsHandler *api.MetricsService
AlertsHandler *AlertsHandler
ConsolesHandler *ConsolesHandler
GraphsHandler *GraphsHandler
QuitChan chan struct{}
}
// ServeForever serves the HTTP endpoints and only returns upon errors.
func (ws WebService) ServeForever(pathPrefix string) {
// NewWebService returns a new WebService.
func NewWebService(o *WebServiceOptions) *WebService {
mux := http.NewServeMux()
http.Handle("/favicon.ico", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "", 404)
}))
ws := &WebService{
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
// that we're at the root here.
if req.URL.Path == pathPrefix+"/" {
ws.StatusHandler.ServeHTTP(rw, req)
} else if req.URL.Path == pathPrefix {
http.Redirect(rw, req, pathPrefix+"/", http.StatusFound)
} else if !strings.HasPrefix(req.URL.Path, pathPrefix+"/") {
if req.URL.Path == o.PathPrefix+"/" {
o.StatusHandler.ServeHTTP(rw, req)
} else if req.URL.Path == o.PathPrefix {
http.Redirect(rw, req, o.PathPrefix+"/", http.StatusFound)
} else if !strings.HasPrefix(req.URL.Path, o.PathPrefix+"/") {
// We're running under a prefix but the user requested something
// 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 {
http.NotFound(rw, req)
}
}))
http.Handle(pathPrefix+"/alerts", prometheus.InstrumentHandler(
pathPrefix+"/alerts", ws.AlertsHandler,
mux.Handle(o.PathPrefix+"/alerts", prometheus.InstrumentHandler(
o.PathPrefix+"/alerts", o.AlertsHandler,
))
http.Handle(pathPrefix+"/consoles/", prometheus.InstrumentHandler(
pathPrefix+"/consoles/", http.StripPrefix(pathPrefix+"/consoles/", ws.ConsolesHandler),
mux.Handle(o.PathPrefix+"/consoles/", prometheus.InstrumentHandler(
o.PathPrefix+"/consoles/", http.StripPrefix(o.PathPrefix+"/consoles/", o.ConsolesHandler),
))
http.Handle(pathPrefix+"/graph", prometheus.InstrumentHandler(
pathPrefix+"/graph", ws.GraphsHandler,
mux.Handle(o.PathPrefix+"/graph", prometheus.InstrumentHandler(
o.PathPrefix+"/graph", o.GraphsHandler,
))
http.Handle(pathPrefix+"/heap", prometheus.InstrumentHandler(
pathPrefix+"/heap", http.HandlerFunc(dumpHeap),
mux.Handle(o.PathPrefix+"/heap", prometheus.InstrumentHandler(
o.PathPrefix+"/heap", http.HandlerFunc(dumpHeap),
))
ws.MetricsHandler.RegisterHandler(pathPrefix)
http.Handle(pathPrefix+*metricsPath, prometheus.Handler())
o.MetricsHandler.RegisterHandler(mux, o.PathPrefix)
mux.Handle(o.PathPrefix+*metricsPath, prometheus.Handler())
if *useLocalAssets {
http.Handle(pathPrefix+"/static/", prometheus.InstrumentHandler(
pathPrefix+"/static/", http.StripPrefix(pathPrefix+"/static/", http.FileServer(http.Dir("web/static"))),
mux.Handle(o.PathPrefix+"/static/", prometheus.InstrumentHandler(
o.PathPrefix+"/static/", http.StripPrefix(o.PathPrefix+"/static/", http.FileServer(http.Dir("web/static"))),
))
} else {
http.Handle(pathPrefix+"/static/", prometheus.InstrumentHandler(
pathPrefix+"/static/", http.StripPrefix(pathPrefix+"/static/", new(blob.Handler)),
mux.Handle(o.PathPrefix+"/static/", prometheus.InstrumentHandler(
o.PathPrefix+"/static/", http.StripPrefix(o.PathPrefix+"/static/", new(blob.Handler)),
))
}
if *userAssetsPath != "" {
http.Handle(pathPrefix+"/user/", prometheus.InstrumentHandler(
pathPrefix+"/user/", http.StripPrefix(pathPrefix+"/user/", http.FileServer(http.Dir(*userAssetsPath))),
mux.Handle(o.PathPrefix+"/user/", prometheus.InstrumentHandler(
o.PathPrefix+"/user/", http.StripPrefix(o.PathPrefix+"/user/", http.FileServer(http.Dir(*userAssetsPath))),
))
}
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)
// If we cannot bind to a port, retry after 30 seconds.
for {
err := http.ListenAndServe(*listenAddress, nil)
err := http.ListenAndServe(*listenAddress, ws.mux)
if err != nil {
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" {
w.Header().Add("Allow", "POST")
w.WriteHeader(http.StatusMethodNotAllowed)