func (s *Server) route() { s.r = mux.NewRouter().StrictSlash(true) s.r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { s.serveErrorPage("page not found", http.StatusNotFound, w, r) }) s.r.Path("/").Methods("OPTIONS").HandlerFunc(s.handleProbe) s.r.Path("/robots.txt").HandlerFunc(s.handleRobotsTxt) s.r.Path("/metrics").Handler( prometheus.InstrumentHandler("metrics", prometheus.UninstrumentedHandler())) s.r.PathPrefix("/static/").Handler( prometheus.InstrumentHandler("static", http.HandlerFunc(s.handleStatic))) s.r.Handle("/", prometheus.InstrumentHandlerFunc("home", s.handleHomeStatic)) s.r.PathPrefix("/about").Handler( prometheus.InstrumentHandler("about", http.HandlerFunc(s.handleAboutStatic))) s.r.HandleFunc("/room/{prefix:(pm:)?}{room:[a-z0-9]+}/ws", instrumentSocketHandlerFunc("ws", s.handleRoom)) s.r.Handle( "/room/{prefix:(pm:)?}{room:[a-z0-9]+}/", prometheus.InstrumentHandlerFunc("room_static", s.handleRoomStatic)) s.r.Handle( "/prefs/reset-password", prometheus.InstrumentHandlerFunc("prefsResetPassword", s.handlePrefsResetPassword)) s.r.Handle( "/prefs/verify", prometheus.InstrumentHandlerFunc("prefsVerify", s.handlePrefsVerify)) }
func (s *Server) route() { s.r = mux.NewRouter().StrictSlash(true) s.r.Path("/").Methods("OPTIONS").HandlerFunc(s.handleProbe) s.r.Path("/robots.txt").HandlerFunc(s.handleRobotsTxt) s.r.Path("/metrics").Handler( prometheus.InstrumentHandler("metrics", prometheus.UninstrumentedHandler())) s.r.PathPrefix("/static/").Handler( prometheus.InstrumentHandler("static", http.StripPrefix("/static", http.HandlerFunc(s.handleStatic)))) s.r.Handle("/", prometheus.InstrumentHandlerFunc("home", s.handleHomeStatic)) s.r.PathPrefix("/about").Handler( prometheus.InstrumentHandler("about", http.HandlerFunc(s.handleAboutStatic))) s.r.HandleFunc("/room/{room:[a-z0-9]+}/ws", instrumentSocketHandlerFunc("ws", s.handleRoom)) s.r.Handle( "/room/{room:[a-z0-9]+}/", prometheus.InstrumentHandlerFunc("room_static", s.handleRoomStatic)) s.r.Handle( "/prefs/reset-password", prometheus.InstrumentHandlerFunc("prefsResetPassword", s.handleResetPassword)) s.r.Handle( "/prefs/verify", prometheus.InstrumentHandlerFunc("prefsVerify", s.handlePrefsVerify)) }
// LegacyDelete returns a handler that accepts delete requests. It deals with // the deprecated API. // // The returned handler is already instrumented for Prometheus. func LegacyDelete(ms storage.MetricStore) func(http.ResponseWriter, *http.Request, httprouter.Params) { var ps httprouter.Params var mtx sync.Mutex // Protects ps. instrumentedHandlerFunc := prometheus.InstrumentHandlerFunc( "delete", func(w http.ResponseWriter, _ *http.Request) { job := ps.ByName("job") instance := ps.ByName("instance") mtx.Unlock() if job == "" { http.Error(w, "job name is required", http.StatusBadRequest) return } labels := map[string]string{"job": job} if instance != "" { labels["instance"] = instance } ms.SubmitWriteRequest(storage.WriteRequest{ Labels: labels, Timestamp: time.Now(), }) w.WriteHeader(http.StatusAccepted) }, ) return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) { mtx.Lock() ps = params instrumentedHandlerFunc(w, r) } }
// Delete returns a handler that accepts delete requests. // // The returned handler is already instrumented for Prometheus. func Delete(ms storage.MetricStore) func(http.ResponseWriter, *http.Request, httprouter.Params) { var ps httprouter.Params var mtx sync.Mutex // Protects ps. instrumentedHandlerFunc := prometheus.InstrumentHandlerFunc( "delete", func(w http.ResponseWriter, _ *http.Request) { job := ps.ByName("job") labelsString := ps.ByName("labels") mtx.Unlock() labels, err := splitLabels(labelsString) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if job == "" { http.Error(w, "job name is required", http.StatusBadRequest) return } labels["job"] = job ms.SubmitWriteRequest(storage.WriteRequest{ Labels: labels, Timestamp: time.Now(), }) w.WriteHeader(http.StatusAccepted) }, ) return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) { mtx.Lock() ps = params instrumentedHandlerFunc(w, r) } }
// Register registers the API handlers under their correct routes // in the given router. func (api *API) Register(r *route.Router) { ihf := func(name string, f http.HandlerFunc) http.HandlerFunc { return prometheus.InstrumentHandlerFunc(name, func(w http.ResponseWriter, r *http.Request) { setCORS(w) f(w, r) }) } r.Options("/*path", ihf("options", func(w http.ResponseWriter, r *http.Request) {})) // Register legacy forwarder for alert pushing. r.Post("/alerts", ihf("legacy_add_alerts", api.legacyAddAlerts)) // Register actual API. r = r.WithPrefix("/v1") r.Get("/status", ihf("status", api.status)) r.Get("/alerts/groups", ihf("alert_groups", api.alertGroups)) r.Get("/alerts", ihf("list_alerts", api.listAlerts)) r.Post("/alerts", ihf("add_alerts", api.addAlerts)) r.Get("/silences", ihf("list_silences", api.listSilences)) r.Post("/silences", ihf("add_silence", api.addSilence)) r.Get("/silence/:sid", ihf("get_silence", api.getSilence)) r.Del("/silence/:sid", ihf("del_silence", api.delSilence)) }
// Endpoints is a listing of all endpoints available in the svc. func (s *svc) Endpoints() map[string]map[string]http.HandlerFunc { dirs := s.conf.GetDirectives() authenticator := lib.NewAuthenticator(dirs.Server.JWTSecret, dirs.Server.JWTSigningMethod) return map[string]map[string]http.HandlerFunc{ "/metrics": { "GET": func(w http.ResponseWriter, r *http.Request) { prometheus.Handler().ServeHTTP(w, r) }, }, "/upload/{path:.*}": { "PUT": prometheus.InstrumentHandlerFunc("/upload", authenticator.JWTHandlerFunc(s.Upload)), }, "/download/{path:.*}": { "GET": prometheus.InstrumentHandlerFunc("/download", authenticator.JWTHandlerFunc(s.Download)), }, } }
// Endpoints is a listing of all endpoints available in the Mixedsvc. func (s *svc) Endpoints() map[string]map[string]http.HandlerFunc { dirs := s.conf.GetDirectives() authenticator := lib.NewAuthenticator(dirs.Server.JWTSecret, dirs.Server.JWTSigningMethod) return map[string]map[string]http.HandlerFunc{ "/metrics": { "GET": func(w http.ResponseWriter, r *http.Request) { prometheus.Handler().ServeHTTP(w, r) }, }, "/token": { "POST": prometheus.InstrumentHandlerFunc("/token", s.Token), }, "/ping": { "GET": prometheus.InstrumentHandlerFunc("/ping", authenticator.JWTHandlerFunc(s.Ping)), }, } }
func (s *ServerContext) ServeHTTP(w http.ResponseWriter, req *http.Request) { log.Printf("Request: %s %s", req.Method, req.URL.Path) switch req.URL.Path { case *metricsEndpoint: prometheus.Handler().ServeHTTP(w, req) case *annoEndpoint: prometheus.InstrumentHandlerFunc(*annoEndpoint, s.annotations)(w, req) default: http.Error(w, "Not found", 404) } }
func instrumentSocketHandlerFunc(name string, handler http.HandlerFunc) http.HandlerFunc { type hijackerKey int var k hijackerKey loadHijacker := func(w http.ResponseWriter, r *http.Request) { if hj, ok := gorillactx.GetOk(r, k); ok { w = &hijackResponseWriter{ResponseWriter: w, Hijacker: hj.(http.Hijacker)} } handler(w, r) } promHandler := prometheus.InstrumentHandlerFunc(name, loadHijacker) saveHijacker := func(w http.ResponseWriter, r *http.Request) { if hj, ok := w.(http.Hijacker); ok { gorillactx.Set(r, k, hj) } promHandler(w, r) } return saveHijacker }
func (w WebService) ServeForever(pathPrefix string) error { http.Handle(pathPrefix+"favicon.ico", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "", 404) })) http.HandleFunc("/", prometheus.InstrumentHandlerFunc("index", 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 { w.AlertsHandler.ServeHTTP(rw, req) } else if req.URL.Path == strings.TrimRight(pathPrefix, "/") { http.Redirect(rw, req, pathPrefix, http.StatusFound) } else if !strings.HasPrefix(req.URL.Path, 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+strings.TrimLeft(req.URL.Path, "/"), http.StatusFound) } else { http.NotFound(rw, req) } })) http.Handle(pathPrefix+"alerts", prometheus.InstrumentHandler("alerts", w.AlertsHandler)) http.Handle(pathPrefix+"silences", prometheus.InstrumentHandler("silences", w.SilencesHandler)) http.Handle(pathPrefix+"status", prometheus.InstrumentHandler("status", w.StatusHandler)) http.Handle(pathPrefix+"metrics", prometheus.Handler()) if *useLocalAssets { http.Handle(pathPrefix+"static/", http.StripPrefix(pathPrefix+"static/", http.FileServer(http.Dir("web/static")))) } else { http.Handle(pathPrefix+"static/", http.StripPrefix(pathPrefix+"static/", new(blob.Handler))) } http.Handle(pathPrefix+"api/", w.AlertManagerService.Handler()) log.Info("listening on ", *listenAddress) return http.ListenAndServe(*listenAddress, nil) }
// Register the API's endpoints in the given router. func (api *API) Register(r *route.Router) { if api.context == nil { api.context = route.Context } instr := func(name string, f apiFunc) http.HandlerFunc { return prometheus.InstrumentHandlerFunc(name, func(w http.ResponseWriter, r *http.Request) { setCORS(w) if data, err := f(r); err != nil { respondError(w, err, data) } else { respond(w, data) } }) } r.Get("/query", instr("query", api.query)) r.Get("/query_range", instr("query_range", api.queryRange)) r.Get("/label/:name/values", instr("label_values", api.labelValues)) r.Get("/series", instr("series", api.series)) r.Del("/series", instr("drop_series", api.dropSeries)) }
// Push returns an http.Handler which accepts samples over HTTP and stores them // in the MetricStore. If replace is true, all metrics for the job and instance // given by the request are deleted before new ones are stored. // // The returned handler is already instrumented for Prometheus. func Push( ms storage.MetricStore, replace bool, ) func(http.ResponseWriter, *http.Request, httprouter.Params) { var ps httprouter.Params var mtx sync.Mutex // Protects ps. instrumentedHandlerFunc := prometheus.InstrumentHandlerFunc( "push", func(w http.ResponseWriter, r *http.Request) { job := ps.ByName("job") labelsString := ps.ByName("labels") mtx.Unlock() labels, err := splitLabels(labelsString) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if job == "" { http.Error(w, "job name is required", http.StatusBadRequest) return } labels["job"] = job if replace { ms.SubmitWriteRequest(storage.WriteRequest{ Labels: labels, Timestamp: time.Now(), }) } var metricFamilies map[string]*dto.MetricFamily ctMediatype, ctParams, ctErr := mime.ParseMediaType(r.Header.Get("Content-Type")) if ctErr == nil && ctMediatype == "application/vnd.google.protobuf" && ctParams["encoding"] == "delimited" && ctParams["proto"] == "io.prometheus.client.MetricFamily" { metricFamilies = map[string]*dto.MetricFamily{} for { mf := &dto.MetricFamily{} if _, err = pbutil.ReadDelimited(r.Body, mf); err != nil { if err == io.EOF { err = nil } break } metricFamilies[mf.GetName()] = mf } } else { // We could do further content-type checks here, but the // fallback for now will anyway be the text format // version 0.0.4, so just go for it and see if it works. var parser text.Parser metricFamilies, err = parser.TextToMetricFamilies(r.Body) } if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } sanitizeLabels(metricFamilies, labels) ms.SubmitWriteRequest(storage.WriteRequest{ Labels: labels, Timestamp: time.Now(), MetricFamilies: metricFamilies, }) w.WriteHeader(http.StatusAccepted) }, ) return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) { mtx.Lock() ps = params instrumentedHandlerFunc(w, r) } }
// Endpoints is a listing of all endpoints available in the svc. func (s *svc) Endpoints() map[string]map[string]http.HandlerFunc { return map[string]map[string]http.HandlerFunc{ "/metrics": { "GET": func(w http.ResponseWriter, r *http.Request) { prometheus.Handler().ServeHTTP(w, r) }, }, "/home/{path:.*}": { "GET": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Get)), "PUT": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Put)), "OPTIONS": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Options)), "LOCK": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Lock)), "UNLOCK": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Unlock)), "HEAD": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Head)), "MKCOL": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Mkcol)), "PROPPATCH": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Proppatch)), "PROPFIND": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Propfind)), "DELETE": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Delete)), "MOVE": prometheus.InstrumentHandlerFunc("/home", s.basicAuthHandlerFunc(s.Move)), }, } }
func main() { flag.Parse() if *showVersion { fmt.Fprintln(os.Stdout, version.Print("pushgateway")) os.Exit(0) } log.Infoln("Starting pushgateway", version.Info()) log.Infoln("Build context", version.BuildContext()) flags := map[string]string{} flag.VisitAll(func(f *flag.Flag) { flags[f.Name] = f.Value.String() }) ms := storage.NewDiskMetricStore(*persistenceFile, *persistenceInterval) prometheus.SetMetricFamilyInjectionHook(ms.GetMetricFamilies) // Enable collect checks for debugging. // prometheus.EnableCollectChecks(true) r := httprouter.New() r.Handler("GET", *metricsPath, prometheus.Handler()) // Handlers for pushing and deleting metrics. r.PUT("/metrics/job/:job/*labels", handler.Push(ms, true)) r.POST("/metrics/job/:job/*labels", handler.Push(ms, false)) r.DELETE("/metrics/job/:job/*labels", handler.Delete(ms)) r.PUT("/metrics/job/:job", handler.Push(ms, true)) r.POST("/metrics/job/:job", handler.Push(ms, false)) r.DELETE("/metrics/job/:job", handler.Delete(ms)) // Handlers for the deprecated API. r.PUT("/metrics/jobs/:job/instances/:instance", handler.LegacyPush(ms, true)) r.POST("/metrics/jobs/:job/instances/:instance", handler.LegacyPush(ms, false)) r.DELETE("/metrics/jobs/:job/instances/:instance", handler.LegacyDelete(ms)) r.PUT("/metrics/jobs/:job", handler.LegacyPush(ms, true)) r.POST("/metrics/jobs/:job", handler.LegacyPush(ms, false)) r.DELETE("/metrics/jobs/:job", handler.LegacyDelete(ms)) r.Handler("GET", "/static/*filepath", prometheus.InstrumentHandler( "static", http.FileServer( &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo}, ), )) statusHandler := prometheus.InstrumentHandlerFunc("status", handler.Status(ms, Asset, flags)) r.Handler("GET", "/status", statusHandler) r.Handler("GET", "/", statusHandler) // Re-enable pprof. r.GET("/debug/pprof/*pprof", handlePprof) log.Infof("Listening on %s.", *listenAddress) l, err := net.Listen("tcp", *listenAddress) if err != nil { log.Fatal(err) } go interruptHandler(l) err = (&http.Server{Addr: *listenAddress, Handler: r}).Serve(l) log.Errorln("HTTP server stopped:", err) // To give running connections a chance to submit their payload, we wait // for 1sec, but we don't want to wait long (e.g. until all connections // are done) to not delay the shutdown. time.Sleep(time.Second) if err := ms.Shutdown(); err != nil { log.Errorln("Problem shutting down metric storage:", err) } }
// Endpoints is a listing of all endpoints available in the svc. func (s *svc) Endpoints() map[string]map[string]http.HandlerFunc { return map[string]map[string]http.HandlerFunc{ "/status.php": { "GET": prometheus.InstrumentHandlerFunc("/status.php", s.Status), }, "/ocs/v1.php/cloud/capabilities": { "GET": prometheus.InstrumentHandlerFunc("/ocs/v1.php/cloud/capabilities", s.Capabilities), }, "/remote.php/webdav/{path:.*}": { "GET": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Get)), "PUT": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Put)), "OPTIONS": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Options)), "LOCK": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Lock)), "UNLOCK": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Unlock)), "HEAD": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Head)), "MKCOL": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Mkcol)), "PROPPATCH": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Proppatch)), "PROPFIND": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Propfind)), "DELETE": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Delete)), "MOVE": prometheus.InstrumentHandlerFunc("/remote.php/webdav", s.basicAuthHandlerFunc(s.Move)), }, } }