Example #1
0
// Quantiles expects a regex whose first capture group can be parsed as a
// float64. It will dump the WriterTo and parse each line, expecting to find a
// match. It observes all captured floats into a generic.Histogram with the
// given number of buckets, and returns the 50th, 90th, 95th, and 99th quantiles
// from that histogram.
func Quantiles(w io.WriterTo, regex string, buckets int) func() (float64, float64, float64, float64) {
	return func() (float64, float64, float64, float64) {
		h := generic.NewHistogram("quantile-test", buckets)
		stats(w, regex, h)
		return h.Quantile(0.50), h.Quantile(0.90), h.Quantile(0.95), h.Quantile(0.99)
	}
}
Example #2
0
func TestHistogram(t *testing.T) {
	in := New(map[string]string{"foo": "alpha"}, influxdb.BatchPointsConfig{}, log.NewNopLogger())
	re := regexp.MustCompile(`influx_histogram,foo=alpha bar="beta",value=([0-9\.]+) [0-9]+`)
	histogram := in.NewHistogram("influx_histogram").With("bar", "beta")
	quantiles := func() (float64, float64, float64, float64) {
		w := &bufWriter{}
		in.WriteTo(w)
		h := generic.NewHistogram("h", 50)
		matches := re.FindAllStringSubmatch(w.buf.String(), -1)
		for _, match := range matches {
			f, _ := strconv.ParseFloat(match[1], 64)
			h.Observe(f)
		}
		return h.Quantile(0.50), h.Quantile(0.90), h.Quantile(0.95), h.Quantile(0.99)
	}
	if err := teststat.TestHistogram(histogram, quantiles, 0.01); err != nil {
		t.Fatal(err)
	}
}
Example #3
0
func TestHistogram(t *testing.T) {
	const name = "ghi"

	// Circonus just emits bucketed counts. We'll dump them into a generic
	// histogram (losing some precision) and take statistics from there. Note
	// this does assume that the generic histogram computes statistics properly,
	// but we have another test for that :)
	re := regexp.MustCompile(`^H\[([0-9\.e\+]+)\]=([0-9]+)$`) // H[1.2e+03]=456

	var p50, p90, p95, p99 float64
	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var res map[string]struct {
			Values []string `json:"_value"` // reverse-engineered :\
		}
		json.NewDecoder(r.Body).Decode(&res)

		h := generic.NewHistogram("dummy", len(res[name].Values)) // match tbe bucket counts
		for _, v := range res[name].Values {
			match := re.FindStringSubmatch(v)
			f, _ := strconv.ParseFloat(match[1], 64)
			n, _ := strconv.ParseInt(match[2], 10, 64)
			for i := int64(0); i < n; i++ {
				h.Observe(f)
			}
		}

		p50 = h.Quantile(0.50)
		p90 = h.Quantile(0.90)
		p95 = h.Quantile(0.95)
		p99 = h.Quantile(0.99)
	}))
	defer s.Close()

	m := newCirconusMetrics(s.URL)
	histogram := New(m).NewHistogram(name).With("label values", "not supported")
	quantiles := func() (float64, float64, float64, float64) { m.Flush(); return p50, p90, p95, p99 }

	// Circonus metrics, because they do their own bucketing, are less precise
	// than other systems. So, we bump the tolerance to 5 percent.
	if err := teststat.TestHistogram(histogram, quantiles, 0.05); err != nil {
		t.Fatal(err)
	}
}
Example #4
0
// NewHistogram returns a new usable Histogram metric.
func NewHistogram(name string, buckets int) *Histogram {
	return &Histogram{generic.NewHistogram(name, buckets)}
}