mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-11 05:47:27 -08:00
web: simplify prefix handling using util/route package.
This commit is contained in:
parent
6c24114a7b
commit
e88e5f680b
|
@ -60,8 +60,7 @@ func New() *Router {
|
|||
return &Router{rtr: httprouter.New()}
|
||||
}
|
||||
|
||||
// WithPrefix returns a router that prefixes all registered routes
|
||||
// with preifx.
|
||||
// WithPrefix returns a router that prefixes all registered routes with prefix.
|
||||
func (r *Router) WithPrefix(prefix string) *Router {
|
||||
return &Router{rtr: r.rtr, prefix: r.prefix + prefix}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/storage/local"
|
||||
"github.com/prometheus/prometheus/util/httputil"
|
||||
"github.com/prometheus/prometheus/util/route"
|
||||
)
|
||||
|
||||
// MetricsService manages the /api HTTP endpoint.
|
||||
|
@ -33,19 +34,15 @@ type MetricsService struct {
|
|||
}
|
||||
|
||||
// RegisterHandler registers the handler for the various endpoints below /api.
|
||||
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),
|
||||
}
|
||||
}
|
||||
mux.Handle(pathPrefix+"/api/query", prometheus.InstrumentHandler(
|
||||
pathPrefix+"/api/query", handler(msrv.Query),
|
||||
))
|
||||
mux.Handle(pathPrefix+"/api/query_range", prometheus.InstrumentHandler(
|
||||
pathPrefix+"/api/query_range", handler(msrv.QueryRange),
|
||||
))
|
||||
mux.Handle(pathPrefix+"/api/metrics", prometheus.InstrumentHandler(
|
||||
pathPrefix+"/api/metrics", handler(msrv.Metrics),
|
||||
))
|
||||
func (msrv *MetricsService) RegisterHandler(router *route.Router) {
|
||||
router.Get("/query", handle("query", msrv.Query))
|
||||
router.Get("/query_range", handle("query_range", msrv.QueryRange))
|
||||
router.Get("/metrics", handle("metrics", msrv.Metrics))
|
||||
}
|
||||
|
||||
func handle(name string, f http.HandlerFunc) http.HandlerFunc {
|
||||
h := httputil.CompressionHandler{
|
||||
Handler: f,
|
||||
}
|
||||
return prometheus.InstrumentHandler(name, h)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/storage/local"
|
||||
"github.com/prometheus/prometheus/util/route"
|
||||
)
|
||||
|
||||
// This is a bit annoying. On one hand, we have to choose a current timestamp
|
||||
|
@ -97,9 +98,10 @@ func TestQuery(t *testing.T) {
|
|||
Storage: storage,
|
||||
QueryEngine: promql.NewEngine(storage),
|
||||
}
|
||||
api.RegisterHandler(http.DefaultServeMux, "")
|
||||
rtr := route.New()
|
||||
api.RegisterHandler(rtr.WithPrefix("/api"))
|
||||
|
||||
server := httptest.NewServer(http.DefaultServeMux)
|
||||
server := httptest.NewServer(rtr)
|
||||
defer server.Close()
|
||||
|
||||
for i, s := range scenarios {
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/prometheus/log"
|
||||
|
||||
"github.com/prometheus/prometheus/util/route"
|
||||
)
|
||||
|
||||
// Sub-directories for templates and static content.
|
||||
|
@ -46,7 +48,9 @@ func GetFile(bucket string, name string) ([]byte, error) {
|
|||
type Handler struct{}
|
||||
|
||||
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.URL.Path
|
||||
ctx := route.Context(r)
|
||||
|
||||
name := strings.Trim(route.Param(ctx, "filepath"), "/")
|
||||
if name == "" {
|
||||
name = "index.html"
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
clientmodel "github.com/prometheus/client_golang/model"
|
||||
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/template"
|
||||
"github.com/prometheus/prometheus/util/route"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -38,7 +40,10 @@ type ConsolesHandler struct {
|
|||
}
|
||||
|
||||
func (h *ConsolesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
file, err := http.Dir(*consoleTemplatesPath).Open(r.URL.Path)
|
||||
ctx := route.Context(r)
|
||||
name := route.Param(ctx, "filepath")
|
||||
|
||||
file, err := http.Dir(*consoleTemplatesPath).Open(name)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
|
@ -67,10 +72,10 @@ func (h *ConsolesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
}{
|
||||
RawParams: rawParams,
|
||||
Params: params,
|
||||
Path: r.URL.Path,
|
||||
Path: name,
|
||||
}
|
||||
|
||||
tmpl := template.NewTemplateExpander(string(text), "__console_"+r.URL.Path, data, clientmodel.Now(), h.QueryEngine, h.PathPrefix)
|
||||
tmpl := template.NewTemplateExpander(string(text), "__console_"+name, data, clientmodel.Now(), h.QueryEngine, h.PathPrefix)
|
||||
filenames, err := filepath.Glob(*consoleLibrariesPath + "/*.lib")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
|
78
web/web.go
78
web/web.go
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/log"
|
||||
"github.com/prometheus/prometheus/util/route"
|
||||
|
||||
clientmodel "github.com/prometheus/client_golang/model"
|
||||
|
||||
|
@ -50,7 +51,7 @@ var (
|
|||
// WebService handles the HTTP endpoints with the exception of /api.
|
||||
type WebService struct {
|
||||
QuitChan chan struct{}
|
||||
mux *http.ServeMux
|
||||
router *route.Router
|
||||
}
|
||||
|
||||
type WebServiceOptions struct {
|
||||
|
@ -64,61 +65,46 @@ type WebServiceOptions struct {
|
|||
|
||||
// NewWebService returns a new WebService.
|
||||
func NewWebService(o *WebServiceOptions) *WebService {
|
||||
mux := http.NewServeMux()
|
||||
router := route.New()
|
||||
|
||||
ws := &WebService{
|
||||
mux: mux,
|
||||
router: router,
|
||||
QuitChan: make(chan struct{}),
|
||||
}
|
||||
|
||||
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 == 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, o.PathPrefix+req.URL.Path, http.StatusFound)
|
||||
} else {
|
||||
http.NotFound(rw, req)
|
||||
}
|
||||
}))
|
||||
mux.Handle(o.PathPrefix+"/alerts", prometheus.InstrumentHandler(
|
||||
o.PathPrefix+"/alerts", o.AlertsHandler,
|
||||
))
|
||||
mux.Handle(o.PathPrefix+"/consoles/", prometheus.InstrumentHandler(
|
||||
o.PathPrefix+"/consoles/", http.StripPrefix(o.PathPrefix+"/consoles/", o.ConsolesHandler),
|
||||
))
|
||||
mux.Handle(o.PathPrefix+"/graph", prometheus.InstrumentHandler(
|
||||
o.PathPrefix+"/graph", o.GraphsHandler,
|
||||
))
|
||||
mux.Handle(o.PathPrefix+"/heap", prometheus.InstrumentHandler(
|
||||
o.PathPrefix+"/heap", http.HandlerFunc(dumpHeap),
|
||||
))
|
||||
if o.PathPrefix != "" {
|
||||
// If the prefix is missing for the root path, append it.
|
||||
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, o.PathPrefix, 301)
|
||||
})
|
||||
router = router.WithPrefix(o.PathPrefix)
|
||||
}
|
||||
|
||||
instr := prometheus.InstrumentHandler
|
||||
|
||||
router.Get("/", instr("status", o.StatusHandler))
|
||||
router.Get("/alerts", instr("alerts", o.AlertsHandler))
|
||||
router.Get("/graph", instr("graph", o.GraphsHandler))
|
||||
router.Get("/heap", instr("heap", http.HandlerFunc(dumpHeap)))
|
||||
|
||||
router.Get(*metricsPath, prometheus.Handler().ServeHTTP)
|
||||
|
||||
o.MetricsHandler.RegisterHandler(router.WithPrefix("/api"))
|
||||
|
||||
router.Get("/consoles/*filepath", instr("consoles", o.ConsolesHandler))
|
||||
|
||||
o.MetricsHandler.RegisterHandler(mux, o.PathPrefix)
|
||||
mux.Handle(o.PathPrefix+*metricsPath, prometheus.Handler())
|
||||
if *useLocalAssets {
|
||||
mux.Handle(o.PathPrefix+"/static/", prometheus.InstrumentHandler(
|
||||
o.PathPrefix+"/static/", http.StripPrefix(o.PathPrefix+"/static/", http.FileServer(http.Dir("web/static"))),
|
||||
))
|
||||
router.Get("/static/*filepath", instr("static", route.FileServe("web/static")))
|
||||
} else {
|
||||
mux.Handle(o.PathPrefix+"/static/", prometheus.InstrumentHandler(
|
||||
o.PathPrefix+"/static/", http.StripPrefix(o.PathPrefix+"/static/", new(blob.Handler)),
|
||||
))
|
||||
router.Get("/static/*filepath", instr("static", blob.Handler{}))
|
||||
}
|
||||
|
||||
if *userAssetsPath != "" {
|
||||
mux.Handle(o.PathPrefix+"/user/", prometheus.InstrumentHandler(
|
||||
o.PathPrefix+"/user/", http.StripPrefix(o.PathPrefix+"/user/", http.FileServer(http.Dir(*userAssetsPath))),
|
||||
))
|
||||
router.Get("/user/*filepath", instr("user", route.FileServe(*userAssetsPath)))
|
||||
}
|
||||
|
||||
if *enableQuit {
|
||||
mux.Handle(o.PathPrefix+"/-/quit", http.HandlerFunc(ws.quitHandler))
|
||||
router.Post("/-/quit", ws.quitHandler)
|
||||
}
|
||||
|
||||
return ws
|
||||
|
@ -130,7 +116,7 @@ func (ws *WebService) Run() {
|
|||
|
||||
// If we cannot bind to a port, retry after 30 seconds.
|
||||
for {
|
||||
err := http.ListenAndServe(*listenAddress, ws.mux)
|
||||
err := http.ListenAndServe(*listenAddress, ws.router)
|
||||
if err != nil {
|
||||
log.Errorf("Could not listen on %s: %s", *listenAddress, err)
|
||||
}
|
||||
|
@ -139,12 +125,6 @@ func (ws *WebService) Run() {
|
|||
}
|
||||
|
||||
func (ws *WebService) quitHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
w.Header().Add("Allow", "POST")
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Requesting termination... Goodbye!")
|
||||
|
||||
close(ws.QuitChan)
|
||||
|
|
Loading…
Reference in a new issue