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:
Fabian Reinartz 2015-05-18 12:16:25 +02:00
parent dbc08d390e
commit 1a2d57b45c
5 changed files with 59 additions and 70 deletions

View file

@ -19,7 +19,6 @@ import (
"math/rand"
"net/http"
"net/url"
"os"
"strings"
"sync"
"time"
@ -53,8 +52,6 @@ const (
var (
errIngestChannelFull = errors.New("ingestion channel full")
localhostRepresentations = []string{"127.0.0.1", "localhost"}
targetIntervalLength = prometheus.NewSummaryVec(
prometheus.SummaryOpts{
Namespace: namespace,
@ -118,17 +115,11 @@ type Target interface {
URL() string
// Used to populate the `instance` label in metrics.
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
// as well as internal labels.
Labels() clientmodel.LabelSet
fullLabels() clientmodel.LabelSet
// Return the target's base labels.
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.
RunScraper(storage.SampleAppender)
// Stop scraping, synchronous.
@ -195,7 +186,6 @@ type target struct {
// The status object for the target. It is only set once on initialization.
status *TargetStatus
// The HTTP client used to scrape the target's endpoint.
httpClient *http.Client
@ -419,66 +409,43 @@ func (t *target) InstanceIdentifier() string {
return t.url.Host
}
// GlobalURL implements Target.
func (t *target) GlobalURL() string {
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 {
// fullLabels implements Target.
func (t *target) fullLabels() clientmodel.LabelSet {
t.RLock()
defer t.RUnlock()
ls := clientmodel.LabelSet{}
lset := make(clientmodel.LabelSet, len(t.baseLabels)+2)
for ln, lv := range t.baseLabels {
ls[ln] = lv
lset[ln] = lv
}
ls[clientmodel.MetricsPathLabel] = clientmodel.LabelValue(t.url.Path)
ls[clientmodel.AddressLabel] = clientmodel.LabelValue(t.url.Host)
return ls
lset[clientmodel.MetricsPathLabel] = clientmodel.LabelValue(t.url.Path)
lset[clientmodel.AddressLabel] = clientmodel.LabelValue(t.url.Host)
return lset
}
// BaseLabels implements Target.
func (t *target) BaseLabels() clientmodel.LabelSet {
t.RLock()
defer t.RUnlock()
return 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{}
lset := make(clientmodel.LabelSet, len(t.baseLabels))
for ln, lv := range t.baseLabels {
if ln != clientmodel.JobLabel && ln != clientmodel.InstanceLabel {
ls[ln] = lv
}
lset[ln] = lv
}
return ls
return lset
}
func (t *target) recordScrapeHealth(sampleAppender storage.SampleAppender, timestamp clientmodel.Timestamp, scrapeDuration time.Duration) {
healthMetric := clientmodel.Metric{}
durationMetric := clientmodel.Metric{}
for label, value := range t.BaseLabels() {
t.RLock()
healthMetric := make(clientmodel.Metric, len(t.baseLabels)+1)
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
durationMetric[label] = value
}
healthMetric[clientmodel.MetricNameLabel] = clientmodel.LabelValue(scrapeHealthMetricName)
durationMetric[clientmodel.MetricNameLabel] = clientmodel.LabelValue(scrapeDurationMetricName)
t.RUnlock()
healthValue := clientmodel.SampleValue(0)
if t.status.State() == Healthy {

View file

@ -44,13 +44,6 @@ func TestBaseLabels(t *testing.T) {
if !reflect.DeepEqual(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) {

View file

@ -215,7 +215,7 @@ func (tm *TargetManager) updateTargetGroup(tgroup *config.TargetGroup, cfg *conf
// to build up.
wg.Add(1)
go func(t Target) {
match.Update(cfg, t.Labels())
match.Update(cfg, t.fullLabels())
wg.Done()
}(tnew)
newTargets[i] = match

View file

@ -48,7 +48,7 @@
{{range $pool}}
<tr>
<td>
<a href="{{.GlobalURL}}">{{.URL}}</a>
<a href="{{.URL | globalURL}}">{{.URL}}</a>
</td>
<td>
<span class="alert alert-{{index $stateToClass .Status.State}} target_status_alert">
@ -56,7 +56,7 @@
</span>
</td>
<td>
{{.BaseLabelsWithoutJobAndInstance}}
{{stripLabels .BaseLabels "job" "instance"}}
</td>
<td>
{{if .Status.LastScrape.IsZero}}Never{{else}}{{since .Status.LastScrape}} ago{{end}}

View file

@ -29,10 +29,14 @@ import (
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
clientmodel "github.com/prometheus/client_golang/model"
"github.com/prometheus/prometheus/web/api"
"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.")
@ -150,28 +154,53 @@ func getConsoles(pathPrefix string) string {
return ""
}
func getTemplate(name string, pathPrefix string) (t *template.Template, err error) {
t = template.New("_base")
func getTemplate(name string, pathPrefix string) (*template.Template, error) {
t := template.New("_base")
var err error
t.Funcs(template.FuncMap{
"since": time.Since,
"getConsoles": func() string { return getConsoles(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")
if err != nil {
glog.Error("Could not read base template: ", err)
glog.Errorln("Could not read base template:", 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)
if err != nil {
glog.Error("Could not read base template: ", err)
glog.Error("Could not read template %d: ", name, err)
return nil, err
}
t.Parse(file)
return
t, err = t.Parse(file)
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) {