diff --git a/model/labelname.go b/model/labelname.go index b9bf32cc4..c019df4fa 100644 --- a/model/labelname.go +++ b/model/labelname.go @@ -13,11 +13,16 @@ package model -// The label name used to indicate the metric name of a timeseries. -const MetricNameLabel = LabelName("name") - -// The label name used to indicate the job from which a timeseries was scraped. -const JobLabel = LabelName("job") +const ( + // The label name indicating the metric name of a timeseries. + MetricNameLabel = LabelName("name") + // The label name indicating the job from which a timeseries was scraped. + JobLabel = LabelName("job") + // The label name indicating the instance from which a timeseries was scraped. + InstanceLabel = LabelName("instance") + // The metric name for the synthetic health variable. + ScrapeHealthMetricName = LabelValue("up") +) // A LabelName is a key for a LabelSet or Metric. It has a value associated // therewith. diff --git a/retrieval/target.go b/retrieval/target.go index 21feba610..03caff9ae 100644 --- a/retrieval/target.go +++ b/retrieval/target.go @@ -24,10 +24,6 @@ import ( "time" ) -const ( - instance = "instance" -) - var ( localhostRepresentations = []string{"http://127.0.0.1", "http://localhost"} ) @@ -140,14 +136,42 @@ func NewTarget(address string, deadline time.Duration, baseLabels model.LabelSet return target } +func (t *target) recordScrapeHealth(results chan format.Result, timestamp time.Time, healthy bool) { + metric := model.Metric{} + for label, value := range t.baseLabels { + metric[label] = value + } + metric[model.MetricNameLabel] = model.ScrapeHealthMetricName + + healthValue := model.SampleValue(0) + if healthy { + healthValue = model.SampleValue(1) + } + + sample := model.Sample{ + Metric: metric, + Timestamp: timestamp, + Value: healthValue, + } + + results <- format.Result{ + Err: nil, + Sample: sample, + } +} + func (t *target) Scrape(earliest time.Time, results chan format.Result) (err error) { + now := time.Now() + defer func() { futureState := t.state switch err { case nil: + t.recordScrapeHealth(results, now, true) futureState = ALIVE default: + t.recordScrapeHealth(results, now, false) futureState = UNREACHABLE } @@ -162,8 +186,6 @@ func (t *target) Scrape(earliest time.Time, results chan format.Result) (err err done <- true }() - now := time.Now() - var resp *http.Response // Don't shadow "err" from the enclosing function. resp, err = http.Get(t.Address()) if err != nil { @@ -179,7 +201,7 @@ func (t *target) Scrape(earliest time.Time, results chan format.Result) (err err // XXX: This is a wart; we need to handle this more gracefully down the // road, especially once we have service discovery support. - baseLabels := model.LabelSet{instance: model.LabelValue(t.Address())} + baseLabels := model.LabelSet{model.InstanceLabel: model.LabelValue(t.Address())} for baseLabel, baseValue := range t.baseLabels { baseLabels[baseLabel] = baseValue } diff --git a/retrieval/target_test.go b/retrieval/target_test.go index b5b051d05..b99845f48 100644 --- a/retrieval/target_test.go +++ b/retrieval/target_test.go @@ -25,7 +25,7 @@ func TestTargetScrapeUpdatesState(t *testing.T) { state: UNKNOWN, address: "bad schema", } - testTarget.Scrape(time.Time{}, make(chan format.Result)) + testTarget.Scrape(time.Time{}, make(chan format.Result, 2)) if testTarget.state != UNREACHABLE { t.Errorf("Expected target state %v, actual: %v", UNREACHABLE, testTarget.state) }