/*
Create a http.HandlerFunc that is tied to r Registry such that requests
against it generate a representation of the housed metrics.
*/
func (registry *Registry) YieldExporter() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var instrumentable metrics.InstrumentableCall = func() {
			requestCount.Increment(nil)
			url := r.URL

			if strings.HasSuffix(url.Path, jsonSuffix) {
				header := w.Header()
				header.Set(ProtocolVersionHeader, APIVersion)
				header.Set(contentTypeHeader, jsonContentType)

				writer := decorateWriter(r, w)

				// TODO(matt): Migrate to ioutil.NopCloser.
				if closer, ok := writer.(io.Closer); ok {
					defer closer.Close()
				}

				registry.dumpToWriter(writer)

			} else {
				w.WriteHeader(http.StatusNotFound)
			}

		}
		metrics.InstrumentCall(instrumentable, requestLatencyAccumulator)
	}
}
Example #2
0
func (t *target) Scrape(earliest time.Time, results chan format.Result) (err error) {
	defer func() {
		futureState := t.state

		switch err {
		case nil:
			futureState = ALIVE
		default:
			futureState = UNREACHABLE
		}

		t.scheduler.Reschedule(earliest, futureState)
		t.state = futureState
	}()

	done := make(chan bool)

	request := func() {
		defer func() {
			done <- true
		}()

		var resp *http.Response // Don't shadow "err" from the enclosing function.
		resp, err = http.Get(t.Address())
		if err != nil {
			return
		}

		defer resp.Body.Close()

		processor, err := format.DefaultRegistry.ProcessorForRequestHeader(resp.Header)
		if err != nil {
			return
		}

		// 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())}
		for baseLabel, baseValue := range t.baseLabels {
			baseLabels[baseLabel] = baseValue
		}

		err = processor.Process(resp.Body, baseLabels, results)
		if err != nil {
			return
		}
	}

	accumulator := func(d time.Duration) {
		ms := float64(d) / float64(time.Millisecond)
		labels := map[string]string{address: t.Address(), outcome: success}
		if err != nil {
			labels[outcome] = failure
		}

		targetOperationLatencies.Add(labels, ms)
		targetOperations.Increment(labels)
	}

	go metrics.InstrumentCall(request, accumulator)

	select {
	case <-done:
		break
	case <-time.After(t.Deadline):
		err = fmt.Errorf("Target %s exceeded %s deadline.", t, t.Deadline)
	}

	return
}