| 
									
										
										
										
											2015-01-22 03:07:45 +08:00
										 |  |  | // Copyright 2013 The Prometheus Authors
 | 
					
						
							| 
									
										
										
										
											2013-02-08 21:49:55 +08:00
										 |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package web | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2015-06-16 20:57:30 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2013-04-05 19:41:52 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2014-07-30 00:28:48 +08:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2013-02-08 21:49:55 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2013-08-10 00:09:44 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2017-05-22 20:15:02 +08:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2015-07-08 22:14:57 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2013-08-29 21:15:22 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pprof_runtime "runtime/pprof" | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:50 +08:00
										 |  |  | 	template_text "text/template" | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-03 07:49:29 +08:00
										 |  |  | 	"github.com/opentracing-contrib/go-stdlib/nethttp" | 
					
						
							|  |  |  | 	"github.com/opentracing/opentracing-go" | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							| 
									
										
										
										
											2015-10-03 16:21:43 +08:00
										 |  |  | 	"github.com/prometheus/common/log" | 
					
						
							| 
									
										
										
										
											2015-08-20 23:18:46 +08:00
										 |  |  | 	"github.com/prometheus/common/model" | 
					
						
							| 
									
										
										
										
											2015-09-24 23:07:11 +08:00
										 |  |  | 	"github.com/prometheus/common/route" | 
					
						
							| 
									
										
											  
											
												promql: Allow per-query contexts.
