mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-25 05:34:05 -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()
|
||||
})
|
||||
|
||||
status := &web.PrometheusStatus{
|
||||
TargetPools: targetManager.Pools,
|
||||
Rules: ruleManager.Rules,
|
||||
Flags: flags,
|
||||
Birth: time.Now(),
|
||||
}
|
||||
|
||||
version := &web.PrometheusVersion{
|
||||
Version: version.Version,
|
||||
Revision: version.Revision,
|
||||
|
@ -119,9 +112,9 @@ func Main() int {
|
|||
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...) {
|
||||
return 1
|
||||
|
|
|
@ -26,7 +26,7 @@ func TestParseTimestampOrNow(t *testing.T) {
|
|||
t.Fatalf("err = %s; want nil", err)
|
||||
}
|
||||
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())
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -39,7 +39,16 @@
|
|||
{{ end }}
|
||||
<li><a href="{{ pathPrefix }}/alerts">Alerts</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>
|
||||
<a href="https://prometheus.io" target="_blank">Help</a>
|
||||
</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>
|
||||
<tr>
|
||||
<th>Uptime</th>
|
||||
<td>{{.Status.Birth.UTC}}</td>
|
||||
<td>{{.Birth.UTC}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -41,76 +41,5 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</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>
|
||||
{{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
|
||||
type Handler struct {
|
||||
ruleManager *rules.Manager
|
||||
queryEngine *promql.Engine
|
||||
storage local.Storage
|
||||
targetManager *retrieval.TargetManager
|
||||
ruleManager *rules.Manager
|
||||
queryEngine *promql.Engine
|
||||
storage local.Storage
|
||||
|
||||
apiV1 *v1.API
|
||||
apiLegacy *legacy.API
|
||||
|
||||
router *route.Router
|
||||
listenErrCh chan error
|
||||
quitCh chan struct{}
|
||||
reloadCh chan struct{}
|
||||
options *Options
|
||||
statusInfo *PrometheusStatus
|
||||
versionInfo *PrometheusVersion
|
||||
router *route.Router
|
||||
listenErrCh chan error
|
||||
quitCh chan struct{}
|
||||
reloadCh chan struct{}
|
||||
options *Options
|
||||
configString string
|
||||
versionInfo *PrometheusVersion
|
||||
birth time.Time
|
||||
flagsMap map[string]string
|
||||
|
||||
externalLabels model.LabelSet
|
||||
mtx sync.RWMutex
|
||||
|
@ -79,38 +82,12 @@ func (h *Handler) ApplyConfig(conf *config.Config) bool {
|
|||
defer h.mtx.Unlock()
|
||||
|
||||
h.externalLabels = conf.GlobalConfig.ExternalLabels
|
||||
h.configString = conf.String()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// PrometheusStatus contains various information about the status
|
||||
// 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
|
||||
// PrometheusVersion contains build information about Prometheus.
|
||||
type PrometheusVersion struct {
|
||||
Version string `json:"version"`
|
||||
Revision string `json:"revision"`
|
||||
|
@ -133,7 +110,15 @@ type Options struct {
|
|||
}
|
||||
|
||||
// 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()
|
||||
|
||||
h := &Handler{
|
||||
|
@ -142,12 +127,14 @@ func New(st local.Storage, qe *promql.Engine, rm *rules.Manager, status *Prometh
|
|||
quitCh: make(chan struct{}),
|
||||
reloadCh: make(chan struct{}),
|
||||
options: o,
|
||||
statusInfo: status,
|
||||
versionInfo: version,
|
||||
birth: time.Now(),
|
||||
flagsMap: flags,
|
||||
|
||||
ruleManager: rm,
|
||||
queryEngine: qe,
|
||||
storage: st,
|
||||
targetManager: tm,
|
||||
ruleManager: rm,
|
||||
queryEngine: qe,
|
||||
storage: st,
|
||||
|
||||
apiV1: v1.NewAPI(qe, st),
|
||||
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.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("/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("/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) {
|
||||
h.statusInfo.mu.RLock()
|
||||
defer h.statusInfo.mu.RUnlock()
|
||||
|
||||
h.executeTemplate(w, "status.html", struct {
|
||||
Status *PrometheusStatus
|
||||
Birth time.Time
|
||||
Version *PrometheusVersion
|
||||
}{
|
||||
Status: h.statusInfo,
|
||||
Birth: h.birth,
|
||||
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) {
|
||||
dec := json.NewEncoder(w)
|
||||
if err := dec.Encode(h.versionInfo); err != nil {
|
||||
|
|
Loading…
Reference in a new issue