Move template functionality out of target.
The target implementation and interface contain methods only serving a specific purpose of the templates. They were moved to the template as they operate on more fundamental target data.
This commit is contained in:
parent
dbc08d390e
commit
1a2d57b45c
|
@ -19,7 +19,6 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -53,8 +52,6 @@ const (
|
||||||
var (
|
var (
|
||||||
errIngestChannelFull = errors.New("ingestion channel full")
|
errIngestChannelFull = errors.New("ingestion channel full")
|
||||||
|
|
||||||
localhostRepresentations = []string{"127.0.0.1", "localhost"}
|
|
||||||
|
|
||||||
targetIntervalLength = prometheus.NewSummaryVec(
|
targetIntervalLength = prometheus.NewSummaryVec(
|
||||||
prometheus.SummaryOpts{
|
prometheus.SummaryOpts{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
|
@ -118,17 +115,11 @@ type Target interface {
|
||||||
URL() string
|
URL() string
|
||||||
// Used to populate the `instance` label in metrics.
|
// Used to populate the `instance` label in metrics.
|
||||||
InstanceIdentifier() string
|
InstanceIdentifier() string
|
||||||
// The URL as seen from other hosts. References to localhost are resolved
|
|
||||||
// to the address of the prometheus server.
|
|
||||||
GlobalURL() string
|
|
||||||
// Return the labels describing the targets. These are the base labels
|
// Return the labels describing the targets. These are the base labels
|
||||||
// as well as internal labels.
|
// as well as internal labels.
|
||||||
Labels() clientmodel.LabelSet
|
fullLabels() clientmodel.LabelSet
|
||||||
// Return the target's base labels.
|
// Return the target's base labels.
|
||||||
BaseLabels() clientmodel.LabelSet
|
BaseLabels() clientmodel.LabelSet
|
||||||
// Return the target's base labels without job and instance label. That's
|
|
||||||
// useful for display purposes.
|
|
||||||
BaseLabelsWithoutJobAndInstance() clientmodel.LabelSet
|
|
||||||
// Start scraping the target in regular intervals.
|
// Start scraping the target in regular intervals.
|
||||||
RunScraper(storage.SampleAppender)
|
RunScraper(storage.SampleAppender)
|
||||||
// Stop scraping, synchronous.
|
// Stop scraping, synchronous.
|
||||||
|
@ -195,7 +186,6 @@ type target struct {
|
||||||
|
|
||||||
// The status object for the target. It is only set once on initialization.
|
// The status object for the target. It is only set once on initialization.
|
||||||
status *TargetStatus
|
status *TargetStatus
|
||||||
|
|
||||||
// The HTTP client used to scrape the target's endpoint.
|
// The HTTP client used to scrape the target's endpoint.
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
|
|
||||||
|
@ -419,66 +409,43 @@ func (t *target) InstanceIdentifier() string {
|
||||||
return t.url.Host
|
return t.url.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalURL implements Target.
|
// fullLabels implements Target.
|
||||||
func (t *target) GlobalURL() string {
|
func (t *target) fullLabels() clientmodel.LabelSet {
|
||||||
url := t.URL()
|
|
||||||
|
|
||||||
hostname, err := os.Hostname()
|
|
||||||
if err != nil {
|
|
||||||
glog.Warningf("Couldn't get hostname: %s, returning target.URL()", err)
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
for _, localhostRepresentation := range localhostRepresentations {
|
|
||||||
url = strings.Replace(url, "//"+localhostRepresentation, "//"+hostname, 1)
|
|
||||||
}
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
// Labels implements Target.
|
|
||||||
func (t *target) Labels() clientmodel.LabelSet {
|
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
ls := clientmodel.LabelSet{}
|
lset := make(clientmodel.LabelSet, len(t.baseLabels)+2)
|
||||||
for ln, lv := range t.baseLabels {
|
for ln, lv := range t.baseLabels {
|
||||||
ls[ln] = lv
|
lset[ln] = lv
|
||||||
}
|
}
|
||||||
ls[clientmodel.MetricsPathLabel] = clientmodel.LabelValue(t.url.Path)
|
lset[clientmodel.MetricsPathLabel] = clientmodel.LabelValue(t.url.Path)
|
||||||
ls[clientmodel.AddressLabel] = clientmodel.LabelValue(t.url.Host)
|
lset[clientmodel.AddressLabel] = clientmodel.LabelValue(t.url.Host)
|
||||||
return ls
|
return lset
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseLabels implements Target.
|
// BaseLabels implements Target.
|
||||||
func (t *target) BaseLabels() clientmodel.LabelSet {
|
func (t *target) BaseLabels() clientmodel.LabelSet {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
return t.baseLabels
|
lset := make(clientmodel.LabelSet, len(t.baseLabels))
|
||||||
}
|
|
||||||
|
|
||||||
// BaseLabelsWithoutJobAndInstance implements Target.
|
|
||||||
//
|
|
||||||
// TODO(fabxc): This method does not have to be part of the interface. Implement this
|
|
||||||
// as a template filter func for the single use case.
|
|
||||||
func (t *target) BaseLabelsWithoutJobAndInstance() clientmodel.LabelSet {
|
|
||||||
t.RLock()
|
|
||||||
defer t.RUnlock()
|
|
||||||
ls := clientmodel.LabelSet{}
|
|
||||||
for ln, lv := range t.baseLabels {
|
for ln, lv := range t.baseLabels {
|
||||||
if ln != clientmodel.JobLabel && ln != clientmodel.InstanceLabel {
|
lset[ln] = lv
|
||||||
ls[ln] = lv
|
|
||||||
}
|
}
|
||||||
}
|
return lset
|
||||||
return ls
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *target) recordScrapeHealth(sampleAppender storage.SampleAppender, timestamp clientmodel.Timestamp, scrapeDuration time.Duration) {
|
func (t *target) recordScrapeHealth(sampleAppender storage.SampleAppender, timestamp clientmodel.Timestamp, scrapeDuration time.Duration) {
|
||||||
healthMetric := clientmodel.Metric{}
|
t.RLock()
|
||||||
durationMetric := clientmodel.Metric{}
|
healthMetric := make(clientmodel.Metric, len(t.baseLabels)+1)
|
||||||
for label, value := range t.BaseLabels() {
|
durationMetric := make(clientmodel.Metric, len(t.baseLabels)+1)
|
||||||
|
|
||||||
|
healthMetric[clientmodel.MetricNameLabel] = clientmodel.LabelValue(scrapeHealthMetricName)
|
||||||
|
durationMetric[clientmodel.MetricNameLabel] = clientmodel.LabelValue(scrapeDurationMetricName)
|
||||||
|
|
||||||
|
for label, value := range t.baseLabels {
|
||||||
healthMetric[label] = value
|
healthMetric[label] = value
|
||||||
durationMetric[label] = value
|
durationMetric[label] = value
|
||||||
}
|
}
|
||||||
healthMetric[clientmodel.MetricNameLabel] = clientmodel.LabelValue(scrapeHealthMetricName)
|
t.RUnlock()
|
||||||
durationMetric[clientmodel.MetricNameLabel] = clientmodel.LabelValue(scrapeDurationMetricName)
|
|
||||||
|
|
||||||
healthValue := clientmodel.SampleValue(0)
|
healthValue := clientmodel.SampleValue(0)
|
||||||
if t.status.State() == Healthy {
|
if t.status.State() == Healthy {
|
||||||
|
|
|
@ -44,13 +44,6 @@ func TestBaseLabels(t *testing.T) {
|
||||||
if !reflect.DeepEqual(want, got) {
|
if !reflect.DeepEqual(want, got) {
|
||||||
t.Errorf("want base labels %v, got %v", want, got)
|
t.Errorf("want base labels %v, got %v", want, got)
|
||||||
}
|
}
|
||||||
delete(want, clientmodel.JobLabel)
|
|
||||||
delete(want, clientmodel.InstanceLabel)
|
|
||||||
|
|
||||||
got = target.BaseLabelsWithoutJobAndInstance()
|
|
||||||
if !reflect.DeepEqual(want, got) {
|
|
||||||
t.Errorf("want base labels %v, got %v", want, got)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTargetScrapeUpdatesState(t *testing.T) {
|
func TestTargetScrapeUpdatesState(t *testing.T) {
|
||||||
|
|
|
@ -215,7 +215,7 @@ func (tm *TargetManager) updateTargetGroup(tgroup *config.TargetGroup, cfg *conf
|
||||||
// to build up.
|
// to build up.
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(t Target) {
|
go func(t Target) {
|
||||||
match.Update(cfg, t.Labels())
|
match.Update(cfg, t.fullLabels())
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(tnew)
|
}(tnew)
|
||||||
newTargets[i] = match
|
newTargets[i] = match
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
{{range $pool}}
|
{{range $pool}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{.GlobalURL}}">{{.URL}}</a>
|
<a href="{{.URL | globalURL}}">{{.URL}}</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="alert alert-{{index $stateToClass .Status.State}} target_status_alert">
|
<span class="alert alert-{{index $stateToClass .Status.State}} target_status_alert">
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{.BaseLabelsWithoutJobAndInstance}}
|
{{stripLabels .BaseLabels "job" "instance"}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{if .Status.LastScrape.IsZero}}Never{{else}}{{since .Status.LastScrape}} ago{{end}}
|
{{if .Status.LastScrape.IsZero}}Never{{else}}{{since .Status.LastScrape}} ago{{end}}
|
||||||
|
|
43
web/web.go
43
web/web.go
|
@ -29,10 +29,14 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
clientmodel "github.com/prometheus/client_golang/model"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/web/api"
|
"github.com/prometheus/prometheus/web/api"
|
||||||
"github.com/prometheus/prometheus/web/blob"
|
"github.com/prometheus/prometheus/web/blob"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var localhostRepresentations = []string{"127.0.0.1", "localhost"}
|
||||||
|
|
||||||
// Commandline flags.
|
// Commandline flags.
|
||||||
var (
|
var (
|
||||||
listenAddress = flag.String("web.listen-address", ":9090", "Address to listen on for the web interface, API, and telemetry.")
|
listenAddress = flag.String("web.listen-address", ":9090", "Address to listen on for the web interface, API, and telemetry.")
|
||||||
|
@ -150,28 +154,53 @@ func getConsoles(pathPrefix string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTemplate(name string, pathPrefix string) (t *template.Template, err error) {
|
func getTemplate(name string, pathPrefix string) (*template.Template, error) {
|
||||||
t = template.New("_base")
|
t := template.New("_base")
|
||||||
|
var err error
|
||||||
|
|
||||||
t.Funcs(template.FuncMap{
|
t.Funcs(template.FuncMap{
|
||||||
"since": time.Since,
|
"since": time.Since,
|
||||||
"getConsoles": func() string { return getConsoles(pathPrefix) },
|
"getConsoles": func() string { return getConsoles(pathPrefix) },
|
||||||
"pathPrefix": func() string { return pathPrefix },
|
"pathPrefix": func() string { return pathPrefix },
|
||||||
|
"stripLabels": func(lset clientmodel.LabelSet, labels ...clientmodel.LabelName) clientmodel.LabelSet {
|
||||||
|
for _, ln := range labels {
|
||||||
|
delete(lset, ln)
|
||||||
|
}
|
||||||
|
return lset
|
||||||
|
},
|
||||||
|
"globalURL": func(url string) string {
|
||||||
|
hostname, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("Couldn't get hostname: %s, returning target.URL()", err)
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
for _, localhostRepresentation := range localhostRepresentations {
|
||||||
|
url = strings.Replace(url, "//"+localhostRepresentation, "//"+hostname, 1)
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
file, err := getTemplateFile("_base")
|
file, err := getTemplateFile("_base")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("Could not read base template: ", err)
|
glog.Errorln("Could not read base template:", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.Parse(file)
|
t, err = t.Parse(file)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorln("Could not parse base template:", err)
|
||||||
|
}
|
||||||
|
|
||||||
file, err = getTemplateFile(name)
|
file, err = getTemplateFile(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("Could not read base template: ", err)
|
glog.Error("Could not read template %d: ", name, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.Parse(file)
|
t, err = t.Parse(file)
|
||||||
return
|
if err != nil {
|
||||||
|
glog.Errorf("Could not parse template %s: %s", name, err)
|
||||||
|
}
|
||||||
|
return t, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeTemplate(w http.ResponseWriter, name string, data interface{}, pathPrefix string) {
|
func executeTemplate(w http.ResponseWriter, name string, data interface{}, pathPrefix string) {
|
||||||
|
|
Loading…
Reference in New Issue