For Weaveworks' Frankenstein, we need to support multitenancy. In
Frankenstein, we initially solved this without modifying the promql
package at all: we constructed a new promql.Engine for every
query and injected a storage implementation into that engine which would
be primed to only collect data for a given user.
This is problematic to upstream, however. Prometheus assumes that there
is only one engine: the query concurrency gate is part of the engine,
and the engine contains one central cancellable context to shut down all
queries. Also, creating a new engine for every query seems like overkill.
Thus, we want to be able to pass per-query contexts into a single engine.
This change gets rid of the promql.Engine's built-in base context and
allows passing in a per-query context instead. Central cancellation of
all queries is still possible by deriving all passed-in contexts from
one central one, but this is now the responsibility of the caller. The
central query context is now created in main() and passed into the
relevant components (web handler / API, rule manager).
In a next step, the per-query context would have to be passed to the
storage implementation, so that the storage can implement multi-tenancy
or other features based on the contextual information.
											
										 
											2016-09-15 19:52:50 +08:00
										 |  |  | 	"golang.org/x/net/context" | 
					
						
							| 
									
										
										
										
											2016-12-06 17:45:59 +08:00
										 |  |  | 	"golang.org/x/net/netutil" | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/config" | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/notifier" | 
					
						
							| 
									
										
										
										
											2017-04-04 20:44:39 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/pkg/labels" | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/promql" | 
					
						
							|  |  |  | 	"github.com/prometheus/prometheus/retrieval" | 
					
						
							|  |  |  | 	"github.com/prometheus/prometheus/rules" | 
					
						
							| 
									
										
										
										
											2016-12-29 16:27:30 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/storage" | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/template" | 
					
						
							| 
									
										
										
										
											2015-09-17 20:49:50 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/util/httputil" | 
					
						
							| 
									
										
										
										
											2016-06-23 23:14:32 +08:00
										 |  |  | 	api_v1 "github.com/prometheus/prometheus/web/api/v1" | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/web/ui" | 
					
						
							| 
									
										
										
										
											2013-02-08 21:49:55 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 18:16:25 +08:00
										 |  |  | var localhostRepresentations = []string{"127.0.0.1", "localhost"} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | // Handler serves various HTTP endpoints of the Prometheus server
 | 
					
						
							|  |  |  | type Handler struct { | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | 	targetManager *retrieval.TargetManager | 
					
						
							|  |  |  | 	ruleManager   *rules.Manager | 
					
						
							|  |  |  | 	queryEngine   *promql.Engine | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 	context       context.Context | 
					
						
							| 
									
										
										
										
											2016-12-29 16:27:30 +08:00
										 |  |  | 	storage       storage.Storage | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 	notifier      *notifier.Notifier | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-23 23:14:32 +08:00
										 |  |  | 	apiV1 *api_v1.API | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | 	router       *route.Router | 
					
						
							|  |  |  | 	listenErrCh  chan error | 
					
						
							|  |  |  | 	quitCh       chan struct{} | 
					
						
							| 
									
										
										
										
											2016-07-11 22:24:54 +08:00
										 |  |  | 	reloadCh     chan chan error | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | 	options      *Options | 
					
						
							|  |  |  | 	configString string | 
					
						
							|  |  |  | 	versionInfo  *PrometheusVersion | 
					
						
							|  |  |  | 	birth        time.Time | 
					
						
							| 
									
										
										
										
											2016-12-04 07:37:59 +08:00
										 |  |  | 	cwd          string | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | 	flagsMap     map[string]string | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-29 23:51:03 +08:00
										 |  |  | 	externalLabels model.LabelSet | 
					
						
							|  |  |  | 	mtx            sync.RWMutex | 
					
						
							| 
									
										
										
										
											2016-09-08 23:39:52 +08:00
										 |  |  | 	now            func() model.Time | 
					
						
							| 
									
										
										
										
											2015-09-02 00:47:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ApplyConfig updates the status state as the new config requires.
 | 
					
						
							| 
									
										
										
										
											2016-07-11 22:24:54 +08:00
										 |  |  | func (h *Handler) ApplyConfig(conf *config.Config) error { | 
					
						
							| 
									
										
										
										
											2015-09-02 00:47:48 +08:00
										 |  |  | 	h.mtx.Lock() | 
					
						
							|  |  |  | 	defer h.mtx.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-29 23:51:03 +08:00
										 |  |  | 	h.externalLabels = conf.GlobalConfig.ExternalLabels | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | 	h.configString = conf.String() | 
					
						
							| 
									
										
										
										
											2015-09-02 00:47:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 22:24:54 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-02-08 22:38:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | // PrometheusVersion contains build information about Prometheus.
 | 
					
						
							| 
									
										
										
										
											2016-05-05 19:46:51 +08:00
										 |  |  | type PrometheusVersion struct { | 
					
						
							|  |  |  | 	Version   string `json:"version"` | 
					
						
							|  |  |  | 	Revision  string `json:"revision"` | 
					
						
							|  |  |  | 	Branch    string `json:"branch"` | 
					
						
							|  |  |  | 	BuildUser string `json:"buildUser"` | 
					
						
							|  |  |  | 	BuildDate string `json:"buildDate"` | 
					
						
							|  |  |  | 	GoVersion string `json:"goVersion"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | // Options for the web Handler.
 | 
					
						
							|  |  |  | type Options struct { | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 	Context       context.Context | 
					
						
							| 
									
										
										
										
											2016-12-29 16:27:30 +08:00
										 |  |  | 	Storage       storage.Storage | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 	QueryEngine   *promql.Engine | 
					
						
							|  |  |  | 	TargetManager *retrieval.TargetManager | 
					
						
							|  |  |  | 	RuleManager   *rules.Manager | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 	Notifier      *notifier.Notifier | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 	Version       *PrometheusVersion | 
					
						
							|  |  |  | 	Flags         map[string]string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	ListenAddress        string | 
					
						
							| 
									
										
										
										
											2016-12-01 21:29:45 +08:00
										 |  |  | 	ReadTimeout          time.Duration | 
					
						
							| 
									
										
										
										
											2016-12-06 17:45:59 +08:00
										 |  |  | 	MaxConnections       int | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 	ExternalURL          *url.URL | 
					
						
							| 
									
										
										
										
											2016-07-05 21:05:43 +08:00
										 |  |  | 	RoutePrefix          string | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	UseLocalAssets       bool | 
					
						
							|  |  |  | 	UserAssetsPath       string | 
					
						
							|  |  |  | 	ConsoleTemplatesPath string | 
					
						
							|  |  |  | 	ConsoleLibrariesPath string | 
					
						
							|  |  |  | 	EnableQuit           bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // New initializes a new web Handler.
 | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | func New(o *Options) *Handler { | 
					
						
							| 
									
										
										
										
											2017-05-03 07:49:29 +08:00
										 |  |  | 	router := route.New() | 
					
						
							| 
									
										
										
										
											2016-12-04 07:37:59 +08:00
										 |  |  | 	cwd, err := os.Getwd() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		cwd = "<error retrieving current working directory>" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	h := &Handler{ | 
					
						
							| 
									
										
										
										
											2015-08-21 00:23:57 +08:00
										 |  |  | 		router:      router, | 
					
						
							|  |  |  | 		listenErrCh: make(chan error), | 
					
						
							|  |  |  | 		quitCh:      make(chan struct{}), | 
					
						
							| 
									
										
										
										
											2016-07-11 22:24:54 +08:00
										 |  |  | 		reloadCh:    make(chan chan error), | 
					
						
							| 
									
										
										
										
											2015-08-21 00:23:57 +08:00
										 |  |  | 		options:     o, | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 		versionInfo: o.Version, | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | 		birth:       time.Now(), | 
					
						
							| 
									
										
										
										
											2016-12-04 07:37:59 +08:00
										 |  |  | 		cwd:         cwd, | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 		flagsMap:    o.Flags, | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 		context:       o.Context, | 
					
						
							|  |  |  | 		targetManager: o.TargetManager, | 
					
						
							|  |  |  | 		ruleManager:   o.RuleManager, | 
					
						
							|  |  |  | 		queryEngine:   o.QueryEngine, | 
					
						
							|  |  |  | 		storage:       o.Storage, | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 		notifier:      o.Notifier, | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-13 17:20:11 +08:00
										 |  |  | 		apiV1: api_v1.NewAPI(o.QueryEngine, o.Storage, o.TargetManager, o.Notifier), | 
					
						
							| 
									
										
										
										
											2016-09-08 23:39:52 +08:00
										 |  |  | 		now:   model.Now, | 
					
						
							| 
									
										
										
										
											2015-06-02 19:07:46 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-06 15:56:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-05 21:05:43 +08:00
										 |  |  | 	if o.RoutePrefix != "/" { | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 		// If the prefix is missing for the root path, prepend it.
 | 
					
						
							| 
									
										
										
										
											2015-06-03 14:38:50 +08:00
										 |  |  | 		router.Get("/", func(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-07-05 21:05:43 +08:00
										 |  |  | 			http.Redirect(w, r, o.RoutePrefix, http.StatusFound) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:38:50 +08:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2016-07-05 21:05:43 +08:00
										 |  |  | 		router = router.WithPrefix(o.RoutePrefix) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:38:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 22:33:14 +08:00
										 |  |  | 	instrh := prometheus.InstrumentHandler | 
					
						
							|  |  |  | 	instrf := prometheus.InstrumentHandlerFunc | 
					
						
							| 
									
										
										
										
											2015-06-03 14:38:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-28 16:53:13 +08:00
										 |  |  | 	router.Get("/", func(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2017-06-10 18:07:43 +08:00
										 |  |  | 		http.Redirect(w, r, path.Join(o.ExternalURL.Path, "/graph"), http.StatusFound) | 
					
						
							| 
									
										
										
										
											2015-08-28 16:53:13 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	router.Get("/alerts", instrf("alerts", h.alerts)) | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | 	router.Get("/graph", instrf("graph", h.graph)) | 
					
						
							|  |  |  | 	router.Get("/status", instrf("status", h.status)) | 
					
						
							|  |  |  | 	router.Get("/flags", instrf("flags", h.flags)) | 
					
						
							|  |  |  | 	router.Get("/config", instrf("config", h.config)) | 
					
						
							|  |  |  | 	router.Get("/rules", instrf("rules", h.rules)) | 
					
						
							|  |  |  | 	router.Get("/targets", instrf("targets", h.targets)) | 
					
						
							| 
									
										
										
										
											2015-06-16 20:57:30 +08:00
										 |  |  | 	router.Get("/version", instrf("version", h.version)) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:38:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	router.Get("/heap", instrf("heap", dumpHeap)) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:38:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-16 22:51:41 +08:00
										 |  |  | 	router.Get("/metrics", prometheus.Handler().ServeHTTP) | 
					
						
							| 
									
										
										
										
											2015-06-05 00:24:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 22:33:14 +08:00
										 |  |  | 	router.Get("/federate", instrh("federate", httputil.CompressionHandler{ | 
					
						
							| 
									
										
										
										
											2015-09-18 22:51:53 +08:00
										 |  |  | 		Handler: http.HandlerFunc(h.federation), | 
					
						
							| 
									
										
										
										
											2015-09-17 22:33:14 +08:00
										 |  |  | 	})) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	h.apiV1.Register(router.WithPrefix("/api/v1")) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:38:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	router.Get("/consoles/*filepath", instrf("consoles", h.consoles)) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:38:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | 	router.Get("/static/*filepath", instrf("static", serveStaticAsset)) | 
					
						
							| 
									
										
										
										
											2013-02-08 21:49:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	if o.UserAssetsPath != "" { | 
					
						
							|  |  |  | 		router.Get("/user/*filepath", instrf("user", route.FileServe(o.UserAssetsPath))) | 
					
						
							| 
									
										
										
										
											2013-05-23 21:47:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	if o.EnableQuit { | 
					
						
							|  |  |  | 		router.Post("/-/quit", h.quit) | 
					
						
							| 
									
										
										
										
											2015-03-25 05:04:38 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-11 18:26:41 +08:00
										 |  |  | 	router.Post("/-/reload", h.reload) | 
					
						
							| 
									
										
										
										
											2016-11-07 23:14:22 +08:00
										 |  |  | 	router.Get("/-/reload", func(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 		w.WriteHeader(http.StatusMethodNotAllowed) | 
					
						
							|  |  |  | 		fmt.Fprintf(w, "This endpoint requires a POST request.\n") | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-08-26 23:42:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-22 06:27:55 +08:00
										 |  |  | 	router.Get("/debug/*subpath", http.DefaultServeMux.ServeHTTP) | 
					
						
							| 
									
										
										
										
											2015-08-26 23:42:25 +08:00
										 |  |  | 	router.Post("/debug/*subpath", http.DefaultServeMux.ServeHTTP) | 
					
						
							| 
									
										
										
										
											2015-07-22 06:27:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	return h | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | func serveStaticAsset(w http.ResponseWriter, req *http.Request) { | 
					
						
							| 
									
										
										
										
											2017-05-03 07:49:29 +08:00
										 |  |  | 	fp := route.Param(req.Context(), "filepath") | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | 	fp = filepath.Join("web/ui/static", fp) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info, err := ui.AssetInfo(fp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		log.With("file", fp).Warn("Could not get file info: ", err) | 
					
						
							|  |  |  | 		w.WriteHeader(http.StatusNotFound) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	file, err := ui.Asset(fp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if err != io.EOF { | 
					
						
							|  |  |  | 			log.With("file", fp).Warn("Could not get file: ", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		w.WriteHeader(http.StatusNotFound) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	http.ServeContent(w, req, info.Name(), info.ModTime(), bytes.NewReader(file)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-21 00:23:57 +08:00
										 |  |  | // ListenError returns the receive-only channel that signals errors while starting the web server.
 | 
					
						
							|  |  |  | func (h *Handler) ListenError() <-chan error { | 
					
						
							|  |  |  | 	return h.listenErrCh | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | // Quit returns the receive-only quit channel.
 | 
					
						
							|  |  |  | func (h *Handler) Quit() <-chan struct{} { | 
					
						
							|  |  |  | 	return h.quitCh | 
					
						
							| 
									
										
										
										
											2015-06-02 19:07:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-21 00:23:57 +08:00
										 |  |  | // Reload returns the receive-only channel that signals configuration reload requests.
 | 
					
						
							| 
									
										
										
										
											2016-07-11 22:24:54 +08:00
										 |  |  | func (h *Handler) Reload() <-chan chan error { | 
					
						
							| 
									
										
										
										
											2015-08-11 15:08:17 +08:00
										 |  |  | 	return h.reloadCh | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-02 19:07:46 +08:00
										 |  |  | // Run serves the HTTP endpoints.
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | func (h *Handler) Run() { | 
					
						
							|  |  |  | 	log.Infof("Listening on %s", h.options.ListenAddress) | 
					
						
							| 
									
										
										
										
											2017-05-03 07:49:29 +08:00
										 |  |  | 	operationName := nethttp.OperationNameFunc(func(r *http.Request) string { | 
					
						
							|  |  |  | 		return fmt.Sprintf("%s %s", r.Method, r.URL.Path) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-05-25 19:13:22 +08:00
										 |  |  | 	server := &http.Server{ | 
					
						
							| 
									
										
										
										
											2016-12-01 21:29:45 +08:00
										 |  |  | 		Addr:        h.options.ListenAddress, | 
					
						
							| 
									
										
										
										
											2017-05-03 07:49:29 +08:00
										 |  |  | 		Handler:     nethttp.Middleware(opentracing.GlobalTracer(), h.router, operationName), | 
					
						
							| 
									
										
										
										
											2016-12-01 21:29:45 +08:00
										 |  |  | 		ErrorLog:    log.NewErrorLogger(), | 
					
						
							|  |  |  | 		ReadTimeout: h.options.ReadTimeout, | 
					
						
							| 
									
										
										
										
											2016-05-25 19:13:22 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-06 17:45:59 +08:00
										 |  |  | 	listener, err := net.Listen("tcp", h.options.ListenAddress) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		h.listenErrCh <- err | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		limitedListener := netutil.LimitListener(listener, h.options.MaxConnections) | 
					
						
							|  |  |  | 		h.listenErrCh <- server.Serve(limitedListener) | 
					
						
							| 
									
										
										
										
											2016-05-25 19:13:22 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-02-08 21:49:55 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-03-28 00:40:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | func (h *Handler) alerts(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	alerts := h.ruleManager.AlertingRules() | 
					
						
							| 
									
										
										
										
											2016-12-27 21:13:33 +08:00
										 |  |  | 	alertsSorter := byAlertStateAndNameSorter{alerts: alerts} | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	sort.Sort(alertsSorter) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	alertStatus := AlertStatus{ | 
					
						
							|  |  |  | 		AlertingRules: alertsSorter.alerts, | 
					
						
							|  |  |  | 		AlertStateToRowClass: map[rules.AlertState]string{ | 
					
						
							|  |  |  | 			rules.StateInactive: "success", | 
					
						
							|  |  |  | 			rules.StatePending:  "warning", | 
					
						
							|  |  |  | 			rules.StateFiring:   "danger", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | 	h.executeTemplate(w, "alerts.html", alertStatus) | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2017-05-03 07:49:29 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	name := route.Param(ctx, "filepath") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	file, err := http.Dir(h.options.ConsoleTemplatesPath).Open(name) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		http.Error(w, err.Error(), http.StatusNotFound) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	text, err := ioutil.ReadAll(file) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		http.Error(w, err.Error(), http.StatusInternalServerError) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Provide URL parameters as a map for easy use. Advanced users may have need for
 | 
					
						
							|  |  |  | 	// parameters beyond the first, so provide RawParams.
 | 
					
						
							|  |  |  | 	rawParams, err := url.ParseQuery(r.URL.RawQuery) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		http.Error(w, err.Error(), http.StatusBadRequest) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	params := map[string]string{} | 
					
						
							|  |  |  | 	for k, v := range rawParams { | 
					
						
							|  |  |  | 		params[k] = v[0] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data := struct { | 
					
						
							|  |  |  | 		RawParams url.Values | 
					
						
							|  |  |  | 		Params    map[string]string | 
					
						
							|  |  |  | 		Path      string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		RawParams: rawParams, | 
					
						
							|  |  |  | 		Params:    params, | 
					
						
							| 
									
										
										
										
											2015-07-08 22:14:57 +08:00
										 |  |  | 		Path:      strings.TrimLeft(name, "/"), | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-13 21:47:04 +08:00
										 |  |  | 	tmpl := template.NewTemplateExpander(h.context, string(text), "__console_"+name, data, h.now(), h.queryEngine, h.options.ExternalURL) | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	filenames, err := filepath.Glob(h.options.ConsoleLibrariesPath + "/*.lib") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		http.Error(w, err.Error(), http.StatusInternalServerError) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	result, err := tmpl.ExpandHTML(filenames) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		http.Error(w, err.Error(), http.StatusInternalServerError) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	io.WriteString(w, result) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *Handler) graph(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | 	h.executeTemplate(w, "graph.html", nil) | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 20:57:30 +08:00
										 |  |  | func (h *Handler) status(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | 	h.executeTemplate(w, "status.html", struct { | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 		Birth         time.Time | 
					
						
							| 
									
										
										
										
											2016-12-04 07:37:59 +08:00
										 |  |  | 		CWD           string | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 		Version       *PrometheusVersion | 
					
						
							| 
									
										
										
										
											2017-04-25 13:42:33 +08:00
										 |  |  | 		Alertmanagers []*url.URL | 
					
						
							| 
									
										
										
										
											2015-06-15 18:23:02 +08:00
										 |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 		Birth:         h.birth, | 
					
						
							| 
									
										
										
										
											2016-12-04 07:37:59 +08:00
										 |  |  | 		CWD:           h.cwd, | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 		Version:       h.versionInfo, | 
					
						
							|  |  |  | 		Alertmanagers: h.notifier.Alertmanagers(), | 
					
						
							| 
									
										
										
										
											2015-06-15 18:23:02 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-04-15 07:02:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | func (h *Handler) flags(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	h.executeTemplate(w, "flags.html", h.flagsMap) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *Handler) config(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	h.mtx.RLock() | 
					
						
							|  |  |  | 	defer h.mtx.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	h.executeTemplate(w, "config.html", h.configString) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *Handler) rules(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	h.executeTemplate(w, "rules.html", h.ruleManager) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *Handler) targets(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-12-02 20:28:58 +08:00
										 |  |  | 	// Bucket targets by job label
 | 
					
						
							| 
									
										
										
										
											2017-01-07 01:43:41 +08:00
										 |  |  | 	tps := map[string][]*retrieval.Target{} | 
					
						
							| 
									
										
										
										
											2016-12-02 20:28:58 +08:00
										 |  |  | 	for _, t := range h.targetManager.Targets() { | 
					
						
							| 
									
										
										
										
											2016-12-29 16:27:30 +08:00
										 |  |  | 		job := t.Labels().Get(model.JobLabel) | 
					
						
							| 
									
										
										
										
											2016-12-02 20:28:58 +08:00
										 |  |  | 		tps[job] = append(tps[job], t) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-31 04:45:18 +08:00
										 |  |  | 	for _, targets := range tps { | 
					
						
							|  |  |  | 		sort.Slice(targets, func(i, j int) bool { | 
					
						
							| 
									
										
										
										
											2017-04-04 20:44:39 +08:00
										 |  |  | 			return targets[i].Labels().Get(labels.InstanceName) < targets[j].Labels().Get(labels.InstanceName) | 
					
						
							| 
									
										
										
										
											2017-03-31 04:45:18 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 	h.executeTemplate(w, "targets.html", struct { | 
					
						
							| 
									
										
										
										
											2017-01-07 01:43:41 +08:00
										 |  |  | 		TargetPools map[string][]*retrieval.Target | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2016-12-02 20:28:58 +08:00
										 |  |  | 		TargetPools: tps, | 
					
						
							| 
									
										
										
										
											2016-11-24 01:23:09 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-05-13 23:59:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 20:57:30 +08:00
										 |  |  | func (h *Handler) version(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	dec := json.NewEncoder(w) | 
					
						
							| 
									
										
										
										
											2016-05-05 19:46:51 +08:00
										 |  |  | 	if err := dec.Encode(h.versionInfo); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-16 20:57:30 +08:00
										 |  |  | 		http.Error(w, fmt.Sprintf("error encoding JSON: %s", err), http.StatusInternalServerError) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | func (h *Handler) quit(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	fmt.Fprintf(w, "Requesting termination... Goodbye!") | 
					
						
							|  |  |  | 	close(h.quitCh) | 
					
						
							| 
									
										
										
										
											2014-04-15 07:02:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-11 15:08:17 +08:00
										 |  |  | func (h *Handler) reload(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-07-11 22:24:54 +08:00
										 |  |  | 	rc := make(chan error) | 
					
						
							|  |  |  | 	h.reloadCh <- rc | 
					
						
							|  |  |  | 	if err := <-rc; err != nil { | 
					
						
							|  |  |  | 		http.Error(w, fmt.Sprintf("failed to reload config: %s", err), http.StatusInternalServerError) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-11 15:08:17 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | func (h *Handler) consolesPath() string { | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	if _, err := os.Stat(h.options.ConsoleTemplatesPath + "/index.html"); !os.IsNotExist(err) { | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 		return h.options.ExternalURL.Path + "/consoles/index.html" | 
					
						
							| 
									
										
										
										
											2014-10-02 22:44:47 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	if h.options.UserAssetsPath != "" { | 
					
						
							|  |  |  | 		if _, err := os.Stat(h.options.UserAssetsPath + "/index.html"); !os.IsNotExist(err) { | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 			return h.options.ExternalURL.Path + "/user/index.html" | 
					
						
							| 
									
										
										
										
											2014-10-02 22:44:47 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return "" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | func tmplFuncs(consolesPath string, opts *Options) template_text.FuncMap { | 
					
						
							|  |  |  | 	return template_text.FuncMap{ | 
					
						
							| 
									
										
										
										
											2016-06-09 02:23:54 +08:00
										 |  |  | 		"since": func(t time.Time) time.Duration { | 
					
						
							|  |  |  | 			return time.Since(t) / time.Millisecond * time.Millisecond | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 		"consolesPath": func() string { return consolesPath }, | 
					
						
							|  |  |  | 		"pathPrefix":   func() string { return opts.ExternalURL.Path }, | 
					
						
							| 
									
										
										
										
											2017-03-19 04:38:35 +08:00
										 |  |  | 		"buildVersion": func() string { return opts.Version.Revision }, | 
					
						
							| 
									
										
										
										
											2017-03-20 21:07:41 +08:00
										 |  |  | 		"stripLabels": func(lset map[string]string, labels ...string) map[string]string { | 
					
						
							| 
									
										
										
										
											2015-05-18 18:16:25 +08:00
										 |  |  | 			for _, ln := range labels { | 
					
						
							|  |  |  | 				delete(lset, ln) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return lset | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2015-06-23 04:57:32 +08:00
										 |  |  | 		"globalURL": func(u *url.URL) *url.URL { | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 			host, port, err := net.SplitHostPort(u.Host) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return u | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-23 04:57:32 +08:00
										 |  |  | 			for _, lhr := range localhostRepresentations { | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 				if host == lhr { | 
					
						
							|  |  |  | 					_, ownPort, err := net.SplitHostPort(opts.ListenAddress) | 
					
						
							|  |  |  | 					if err != nil { | 
					
						
							|  |  |  | 						return u | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if port == ownPort { | 
					
						
							|  |  |  | 						// Only in the case where the target is on localhost and its port is
 | 
					
						
							|  |  |  | 						// the same as the one we're listening on, we know for sure that
 | 
					
						
							|  |  |  | 						// we're monitoring our own process and that we need to change the
 | 
					
						
							|  |  |  | 						// scheme, hostname, and port to the externally reachable ones as
 | 
					
						
							|  |  |  | 						// well. We shouldn't need to touch the path at all, since if a
 | 
					
						
							|  |  |  | 						// path prefix is defined, the path under which we scrape ourselves
 | 
					
						
							|  |  |  | 						// should already contain the prefix.
 | 
					
						
							|  |  |  | 						u.Scheme = opts.ExternalURL.Scheme | 
					
						
							|  |  |  | 						u.Host = opts.ExternalURL.Host | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						// Otherwise, we only know that localhost is not reachable
 | 
					
						
							|  |  |  | 						// externally, so we replace only the hostname by the one in the
 | 
					
						
							|  |  |  | 						// external URL. It could be the wrong hostname for the service on
 | 
					
						
							|  |  |  | 						// this port, but it's still the best possible guess.
 | 
					
						
							|  |  |  | 						host, _, err := net.SplitHostPort(opts.ExternalURL.Host) | 
					
						
							|  |  |  | 						if err != nil { | 
					
						
							|  |  |  | 							return u | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						u.Host = host + ":" + port | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break | 
					
						
							| 
									
										
										
										
											2015-06-23 04:57:32 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-05-18 18:16:25 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-23 04:57:32 +08:00
										 |  |  | 			return u | 
					
						
							| 
									
										
										
										
											2015-05-18 18:16:25 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 		"healthToClass": func(th retrieval.TargetHealth) string { | 
					
						
							|  |  |  | 			switch th { | 
					
						
							|  |  |  | 			case retrieval.HealthUnknown: | 
					
						
							|  |  |  | 				return "warning" | 
					
						
							|  |  |  | 			case retrieval.HealthGood: | 
					
						
							|  |  |  | 				return "success" | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				return "danger" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:50 +08:00
										 |  |  | 		"alertStateToClass": func(as rules.AlertState) string { | 
					
						
							|  |  |  | 			switch as { | 
					
						
							|  |  |  | 			case rules.StateInactive: | 
					
						
							|  |  |  | 				return "success" | 
					
						
							|  |  |  | 			case rules.StatePending: | 
					
						
							|  |  |  | 				return "warning" | 
					
						
							|  |  |  | 			case rules.StateFiring: | 
					
						
							|  |  |  | 				return "danger" | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				panic("unknown alert state") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-11 23:31:09 +08:00
										 |  |  | func (h *Handler) getTemplate(name string) (string, error) { | 
					
						
							|  |  |  | 	baseTmpl, err := ui.Asset("web/ui/templates/_base.html") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("error reading base template: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pageTmpl, err := ui.Asset(filepath.Join("web/ui/templates", name)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("error reading page template %s: %s", name, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return string(baseTmpl) + string(pageTmpl), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | func (h *Handler) executeTemplate(w http.ResponseWriter, name string, data interface{}) { | 
					
						
							|  |  |  | 	text, err := h.getTemplate(name) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		http.Error(w, err.Error(), http.StatusInternalServerError) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-13 21:47:04 +08:00
										 |  |  | 	tmpl := template.NewTemplateExpander(h.context, text, name, data, h.now(), h.queryEngine, h.options.ExternalURL) | 
					
						
							| 
									
										
										
										
											2015-06-30 20:38:01 +08:00
										 |  |  | 	tmpl.Funcs(tmplFuncs(h.consolesPath(), h.options)) | 
					
						
							| 
									
										
										
										
											2015-05-18 18:16:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:50 +08:00
										 |  |  | 	result, err := tmpl.ExpandHTML(nil) | 
					
						
							| 
									
										
										
										
											2013-03-28 00:40:01 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:50 +08:00
										 |  |  | 		http.Error(w, err.Error(), http.StatusInternalServerError) | 
					
						
							| 
									
										
										
										
											2013-03-28 00:40:01 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:50 +08:00
										 |  |  | 	io.WriteString(w, result) | 
					
						
							| 
									
										
										
										
											2013-03-28 00:40:01 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-08-10 00:09:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-29 21:15:22 +08:00
										 |  |  | func dumpHeap(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	target := fmt.Sprintf("/tmp/%d.heap", time.Now().Unix()) | 
					
						
							|  |  |  | 	f, err := os.Create(target) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-05-21 00:10:29 +08:00
										 |  |  | 		log.Error("Could not dump heap: ", err) | 
					
						
							| 
									
										
										
										
											2013-08-29 21:15:22 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Fprintf(w, "Writing to %s...", target) | 
					
						
							|  |  |  | 	defer f.Close() | 
					
						
							|  |  |  | 	pprof_runtime.WriteHeapProfile(f) | 
					
						
							|  |  |  | 	fmt.Fprintf(w, "Done") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | // AlertStatus bundles alerting rules and the mapping of alert states to row classes.
 | 
					
						
							|  |  |  | type AlertStatus struct { | 
					
						
							|  |  |  | 	AlertingRules        []*rules.AlertingRule | 
					
						
							|  |  |  | 	AlertStateToRowClass map[rules.AlertState]string | 
					
						
							| 
									
										
										
										
											2013-08-10 00:09:44 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-22 18:29:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 21:13:33 +08:00
										 |  |  | type byAlertStateAndNameSorter struct { | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	alerts []*rules.AlertingRule | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 21:13:33 +08:00
										 |  |  | func (s byAlertStateAndNameSorter) Len() int { | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	return len(s.alerts) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 21:13:33 +08:00
										 |  |  | func (s byAlertStateAndNameSorter) Less(i, j int) bool { | 
					
						
							|  |  |  | 	return s.alerts[i].State() > s.alerts[j].State() || | 
					
						
							|  |  |  | 		(s.alerts[i].State() == s.alerts[j].State() && | 
					
						
							|  |  |  | 			s.alerts[i].Name() < s.alerts[j].Name()) | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 21:13:33 +08:00
										 |  |  | func (s byAlertStateAndNameSorter) Swap(i, j int) { | 
					
						
							| 
									
										
										
										
											2015-06-15 18:50:53 +08:00
										 |  |  | 	s.alerts[i], s.alerts[j] = s.alerts[j], s.alerts[i] | 
					
						
							| 
									
										
										
										
											2015-05-22 18:29:33 +08:00
										 |  |  | } |