mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Partition the status tab into items in a dropdown
I got feedback from different sources about rules and targets being too heavy in the status tab if their are lots of them. This change also allows for more fine-granular locking.
This commit is contained in:
parent
8ec10ae7a5
commit
da8cb10b43
|
@ -103,13 +103,6 @@ func Main() int {
|
||||||
flags[f.Name] = f.Value.String()
|
flags[f.Name] = f.Value.String()
|
||||||
})
|
})
|
||||||
|
|
||||||
status := &web.PrometheusStatus{
|
|
||||||
TargetPools: targetManager.Pools,
|
|
||||||
Rules: ruleManager.Rules,
|
|
||||||
Flags: flags,
|
|
||||||
Birth: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
version := &web.PrometheusVersion{
|
version := &web.PrometheusVersion{
|
||||||
Version: version.Version,
|
Version: version.Version,
|
||||||
Revision: version.Revision,
|
Revision: version.Revision,
|
||||||
|
@ -119,9 +112,9 @@ func Main() int {
|
||||||
GoVersion: version.GoVersion,
|
GoVersion: version.GoVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
webHandler := web.New(memStorage, queryEngine, ruleManager, status, version, &cfg.web)
|
webHandler := web.New(memStorage, queryEngine, targetManager, ruleManager, version, flags, &cfg.web)
|
||||||
|
|
||||||
reloadables = append(reloadables, status, targetManager, ruleManager, webHandler, notifier)
|
reloadables = append(reloadables, targetManager, ruleManager, webHandler, notifier)
|
||||||
|
|
||||||
if !reloadConfig(cfg.configFile, reloadables...) {
|
if !reloadConfig(cfg.configFile, reloadables...) {
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -26,7 +26,7 @@ func TestParseTimestampOrNow(t *testing.T) {
|
||||||
t.Fatalf("err = %s; want nil", err)
|
t.Fatalf("err = %s; want nil", err)
|
||||||
}
|
}
|
||||||
if !testNow().Equal(ts) {
|
if !testNow().Equal(ts) {
|
||||||
t.Fatalf("ts = %v; want ts = %v", ts, testNow)
|
t.Fatalf("ts = %v; want ts = %v", ts, testNow())
|
||||||
}
|
}
|
||||||
|
|
||||||
ts, err = parseTimestampOrNow("1426956073.12345", testNow())
|
ts, err = parseTimestampOrNow("1426956073.12345", testNow())
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -39,7 +39,16 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<li><a href="{{ pathPrefix }}/alerts">Alerts</a></li>
|
<li><a href="{{ pathPrefix }}/alerts">Alerts</a></li>
|
||||||
<li><a href="{{ pathPrefix }}/graph">Graph</a></li>
|
<li><a href="{{ pathPrefix }}/graph">Graph</a></li>
|
||||||
<li><a href="{{ pathPrefix }}/status">Status</a></li>
|
w <li class="dropdown">
|
||||||
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Status <span class="caret"></span></a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="/status">Runtime & Build Information</a></li>
|
||||||
|
<li><a href="/flags">Command-Line Flags</a></li>
|
||||||
|
<li><a href="/config">Configuration</a></li>
|
||||||
|
<li><a href="/rules">Rules</a></li>
|
||||||
|
<li><a href="/targets">Targets</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://prometheus.io" target="_blank">Help</a>
|
<a href="https://prometheus.io" target="_blank">Help</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
8
web/ui/templates/config.html
Normal file
8
web/ui/templates/config.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{{define "head"}}<!-- nix -->{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 id="configuration">Configuration</h2>
|
||||||
|
<pre>{{.}}</pre>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
17
web/ui/templates/flags.html
Normal file
17
web/ui/templates/flags.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{{define "head"}}<!-- nix -->{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 id="startupflags">Command-Line Flags</h2>
|
||||||
|
<table class="table table-condensed table-bordered table-striped table-hover">
|
||||||
|
<tbody>
|
||||||
|
{{range $key, $value := . }}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{$key}}</th>
|
||||||
|
<td>{{$value}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
8
web/ui/templates/rules.html
Normal file
8
web/ui/templates/rules.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{{define "head"}}<!-- nix -->{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 id="rules">Rules</h2>
|
||||||
|
<pre>{{range .Rules}}{{.HTMLSnippet pathPrefix}}<br/>{{end}}</pre>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
|
@ -7,7 +7,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Uptime</th>
|
<th>Uptime</th>
|
||||||
<td>{{.Status.Birth.UTC}}</td>
|
<td>{{.Birth.UTC}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -41,76 +41,5 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h2 id="configuration">Configuration</h2>
|
|
||||||
<pre>{{.Status.Config}}</pre>
|
|
||||||
|
|
||||||
<h2 id="rules">Rules</h2>
|
|
||||||
<pre>{{range call .Status.Rules}}{{.HTMLSnippet pathPrefix}}<br/>{{end}}</pre>
|
|
||||||
|
|
||||||
<h2 id="targets">Targets</h2>
|
|
||||||
<table class="table table-condensed table-bordered table-striped table-hover">
|
|
||||||
{{range $job, $pool := call .Status.TargetPools}}
|
|
||||||
<thead>
|
|
||||||
<tr><th colspan="5" class="job_header">{{$job}}</th></tr>
|
|
||||||
<tr>
|
|
||||||
<th>Endpoint</th>
|
|
||||||
<th>State</th>
|
|
||||||
<th>Labels</th>
|
|
||||||
<th>Last Scrape</th>
|
|
||||||
<th>Error</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{{range $pool}}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<a href="{{.URL | globalURL}}">{{.URL.Scheme}}://{{.URL.Host}}{{.URL.Path}}</a><br>
|
|
||||||
{{range $label, $values := .URL.Query }}
|
|
||||||
{{range $i, $value := $values}}
|
|
||||||
<span class="label label-primary">{{$label}}="{{$value}}"</span>
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="alert alert-{{ .Health | healthToClass }} state_indicator text-uppercase">
|
|
||||||
{{.Health}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="cursor-pointer" data-toggle="tooltip" title="" data-html=true data-original-title="<b>Before relabeling:</b>{{range $k, $v := .MetaLabels}}<br>{{$k | html | html}}="{{$v | html | html}}"{{end}}">
|
|
||||||
{{$labels := stripLabels .Labels "job" "instance"}}
|
|
||||||
{{range $label, $value := $labels}}
|
|
||||||
<span class="label label-primary">{{$label}}="{{$value}}"</span>
|
|
||||||
{{else}}
|
|
||||||
<span class="label label-default">none</span>
|
|
||||||
{{end}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{if .LastScrape.IsZero}}Never{{else}}{{since .LastScrape}} ago{{end}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{if .LastError}}
|
|
||||||
<span class="alert alert-danger state_indicator">{{.LastError}}</span>
|
|
||||||
{{end}}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</tbody>
|
|
||||||
{{end}}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2 id="startupflags">Startup Flags</h2>
|
|
||||||
<table class="table table-condensed table-bordered table-striped table-hover">
|
|
||||||
<tbody>
|
|
||||||
{{range $key, $value := .Status.Flags}}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{$key}}</th>
|
|
||||||
<td>{{$value}}</td>
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
58
web/ui/templates/targets.html
Normal file
58
web/ui/templates/targets.html
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
{{define "head"}}<!-- nix -->{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 id="targets">Targets</h2>
|
||||||
|
<table class="table table-condensed table-bordered table-striped table-hover">
|
||||||
|
{{range $job, $pool := .Pools}}
|
||||||
|
<thead>
|
||||||
|
<tr><th colspan="5" class="job_header">{{$job}}</th></tr>
|
||||||
|
<tr>
|
||||||
|
<th>Endpoint</th>
|
||||||
|
<th>State</th>
|
||||||
|
<th>Labels</th>
|
||||||
|
<th>Last Scrape</th>
|
||||||
|
<th>Error</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $pool}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{{.URL | globalURL}}">{{.URL.Scheme}}://{{.URL.Host}}{{.URL.Path}}</a><br>
|
||||||
|
{{range $label, $values := .URL.Query }}
|
||||||
|
{{range $i, $value := $values}}
|
||||||
|
<span class="label label-primary">{{$label}}="{{$value}}"</span>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="alert alert-{{ .Health | healthToClass }} state_indicator text-uppercase">
|
||||||
|
{{.Health}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="cursor-pointer" data-toggle="tooltip" title="" data-html=true data-original-title="<b>Before relabeling:</b>{{range $k, $v := .MetaLabels}}<br>{{$k | html | html}}="{{$v | html | html}}"{{end}}">
|
||||||
|
{{$labels := stripLabels .Labels "job" "instance"}}
|
||||||
|
{{range $label, $value := $labels}}
|
||||||
|
<span class="label label-primary">{{$label}}="{{$value}}"</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="label label-default">none</span>
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{if .LastScrape.IsZero}}Never{{else}}{{since .LastScrape}} ago{{end}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{if .LastError}}
|
||||||
|
<span class="alert alert-danger state_indicator">{{.LastError}}</span>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
107
web/web.go
107
web/web.go
|
@ -53,20 +53,23 @@ var localhostRepresentations = []string{"127.0.0.1", "localhost"}
|
||||||
|
|
||||||
// Handler serves various HTTP endpoints of the Prometheus server
|
// Handler serves various HTTP endpoints of the Prometheus server
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
ruleManager *rules.Manager
|
targetManager *retrieval.TargetManager
|
||||||
queryEngine *promql.Engine
|
ruleManager *rules.Manager
|
||||||
storage local.Storage
|
queryEngine *promql.Engine
|
||||||
|
storage local.Storage
|
||||||
|
|
||||||
apiV1 *v1.API
|
apiV1 *v1.API
|
||||||
apiLegacy *legacy.API
|
apiLegacy *legacy.API
|
||||||
|
|
||||||
router *route.Router
|
router *route.Router
|
||||||
listenErrCh chan error
|
listenErrCh chan error
|
||||||
quitCh chan struct{}
|
quitCh chan struct{}
|
||||||
reloadCh chan struct{}
|
reloadCh chan struct{}
|
||||||
options *Options
|
options *Options
|
||||||
statusInfo *PrometheusStatus
|
configString string
|
||||||
versionInfo *PrometheusVersion
|
versionInfo *PrometheusVersion
|
||||||
|
birth time.Time
|
||||||
|
flagsMap map[string]string
|
||||||
|
|
||||||
externalLabels model.LabelSet
|
externalLabels model.LabelSet
|
||||||
mtx sync.RWMutex
|
mtx sync.RWMutex
|
||||||
|
@ -79,38 +82,12 @@ func (h *Handler) ApplyConfig(conf *config.Config) bool {
|
||||||
defer h.mtx.Unlock()
|
defer h.mtx.Unlock()
|
||||||
|
|
||||||
h.externalLabels = conf.GlobalConfig.ExternalLabels
|
h.externalLabels = conf.GlobalConfig.ExternalLabels
|
||||||
|
h.configString = conf.String()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrometheusStatus contains various information about the status
|
// PrometheusVersion contains build information about Prometheus.
|
||||||
// of the running Prometheus process.
|
|
||||||
type PrometheusStatus struct {
|
|
||||||
Birth time.Time
|
|
||||||
Flags map[string]string
|
|
||||||
Config string
|
|
||||||
|
|
||||||
// A function that returns the current scrape targets pooled
|
|
||||||
// by their job name.
|
|
||||||
TargetPools func() map[string]retrieval.Targets
|
|
||||||
// A function that returns all loaded rules.
|
|
||||||
Rules func() []rules.Rule
|
|
||||||
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyConfig updates the status state as the new config requires.
|
|
||||||
// Returns true on success.
|
|
||||||
func (s *PrometheusStatus) ApplyConfig(conf *config.Config) bool {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
|
|
||||||
s.Config = conf.String()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrometheusVersion contains various build information about Prometheus
|
|
||||||
type PrometheusVersion struct {
|
type PrometheusVersion struct {
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Revision string `json:"revision"`
|
Revision string `json:"revision"`
|
||||||
|
@ -133,7 +110,15 @@ type Options struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// New initializes a new web Handler.
|
// New initializes a new web Handler.
|
||||||
func New(st local.Storage, qe *promql.Engine, rm *rules.Manager, status *PrometheusStatus, version *PrometheusVersion, o *Options) *Handler {
|
func New(
|
||||||
|
st local.Storage,
|
||||||
|
qe *promql.Engine,
|
||||||
|
tm *retrieval.TargetManager,
|
||||||
|
rm *rules.Manager,
|
||||||
|
version *PrometheusVersion,
|
||||||
|
flags map[string]string,
|
||||||
|
o *Options,
|
||||||
|
) *Handler {
|
||||||
router := route.New()
|
router := route.New()
|
||||||
|
|
||||||
h := &Handler{
|
h := &Handler{
|
||||||
|
@ -142,12 +127,14 @@ func New(st local.Storage, qe *promql.Engine, rm *rules.Manager, status *Prometh
|
||||||
quitCh: make(chan struct{}),
|
quitCh: make(chan struct{}),
|
||||||
reloadCh: make(chan struct{}),
|
reloadCh: make(chan struct{}),
|
||||||
options: o,
|
options: o,
|
||||||
statusInfo: status,
|
|
||||||
versionInfo: version,
|
versionInfo: version,
|
||||||
|
birth: time.Now(),
|
||||||
|
flagsMap: flags,
|
||||||
|
|
||||||
ruleManager: rm,
|
targetManager: tm,
|
||||||
queryEngine: qe,
|
ruleManager: rm,
|
||||||
storage: st,
|
queryEngine: qe,
|
||||||
|
storage: st,
|
||||||
|
|
||||||
apiV1: v1.NewAPI(qe, st),
|
apiV1: v1.NewAPI(qe, st),
|
||||||
apiLegacy: &legacy.API{
|
apiLegacy: &legacy.API{
|
||||||
|
@ -171,10 +158,14 @@ func New(st local.Storage, qe *promql.Engine, rm *rules.Manager, status *Prometh
|
||||||
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
router.Redirect(w, r, "/graph", http.StatusFound)
|
router.Redirect(w, r, "/graph", http.StatusFound)
|
||||||
})
|
})
|
||||||
router.Get("/graph", instrf("graph", h.graph))
|
|
||||||
|
|
||||||
router.Get("/status", instrf("status", h.status))
|
|
||||||
router.Get("/alerts", instrf("alerts", h.alerts))
|
router.Get("/alerts", instrf("alerts", h.alerts))
|
||||||
|
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))
|
||||||
router.Get("/version", instrf("version", h.version))
|
router.Get("/version", instrf("version", h.version))
|
||||||
|
|
||||||
router.Get("/heap", instrf("heap", dumpHeap))
|
router.Get("/heap", instrf("heap", dumpHeap))
|
||||||
|
@ -322,18 +313,34 @@ func (h *Handler) graph(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) status(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) status(w http.ResponseWriter, r *http.Request) {
|
||||||
h.statusInfo.mu.RLock()
|
|
||||||
defer h.statusInfo.mu.RUnlock()
|
|
||||||
|
|
||||||
h.executeTemplate(w, "status.html", struct {
|
h.executeTemplate(w, "status.html", struct {
|
||||||
Status *PrometheusStatus
|
Birth time.Time
|
||||||
Version *PrometheusVersion
|
Version *PrometheusVersion
|
||||||
}{
|
}{
|
||||||
Status: h.statusInfo,
|
Birth: h.birth,
|
||||||
Version: h.versionInfo,
|
Version: h.versionInfo,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
h.executeTemplate(w, "targets.html", h.targetManager)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) version(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) version(w http.ResponseWriter, r *http.Request) {
|
||||||
dec := json.NewEncoder(w)
|
dec := json.NewEncoder(w)
|
||||||
if err := dec.Encode(h.versionInfo); err != nil {
|
if err := dec.Encode(h.versionInfo); err != nil {
|
||||||
|
|
Loading…
Reference in a new issue