web: remove flags, refactor handlers

pull/808/head
Fabian Reinartz 2015-06-15 12:50:53 +02:00
parent a0b3aaa551
commit 85d7c7640a
8 changed files with 281 additions and 390 deletions

View File

@ -1,72 +0,0 @@
// Copyright 2013 The Prometheus Authors
// 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 (
"net/http"
"sort"
"sync"
"github.com/prometheus/prometheus/rules"
)
// AlertStatus bundles alerting rules and the mapping of alert states to row
// classes.
type AlertStatus struct {
AlertingRules []*rules.AlertingRule
AlertStateToRowClass map[rules.AlertState]string
}
type byAlertStateSorter struct {
alerts []*rules.AlertingRule
}
func (s byAlertStateSorter) Len() int {
return len(s.alerts)
}
func (s byAlertStateSorter) Less(i, j int) bool {
return s.alerts[i].State() > s.alerts[j].State()
}
func (s byAlertStateSorter) Swap(i, j int) {
s.alerts[i], s.alerts[j] = s.alerts[j], s.alerts[i]
}
// AlertsHandler implements http.Handler.
type AlertsHandler struct {
RuleManager *rules.Manager
PathPrefix string
mutex sync.Mutex
}
func (h *AlertsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mutex.Lock()
defer h.mutex.Unlock()
alerts := h.RuleManager.AlertingRules()
alertsSorter := byAlertStateSorter{alerts: alerts}
sort.Sort(alertsSorter)
alertStatus := AlertStatus{
AlertingRules: alertsSorter.alerts,
AlertStateToRowClass: map[rules.AlertState]string{
rules.StateInactive: "success",
rules.StatePending: "warning",
rules.StateFiring: "danger",
},
}
executeTemplate(w, "alerts", alertStatus, h.PathPrefix)
}

View File

@ -96,7 +96,7 @@ func TestQuery(t *testing.T) {
api := &API{
Now: testNow,
Storage: storage,
QueryEngine: promql.NewEngine(storage),
QueryEngine: promql.NewEngine(storage, nil),
}
rtr := route.New()
api.Register(rtr.WithPrefix("/api"))

View File

@ -120,7 +120,7 @@ func templates_baseHtml() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "templates/_base.html", size: 2010, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "templates/_base.html", size: 2010, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -140,7 +140,7 @@ func templatesAlertsHtml() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "templates/alerts.html", size: 1699, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "templates/alerts.html", size: 1699, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -160,12 +160,12 @@ func templatesGraphHtml() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "templates/graph.html", size: 1559, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "templates/graph.html", size: 1559, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _templatesStatusHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xcc\x56\x4b\x6f\xfb\x36\x0c\xbf\xe7\x53\x68\x46\x8e\xb3\x0d\x0c\xd8\xa5\x48\x72\x48\xd1\xa1\x05\xd2\xa1\xe8\xe3\xb2\x4b\x21\xdb\x8c\xad\x4d\x95\x0c\x49\xee\x5a\x78\xfe\xee\x23\xe5\x38\x71\xfc\xd8\x8a\xff\x03\xff\x5e\x02\x51\xa4\xf8\xf8\xf1\x47\xc6\x75\x9d\xc1\x5e\x28\x60\x41\x01\x3c\x0b\x9a\x66\xf5\x53\x18\x32\x25\xde\x58\x18\x6e\xea\x1a\x54\xd6\x34\x8b\xc5\xc9\x2a\xd5\xca\x81\x72\x68\xb8\x60\x6c\x95\x89\x57\x96\x4a\x6e\xed\xda\x2b\x38\x9a\x98\x70\x2f\x2b\x91\x05\x1b\xd4\xa3\x45\xf1\xcb\xe6\xbe\x52\x4e\xbc\x00\xbb\x51\x7b\x6d\x5e\xb8\x13\x5a\xad\x62\xbc\x6f\x0d\x1c\x4f\x24\x74\x4e\x5a\xc1\xff\x86\xe8\x30\x03\x65\x21\x3b\xc8\x89\x36\x19\x98\xa3\x68\x9d\x11\xe5\x51\x2a\xf4\x2b\x98\x43\x4c\x72\x9a\xe8\xec\xbd\x93\x48\x36\x27\x81\xc4\x62\xf3\x54\x52\x4e\xab\x18\x8f\x67\x9a\x0c\x8b\x8e\xb6\xc2\xb8\x02\xa1\x88\x51\x3c\x39\x89\x4f\x5e\xf0\x7c\x8a\x80\x02\xe5\xb0\x59\x1c\x2b\xde\x56\x42\x66\x3f\xb0\xde\xba\x36\x5c\xe5\xc0\x96\x7f\xc1\xfb\xcf\x6c\xf9\xca\x65\x05\xec\x62\xcd\x22\x9f\x18\xe5\xe5\xdb\x37\x07\x0e\xb3\xa9\x2e\x61\x1d\x18\xfd\x77\x80\x70\x90\x17\x0f\xc6\x04\x54\xad\xef\xff\x82\x8a\xb2\x69\x59\xf4\x21\xe8\x2e\xb5\xda\x8b\xbc\x32\x43\xd8\x4a\x03\xd4\x99\x56\x4d\xf1\xe8\x62\xd1\xe3\x98\x04\x3b\x32\x6f\x51\x88\x48\x79\xcb\x15\xcf\xc1\xf8\xb3\x6d\x1a\x74\x75\xfd\x78\xbb\x7b\x50\xa2\x2c\xc1\xb1\x92\xbb\xe2\xce\x20\xc5\xdf\xd0\x75\x62\xe2\x8e\xf9\xc3\x30\x8f\xdc\xe4\xe0\x7a\x81\xbe\x53\x43\x09\xb4\x25\x0e\xa4\x74\xc5\xa3\xbe\x24\xd7\xbe\x7d\x6d\xf8\xeb\xfe\x7d\xaf\x91\xc7\xae\xff\xa9\x13\xec\x7a\xa9\xb5\xa4\x57\x29\x97\xb2\x7b\x7a\x87\x77\xfd\x27\xbe\xdd\x38\xf7\xfd\xc6\xb6\x8c\x20\x1a\xa4\x68\x5c\x72\xb5\x0e\x7e\x0d\xba\xfa\xd0\xf5\x33\x3d\xa0\x5c\x31\x45\x14\x0f\xcc\x38\x6f\xf9\x04\xaf\x0e\xc1\x36\x57\x2a\x2b\xb5\x50\x6e\xc8\xa7\x4e\xff\xe0\xb8\x1b\xcd\x65\xa7\xdc\x72\x0b\x6c\xc7\x13\x90\x76\xce\x64\xc7\xad\x63\x0f\xa9\xe1\xe5\xac\x97\x2b\x63\xb4\x19\x2b\x87\x25\x90\xc5\x00\x9b\xe1\xa0\xf5\x40\x27\xb8\xcf\x90\x9d\x41\x20\x1b\x5e\xe1\x25\x67\x05\x92\x6f\x1d\x20\x2b\x9f\xee\x77\xec\x1f\x96\x4b\x9d\x70\x89\xe7\xa6\x21\x9c\x23\x7f\x5a\xc5\x7c\xe4\x2e\x1e\xfb\x9b\x0e\x41\x8d\xec\x9a\xc8\x25\x18\xc7\xfc\x6f\x58\xd7\x02\x59\xfa\xc6\x06\x6c\x8b\xa8\x0d\x95\x8d\x5a\xae\x35\x0d\xb2\x94\xf8\xf3\x6c\xfd\xf5\xb3\x7f\x1b\x8c\xc3\x10\x1e\xc3\xa7\xe3\x5c\x62\x4a\xe6\xdb\x94\x92\x56\xc6\x6a\x13\x7a\x46\x21\x27\x59\xc6\x1d\x0f\x9d\xce\x73\x89\xfb\xcb\x61\x4b\x9c\x28\x03\xe6\x84\x23\xf9\xa0\xd6\x46\xe4\x42\x71\x19\x1e\xae\xb7\x80\x7b\x1a\x98\x01\x49\xc4\x12\x2a\xbf\xa0\x2a\x6e\xc1\xf1\x96\x69\xd4\x83\xc9\x4a\x97\x09\xd2\xb1\xb5\xa1\x41\xf3\x03\x7d\x10\xa3\xed\x49\x45\x43\x13\xb0\x40\x28\x04\x4f\xa5\x10\x4c\x40\x42\xde\xc4\x9e\xf5\x1c\x4e\x1a\xf5\xe8\xe6\x73\xed\xef\xf6\xff\x7f\x3b\x80\xce\x7b\x60\xfe\x37\x2c\x8d\x78\xe1\xe6\xdd\xcf\xb4\xbf\x69\x1a\x62\x63\xb7\xdd\x83\xe9\x96\x75\x29\xf5\xd7\xfb\x40\x23\x2d\xcc\x64\x33\x9b\x0b\x7e\x69\xf0\x4a\x22\xbb\x94\x56\x30\x1f\x78\x2e\xec\x57\xb2\xcb\xf7\xa1\xa3\x30\xed\x92\x76\x95\x44\x37\xf6\x0f\x30\xf8\xb7\xf9\x3b\xe0\x9e\xee\x0a\xab\x6b\x2b\xb0\xa3\x13\xf6\x38\x31\x3c\xd7\xd3\x39\x7e\x79\x2e\x7e\x71\x4d\xd5\x3c\x37\xdd\x19\x91\xc5\x4c\x0f\xef\x69\x52\x7b\xae\xe7\xf0\xfe\x68\x25\xc3\x1d\x3a\x7e\x77\xf6\xff\x3f\x36\x19\x7f\x11\x60\x92\xc6\x55\x25\xfb\x4d\xf2\xdc\x7e\x96\x0f\x29\x9f\xcc\x67\xfb\x88\xa2\x23\x7e\x91\x6f\x16\x9d\xf1\xbf\x01\x00\x00\xff\xff\x7a\x1b\xa1\x5a\xdd\x0b\x00\x00")
var _templatesStatusHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xcc\x56\x4b\x6f\xdb\x30\x0c\xbe\xe7\x57\x68\x46\x8f\xb3\x03\x0c\xd8\xa5\x48\x72\x48\xd1\xa1\x05\xd2\xa1\xe8\xe3\xb2\x4b\x21\xdb\x8c\xad\x4d\x95\x0c\x49\xee\x5a\xb8\xfe\xef\x23\xe5\xb8\x71\xfc\xd8\x8a\x3d\xb0\x5e\x0c\x51\xa2\x29\xf2\xfb\x3e\xd2\xae\xaa\x14\xb6\x42\x01\x0b\x72\xe0\x69\x50\xd7\x8b\x77\x61\xc8\x94\x78\x64\x61\xb8\xaa\x2a\x50\x69\x5d\xcf\x66\x7b\xaf\x44\x2b\x07\xca\xa1\xe3\x8c\xb1\x45\x2a\x1e\x58\x22\xb9\xb5\x4b\x7f\xc0\xd1\xc5\x84\x5b\x59\x8a\x34\x58\xe1\x39\x7a\xe4\x1f\x56\x57\xa5\x72\xe2\x1e\xd8\xb9\xda\x6a\x73\xcf\x9d\xd0\x6a\x31\xc7\xfd\xc6\xc1\xf1\x58\x42\x1b\xa4\x31\xfc\x33\xc4\x80\x29\x28\x0b\xe9\xce\x8e\xb5\x49\xc1\xbc\x98\xd6\x19\x51\xbc\x58\xb9\x7e\x00\xb3\xbb\x93\x82\xc6\x3a\x7d\x6a\x2d\xb2\xcd\xde\x20\x33\x5f\xdd\x16\x94\xd3\x62\x8e\xcb\x83\x93\x14\x8b\x8e\xd6\xc2\xb8\x1c\xa1\x98\xa3\xb9\x0f\x32\xdf\x47\xc1\xf5\xfe\x06\x34\x28\x87\xd5\xec\xa5\xe2\x75\x29\x64\xfa\x1f\xeb\xad\x2a\xc3\x55\x06\xec\xe8\x1b\x3c\xbd\x67\x47\x0f\x5c\x96\xc0\x8e\x97\x2c\xf2\x89\x51\x5e\x9e\xbe\x29\x70\x98\x4d\x74\x01\xcb\xc0\xe8\xef\x01\xc2\x41\x51\x3c\x18\x23\x50\x35\xb1\x7f\x06\x15\x65\xd3\xa8\xe8\x55\xd0\x9d\x68\xb5\x15\x59\x69\xfa\xb0\x15\x06\x88\x99\xe6\x98\xee\xa3\x8d\x59\x47\x63\x12\xec\xc0\xbd\x41\x21\xe1\x52\xb2\xc8\x7b\xd4\x35\xc6\x38\xbb\xb9\xd8\x5c\x2b\x51\x14\xe0\x58\xc1\x5d\x7e\x69\x50\xdb\x8f\x18\x33\x36\xf3\x56\xf2\xfd\xf8\x37\xdc\x64\xe0\x3a\x37\xfc\x23\x26\x3b\xdc\x7d\xd5\x31\x72\x57\x68\x2d\x89\xba\xa6\x88\x26\x8d\x4b\xdc\xb3\x1d\x06\x3d\x69\xd8\xbd\x5d\x7a\x1a\x5e\x89\xcc\x04\x9d\x0b\xae\x96\xc1\xc7\xa0\x4d\x16\x43\xdf\xd1\x0b\x74\x31\x72\x88\xe6\x8e\xdf\x43\xe2\x46\xd4\xb1\xbb\x6c\x75\xaa\xd2\x42\x0b\xe5\xfa\xaa\x68\xcf\xaf\x1d\x77\x83\xee\x6a\x0f\xd7\xdc\x02\xdb\xf0\x18\xa4\x9d\x72\xd9\x70\xeb\xd8\x75\x62\x78\x31\x19\xe5\xd4\x18\x6d\x86\x87\xfd\x12\xc8\xa3\x87\x4d\xbf\x5d\x3a\xa0\x13\xdc\x07\xc8\x4e\x20\x90\xf6\xb7\x70\x93\xb3\x1c\x95\xb4\x0c\x50\x62\xb7\x57\x1b\xf6\xcc\x32\xa9\x63\x2e\x71\x5d\xd7\x84\x73\xe4\x57\x8b\x39\x1f\x84\x9b\x0f\xe3\x8d\x5f\x41\x44\xb6\x24\x72\x09\xc6\x31\xff\x0c\xab\x8a\x45\x04\x79\x69\xa3\x33\xe0\x12\x59\x7f\x66\xb9\x5f\xdc\xe8\x13\x72\x67\x75\x8d\x7a\x23\xf1\xdc\x59\xef\x77\xe7\x5f\x0c\x86\x77\x10\x18\x87\xb1\x7a\x78\x34\x19\x53\x26\x7f\xa7\x8e\xa4\x34\x56\x9b\xd0\xcb\x09\x05\xc9\x52\xee\x78\xe8\x74\x96\x49\x1c\x41\x0e\xf9\x70\xa2\x08\x98\x13\x8e\xec\xdd\xb1\x36\x22\x13\x8a\xcb\x70\xb7\xbd\x06\x1c\xb5\xc0\x0c\x48\x52\x95\x50\xd9\x31\x55\x71\x01\x8e\x37\x32\x23\x02\x46\x2b\x3d\x8a\x51\x8b\x8d\x0f\x75\x99\x6f\xcd\x9d\x19\xad\xf7\x47\xd4\x31\x01\x0b\x84\x42\xf0\x54\x02\xc1\x08\x24\x14\x4d\x6c\x59\x27\xe0\xa8\x53\x47\x6b\x3e\xd7\xee\x78\xfe\xf5\xbb\x3d\xe8\x7c\x04\xe6\x9f\x61\x61\xc4\x3d\x37\x4f\xbe\xa1\xfd\x4e\x5d\x93\x14\xdb\x01\x1d\x8c\x53\xd6\xa6\xd4\x9d\xd0\xbd\x13\x69\x61\x22\x9b\xc9\x5c\xf0\x67\x81\x97\x12\xd5\xa5\xb4\x82\xe9\x8b\xa7\xae\xfd\x43\x75\x79\x1e\x5a\x09\xd3\x20\x69\xe6\x48\x74\x6e\xbf\x80\xc1\x2f\xdf\x67\xc0\x89\xdb\x16\x56\x55\x56\x20\xa3\x23\xfe\xd8\x31\x3c\xd3\xe3\x39\xfe\x7e\x2e\x7e\x6a\x8d\xd5\x3c\xd5\xda\x29\x89\xc5\x8c\x37\xef\xbe\x53\x3b\xa1\xa7\xf0\x7e\x6d\x25\xfd\x01\x3a\x7c\xef\xe0\x13\x3e\x74\x19\x7e\xd4\x31\x49\xe3\xca\x82\x7d\x92\x3c\xb3\x6f\xe5\x5f\xc8\x27\xf3\xd6\xfe\x83\x68\x89\x3f\xd5\xab\x59\xeb\xfc\x23\x00\x00\xff\xff\x6d\x4a\x14\xff\xa0\x0b\x00\x00")
func templatesStatusHtmlBytes() ([]byte, error) {
return bindataRead(
@ -180,7 +180,7 @@ func templatesStatusHtml() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "templates/status.html", size: 3037, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "templates/status.html", size: 2976, mode: os.FileMode(420), modTime: time.Unix(1434365394, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -200,7 +200,7 @@ func staticCssAlertsCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/css/alerts.css", size: 293, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/css/alerts.css", size: 293, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -220,7 +220,7 @@ func staticCssGraphCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/css/graph.css", size: 2668, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/css/graph.css", size: 2668, mode: os.FileMode(420), modTime: time.Unix(1434193569, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -240,7 +240,7 @@ func staticCssProm_consoleCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/css/prom_console.css", size: 2883, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/css/prom_console.css", size: 2883, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -260,7 +260,7 @@ func staticCssPrometheusCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/css/prometheus.css", size: 350, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/css/prometheus.css", size: 350, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -280,7 +280,7 @@ func staticImgAjaxLoaderGif() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/img/ajax-loader.gif", size: 847, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/img/ajax-loader.gif", size: 847, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -300,7 +300,7 @@ func staticJsAlertsJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/js/alerts.js", size: 567, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/js/alerts.js", size: 567, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -320,7 +320,7 @@ func staticJsGraphJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/js/graph.js", size: 19251, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/js/graph.js", size: 19251, mode: os.FileMode(420), modTime: time.Unix(1434193569, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -340,7 +340,7 @@ func staticJsGraph_templateHandlebar() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/js/graph_template.handlebar", size: 6365, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/js/graph_template.handlebar", size: 6365, mode: os.FileMode(420), modTime: time.Unix(1434193569, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -360,7 +360,7 @@ func staticJsProm_consoleJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/js/prom_console.js", size: 20259, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/js/prom_console.js", size: 20259, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -380,7 +380,7 @@ func staticVendorBootstrap331CssBootstrapThemeCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap-theme.css", size: 22474, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap-theme.css", size: 22474, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -400,7 +400,7 @@ func staticVendorBootstrap331CssBootstrapThemeCssMap() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap-theme.css.map", size: 43029, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap-theme.css.map", size: 43029, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -420,7 +420,7 @@ func staticVendorBootstrap331CssBootstrapThemeMinCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap-theme.min.css", size: 19835, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap-theme.min.css", size: 19835, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -440,7 +440,7 @@ func staticVendorBootstrap331CssBootstrapCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap.css", size: 137067, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap.css", size: 137067, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -460,7 +460,7 @@ func staticVendorBootstrap331CssBootstrapCssMap() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap.css.map", size: 366144, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap.css.map", size: 366144, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -480,7 +480,7 @@ func staticVendorBootstrap331CssBootstrapMinCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap.min.css", size: 113498, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/css/bootstrap.min.css", size: 113498, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -500,7 +500,7 @@ func staticVendorBootstrap331FontsGlyphiconsHalflingsRegularEot() (*asset, error
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/fonts/glyphicons-halflings-regular.eot", size: 20335, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/fonts/glyphicons-halflings-regular.eot", size: 20335, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -520,7 +520,7 @@ func staticVendorBootstrap331FontsGlyphiconsHalflingsRegularSvg() (*asset, error
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/fonts/glyphicons-halflings-regular.svg", size: 62926, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/fonts/glyphicons-halflings-regular.svg", size: 62926, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -540,7 +540,7 @@ func staticVendorBootstrap331FontsGlyphiconsHalflingsRegularTtf() (*asset, error
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/fonts/glyphicons-halflings-regular.ttf", size: 41280, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/fonts/glyphicons-halflings-regular.ttf", size: 41280, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -560,7 +560,7 @@ func staticVendorBootstrap331FontsGlyphiconsHalflingsRegularWoff() (*asset, erro
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/fonts/glyphicons-halflings-regular.woff", size: 23320, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/fonts/glyphicons-halflings-regular.woff", size: 23320, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -580,7 +580,7 @@ func staticVendorBootstrap331JsBootstrapJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/js/bootstrap.js", size: 67155, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/js/bootstrap.js", size: 67155, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -600,7 +600,7 @@ func staticVendorBootstrap331JsBootstrapMinJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/js/bootstrap.min.js", size: 35601, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/js/bootstrap.min.js", size: 35601, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -620,7 +620,7 @@ func staticVendorBootstrap331JsNpmJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/js/npm.js", size: 484, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-3.3.1/js/npm.js", size: 484, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -640,7 +640,7 @@ func staticVendorBootstrapDatetimepickerBootstrapDatetimepickerJs() (*asset, err
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.js", size: 53185, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.js", size: 53185, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -660,7 +660,7 @@ func staticVendorBootstrapDatetimepickerBootstrapDatetimepickerMinCss() (*asset,
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css", size: 5059, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css", size: 5059, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -680,7 +680,7 @@ func staticVendorBootstrap3TypeaheadBootstrap3TypeaheadMinJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/bootstrap3-typeahead/bootstrap3-typeahead.min.js", size: 7856, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/bootstrap3-typeahead/bootstrap3-typeahead.min.js", size: 7856, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -700,7 +700,7 @@ func staticVendorJsHandlebarsJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/js/handlebars.js", size: 65639, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/js/handlebars.js", size: 65639, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -720,7 +720,7 @@ func staticVendorJsJqueryHotkeysJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/js/jquery.hotkeys.js", size: 3283, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/js/jquery.hotkeys.js", size: 3283, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -740,7 +740,7 @@ func staticVendorJsJqueryMinJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/js/jquery.min.js", size: 95935, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/js/jquery.min.js", size: 95935, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -760,7 +760,7 @@ func staticVendorJsJquerySelectionJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/js/jquery.selection.js", size: 13320, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/js/jquery.selection.js", size: 13320, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -780,7 +780,7 @@ func staticVendorRickshawRickshawMinCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/rickshaw/rickshaw.min.css", size: 6102, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/rickshaw/rickshaw.min.css", size: 6102, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -800,7 +800,7 @@ func staticVendorRickshawRickshawMinJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/rickshaw/rickshaw.min.js", size: 76322, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/rickshaw/rickshaw.min.js", size: 76322, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -820,7 +820,7 @@ func staticVendorRickshawVendorD3LayoutMinJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/rickshaw/vendor/d3.layout.min.js", size: 17514, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/rickshaw/vendor/d3.layout.min.js", size: 17514, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -840,7 +840,7 @@ func staticVendorRickshawVendorD3V3Js() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static/vendor/rickshaw/vendor/d3.v3.js", size: 144718, mode: os.FileMode(436), modTime: time.Unix(1434138876, 0)}
info := bindataFileInfo{name: "static/vendor/rickshaw/vendor/d3.v3.js", size: 144718, mode: os.FileMode(420), modTime: time.Unix(1434029945, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}

View File

@ -28,11 +28,10 @@
<pre>{{.Config}}</pre>
<h2>Rules</h2>
<pre>{{range .RuleManager.Rules}}{{.HTMLSnippet pathPrefix}}<br/>{{end}}</pre>
<pre>{{range call .Rules}}{{.HTMLSnippet pathPrefix}}<br/>{{end}}</pre>
<h2>Targets</h2>
<table class="table table-condensed table-bordered table-striped table-hover">
{{$healthToClass := .TargetHealthToClass}}
{{range $job, $pool := call .TargetPools}}
<thead>
<tr><th colspan="5" class="job_header">{{$job}}</th></tr>
@ -51,7 +50,7 @@
<a href="{{.URL | globalURL}}">{{.URL}}</a>
</td>
<td>
<span class="alert alert-{{index $healthToClass .Status.Health}} target_status_alert">
<span class="alert alert-{{ .Status.Health | healthToClass }} target_status_alert">
{{.Status.Health}}
</span>
</td>

View File

@ -1,90 +0,0 @@
// Copyright 2014 The Prometheus Authors
// 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 (
"flag"
"io"
"io/ioutil"
"net/http"
"net/url"
"path/filepath"
clientmodel "github.com/prometheus/client_golang/model"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/template"
"github.com/prometheus/prometheus/util/route"
)
var (
consoleTemplatesPath = flag.String("web.console.templates", "consoles", "Path to the console template directory, available at /console.")
consoleLibrariesPath = flag.String("web.console.libraries", "console_libraries", "Path to the console library directory.")
)
// ConsolesHandler implements http.Handler.
type ConsolesHandler struct {
QueryEngine *promql.Engine
PathPrefix string
}
func (h *ConsolesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := route.Context(r)
name := route.Param(ctx, "filepath")
file, err := http.Dir(*consoleTemplatesPath).Open(name)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
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,
Path: name,
}
tmpl := template.NewTemplateExpander(string(text), "__console_"+name, data, clientmodel.Now(), h.QueryEngine, h.PathPrefix)
filenames, err := filepath.Glob(*consoleLibrariesPath + "/*.lib")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
result, err := tmpl.ExpandHTML(filenames)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
io.WriteString(w, result)
}

View File

@ -1,27 +0,0 @@
// Copyright 2013 The Prometheus Authors
// 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 (
"net/http"
)
// GraphsHandler implements http.Handler.
type GraphsHandler struct {
PathPrefix string
}
func (h *GraphsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
executeTemplate(w, "graph", nil, h.PathPrefix)
}

View File

@ -1,63 +0,0 @@
// Copyright 2013 The Prometheus Authors
// 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 (
"net/http"
"sync"
"time"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/retrieval"
"github.com/prometheus/prometheus/rules"
)
// PrometheusStatusHandler implements http.Handler.
type PrometheusStatusHandler struct {
mu sync.RWMutex
BuildInfo map[string]string
Config string
Flags map[string]string
RuleManager *rules.Manager
TargetPools func() map[string][]*retrieval.Target
Birth time.Time
PathPrefix string
}
// TargetHealthToClass returns a map of TargetHealth to the name of a Bootstrap CSS class.
func (h *PrometheusStatusHandler) TargetHealthToClass() map[retrieval.TargetHealth]string {
return map[retrieval.TargetHealth]string{
retrieval.HealthUnknown: "warning",
retrieval.HealthGood: "success",
retrieval.HealthBad: "danger",
}
}
func (h *PrometheusStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mu.RLock()
executeTemplate(w, "status", h, h.PathPrefix)
h.mu.RUnlock()
}
// ApplyConfig updates the status handler's state as the new config requires.
// Returns true on success.
func (h *PrometheusStatusHandler) ApplyConfig(conf *config.Config) bool {
h.mu.Lock()
h.Config = conf.String()
h.mu.Unlock()
return true
}

View File

@ -14,128 +14,265 @@
package web
import (
"flag"
"fmt"
"html/template"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"time"
template_std "html/template"
pprof_runtime "runtime/pprof"
clientmodel "github.com/prometheus/client_golang/model"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/log"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/retrieval"
"github.com/prometheus/prometheus/rules"
"github.com/prometheus/prometheus/storage/local"
"github.com/prometheus/prometheus/template"
"github.com/prometheus/prometheus/util/route"
"github.com/prometheus/prometheus/web/api/legacy"
"github.com/prometheus/prometheus/web/api/v1"
"github.com/prometheus/prometheus/util/route"
"github.com/prometheus/prometheus/web/blob"
)
var localhostRepresentations = []string{"127.0.0.1", "localhost"}
// Commandline flags.
var (
listenAddress = flag.String("web.listen-address", ":9090", "Address to listen on for the web interface, API, and telemetry.")
hostname = flag.String("web.hostname", "", "Hostname on which the server is available.")
metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
useLocalAssets = flag.Bool("web.use-local-assets", false, "Read assets/templates from file instead of binary.")
userAssetsPath = flag.String("web.user-assets", "", "Path to static asset directory, available at /user.")
enableQuit = flag.Bool("web.enable-remote-shutdown", false, "Enable remote service shutdown.")
)
// Handler serves various HTTP endpoints of the Prometheus server
type Handler struct {
ruleManager *rules.Manager
queryEngine *promql.Engine
// WebService handles the HTTP endpoints with the exception of /api.
type WebService struct {
QuitChan chan struct{}
router *route.Router
apiV1 *v1.API
apiLegacy *legacy.API
router *route.Router
quitCh chan struct{}
options *Options
status *PrometheusStatus
muAlerts sync.Mutex
}
type WebServiceOptions struct {
PathPrefix string
StatusHandler *PrometheusStatusHandler
APILegacy *legacy.API
APIv1 *v1.API
AlertsHandler *AlertsHandler
ConsolesHandler *ConsolesHandler
GraphsHandler *GraphsHandler
// PrometheusStatus contains various information about the status
// of the running Prometheus process.
type PrometheusStatus struct {
Birth time.Time
BuildInfo map[string]string
Flags map[string]string
Config string
// A function that returns the current scrape targets pooled
// by their job name.
TargetPools func() map[string][]*retrieval.Target
// A function that returns all loaded rules.
Rules func() []rules.Rule
mu sync.RWMutex
}
// NewWebService returns a new WebService.
func NewWebService(o *WebServiceOptions) *WebService {
// 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()
s.Config = conf.String()
s.mu.Unlock()
return true
}
// Options for the web Handler.
type Options struct {
PathPrefix string
ListenAddress string
Hostname string
MetricsPath string
UseLocalAssets bool
UserAssetsPath string
ConsoleTemplatesPath string
ConsoleLibrariesPath string
EnableQuit bool
}
// New initializes a new web Handler.
func New(st local.Storage, qe *promql.Engine, rm *rules.Manager, status *PrometheusStatus, o *Options) *Handler {
router := route.New()
ws := &WebService{
router: router,
QuitChan: make(chan struct{}),
h := &Handler{
router: router,
quitCh: make(chan struct{}),
options: o,
status: status,
ruleManager: rm,
queryEngine: qe,
apiV1: &v1.API{
QueryEngine: qe,
Storage: st,
},
apiLegacy: &legacy.API{
QueryEngine: qe,
Storage: st,
Now: clientmodel.Now,
},
}
if o.PathPrefix != "" {
// If the prefix is missing for the root path, append it.
// If the prefix is missing for the root path, prepend it.
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, o.PathPrefix, 302)
http.Redirect(w, r, o.PathPrefix, http.StatusFound)
})
router = router.WithPrefix(o.PathPrefix)
}
instr := prometheus.InstrumentHandler
instrf := prometheus.InstrumentHandlerFunc
instrh := prometheus.InstrumentHandler
router.Get("/", instr("status", o.StatusHandler))
router.Get("/alerts", instr("alerts", o.AlertsHandler))
router.Get("/graph", instr("graph", o.GraphsHandler))
router.Get("/heap", instr("heap", http.HandlerFunc(dumpHeap)))
router.Get("/", instrf("status", h.statush))
router.Get("/alerts", instrf("alerts", h.alerts))
router.Get("/graph", instrf("graph", h.graph))
router.Get(*metricsPath, prometheus.Handler().ServeHTTP)
router.Get("/heap", instrf("heap", dumpHeap))
o.APILegacy.Register(router.WithPrefix("/api"))
router.Get(o.MetricsPath, prometheus.Handler().ServeHTTP)
o.APIv1.Register(router.WithPrefix("/api/v1"))
h.apiLegacy.Register(router.WithPrefix("/api"))
h.apiV1.Register(router.WithPrefix("/api/v1"))
router.Get("/consoles/*filepath", instr("consoles", o.ConsolesHandler))
router.Get("/consoles/*filepath", instrf("consoles", h.consoles))
if *useLocalAssets {
router.Get("/static/*filepath", instr("static", route.FileServe("web/blob/static")))
if o.UseLocalAssets {
router.Get("/static/*filepath", instrf("static", route.FileServe("web/blob/static")))
} else {
router.Get("/static/*filepath", instr("static", blob.Handler{}))
router.Get("/static/*filepath", instrh("static", blob.Handler{}))
}
if *userAssetsPath != "" {
router.Get("/user/*filepath", instr("user", route.FileServe(*userAssetsPath)))
if o.UserAssetsPath != "" {
router.Get("/user/*filepath", instrf("user", route.FileServe(o.UserAssetsPath)))
}
if *enableQuit {
router.Post("/-/quit", ws.quitHandler)
if o.EnableQuit {
router.Post("/-/quit", h.quit)
}
return ws
return h
}
// Quit returns the receive-only quit channel.
func (h *Handler) Quit() <-chan struct{} {
return h.quitCh
}
// Run serves the HTTP endpoints.
func (ws *WebService) Run() {
log.Infof("Listening on %s", *listenAddress)
func (h *Handler) Run() {
log.Infof("Listening on %s", h.options.ListenAddress)
// If we cannot bind to a port, retry after 30 seconds.
for {
err := http.ListenAndServe(*listenAddress, ws.router)
err := http.ListenAndServe(h.options.ListenAddress, h.router)
if err != nil {
log.Errorf("Could not listen on %s: %s", *listenAddress, err)
log.Errorf("Could not listen on %s: %s", h.options.ListenAddress, err)
}
time.Sleep(30 * time.Second)
}
}
func (ws *WebService) quitHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Requesting termination... Goodbye!")
func (h *Handler) alerts(w http.ResponseWriter, r *http.Request) {
h.muAlerts.Lock()
defer h.muAlerts.Unlock()
close(ws.QuitChan)
alerts := h.ruleManager.AlertingRules()
alertsSorter := byAlertStateSorter{alerts: alerts}
sort.Sort(alertsSorter)
alertStatus := AlertStatus{
AlertingRules: alertsSorter.alerts,
AlertStateToRowClass: map[rules.AlertState]string{
rules.StateInactive: "success",
rules.StatePending: "warning",
rules.StateFiring: "danger",
},
}
h.executeTemplate(w, "alerts", alertStatus)
}
func getTemplateFile(name string) (string, error) {
if *useLocalAssets {
func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) {
ctx := route.Context(r)
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,
Path: name,
}
tmpl := template.NewTemplateExpander(string(text), "__console_"+name, data, clientmodel.Now(), h.queryEngine, h.options.PathPrefix)
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) {
h.executeTemplate(w, "graph", nil)
}
func (h *Handler) statush(w http.ResponseWriter, r *http.Request) {
h.status.mu.RLock()
defer h.status.mu.RUnlock()
h.executeTemplate(w, "status", h.status)
}
func (h *Handler) quit(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Requesting termination... Goodbye!")
close(h.quitCh)
}
func (h *Handler) getTemplateFile(name string) (string, error) {
if h.options.UseLocalAssets {
file, err := ioutil.ReadFile(fmt.Sprintf("web/blob/templates/%s.html", name))
if err != nil {
log.Errorf("Could not read %s template: %s", name, err)
@ -151,26 +288,26 @@ func getTemplateFile(name string) (string, error) {
return string(file), nil
}
func getConsoles(pathPrefix string) string {
if _, err := os.Stat(*consoleTemplatesPath + "/index.html"); !os.IsNotExist(err) {
return pathPrefix + "/consoles/index.html"
func (h *Handler) getConsoles() string {
if _, err := os.Stat(h.options.ConsoleTemplatesPath + "/index.html"); !os.IsNotExist(err) {
return h.options.PathPrefix + "/consoles/index.html"
}
if *userAssetsPath != "" {
if _, err := os.Stat(*userAssetsPath + "/index.html"); !os.IsNotExist(err) {
return pathPrefix + "/user/index.html"
if h.options.UserAssetsPath != "" {
if _, err := os.Stat(h.options.UserAssetsPath + "/index.html"); !os.IsNotExist(err) {
return h.options.PathPrefix + "/user/index.html"
}
}
return ""
}
func getTemplate(name string, pathPrefix string) (*template.Template, error) {
t := template.New("_base")
func (h *Handler) getTemplate(name string) (*template_std.Template, error) {
t := template_std.New("_base")
var err error
t.Funcs(template.FuncMap{
t.Funcs(template_std.FuncMap{
"since": time.Since,
"getConsoles": func() string { return getConsoles(pathPrefix) },
"pathPrefix": func() string { return pathPrefix },
"getConsoles": h.getConsoles,
"pathPrefix": func() string { return h.options.PathPrefix },
"stripLabels": func(lset clientmodel.LabelSet, labels ...clientmodel.LabelName) clientmodel.LabelSet {
for _, ln := range labels {
delete(lset, ln)
@ -178,19 +315,24 @@ func getTemplate(name string, pathPrefix string) (*template.Template, error) {
return lset
},
"globalURL": func(url string) string {
hostname, err := getHostname()
if err != nil {
log.Warnf("Couldn't get hostname: %s, returning target.URL()", err)
return url
}
for _, localhostRepresentation := range localhostRepresentations {
url = strings.Replace(url, "//"+localhostRepresentation, "//"+hostname, 1)
url = strings.Replace(url, "//"+localhostRepresentation, "//"+h.options.Hostname, 1)
}
return url
},
"healthToClass": func(th retrieval.TargetHealth) string {
switch th {
case retrieval.HealthUnknown:
return "warning"
case retrieval.HealthGood:
return "success"
default:
return "danger"
}
},
})
file, err := getTemplateFile("_base")
file, err := h.getTemplateFile("_base")
if err != nil {
log.Errorln("Could not read base template:", err)
return nil, err
@ -200,7 +342,7 @@ func getTemplate(name string, pathPrefix string) (*template.Template, error) {
log.Errorln("Could not parse base template:", err)
}
file, err = getTemplateFile(name)
file, err = h.getTemplateFile(name)
if err != nil {
log.Error("Could not read template %s: %s", name, err)
return nil, err
@ -212,8 +354,8 @@ func getTemplate(name string, pathPrefix string) (*template.Template, error) {
return t, err
}
func executeTemplate(w http.ResponseWriter, name string, data interface{}, pathPrefix string) {
tpl, err := getTemplate(name, pathPrefix)
func (h *Handler) executeTemplate(w http.ResponseWriter, name string, data interface{}) {
tpl, err := h.getTemplate(name)
if err != nil {
log.Error("Error preparing layout template: ", err)
return
@ -236,22 +378,24 @@ func dumpHeap(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Done")
}
// MustBuildServerURL returns the server URL and panics in case an error occurs.
func MustBuildServerURL(pathPrefix string) string {
_, port, err := net.SplitHostPort(*listenAddress)
if err != nil {
panic(err)
}
hostname, err := getHostname()
if err != nil {
panic(err)
}
return fmt.Sprintf("http://%s:%s%s/", hostname, port, pathPrefix)
// AlertStatus bundles alerting rules and the mapping of alert states to row classes.
type AlertStatus struct {
AlertingRules []*rules.AlertingRule
AlertStateToRowClass map[rules.AlertState]string
}
func getHostname() (string, error) {
if *hostname != "" {
return *hostname, nil
}
return os.Hostname()
type byAlertStateSorter struct {
alerts []*rules.AlertingRule
}
func (s byAlertStateSorter) Len() int {
return len(s.alerts)
}
func (s byAlertStateSorter) Less(i, j int) bool {
return s.alerts[i].State() > s.alerts[j].State()
}
func (s byAlertStateSorter) Swap(i, j int) {
s.alerts[i], s.alerts[j] = s.alerts[j], s.alerts[i]
}