Example #1
0
func TestPrintDistribution(t *testing.T) {
	var (
		quantiles = []int{50, 90, 95, 99}
		h         = expvar.NewHistogram("test_print_distribution", 0, 100, 3, quantiles...)
		seed      = int64(555)
		mean      = int64(5)
		stdev     = int64(1)
	)
	teststat.PopulateNormalHistogram(t, h, seed, mean, stdev)

	var buf bytes.Buffer
	metrics.PrintDistribution(&buf, h)
	t.Logf("\n%s\n", buf.String())

	// Count the number of bar chart characters.
	// We should have ca. 100 in any distribution with a small-enough stdev.

	var n int
	for _, r := range buf.String() {
		if r == '#' {
			n++
		}
	}
	if want, have, tol := 100, n, 5; int(math.Abs(float64(want-have))) > tol {
		t.Errorf("want %d, have %d (tolerance %d)", want, have, tol)
	}
}
Example #2
0
func TestHistogramQuantiles(t *testing.T) {
	metricName := "test_histogram"
	quantiles := []int{50, 90, 95, 99}
	h := expvar.NewHistogram(metricName, 0, 100, 3, quantiles...)

	const seed, mean, stdev int64 = 424242, 50, 10
	teststat.PopulateNormalHistogram(t, h, seed, mean, stdev)
	teststat.AssertExpvarNormalHistogram(t, metricName, mean, stdev, quantiles)
}
Example #3
0
func TestHistogramQuantiles(t *testing.T) {
	var (
		name      = "test_histogram"
		quantiles = []int{50, 90, 95, 99}
		h         = expvar.NewHistogram(name, 0, 100, 3, quantiles...).With(metrics.Field{Key: "ignored", Value: "field"})
	)
	const seed, mean, stdev int64 = 424242, 50, 10
	teststat.PopulateNormalHistogram(t, h, seed, mean, stdev)
	teststat.AssertExpvarNormalHistogram(t, name, mean, stdev, quantiles)
}
Example #4
0
func TestPrometheusSummary(t *testing.T) {
	h := prometheus.NewSummary(stdprometheus.SummaryOpts{
		Namespace: "test",
		Subsystem: "prometheus_summary_histogram",
		Name:      "foobar",
		Help:      "Qwerty asdf.",
	}, []string{})

	const mean, stdev int64 = 50, 10
	teststat.PopulateNormalHistogram(t, h, 34, mean, stdev)
	teststat.AssertPrometheusNormalSummary(t, "test_prometheus_summary_histogram_foobar", mean, stdev)
}
Example #5
0
func TestHistogram(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	defer circonusgometrics.Reset()

	var (
		name       = "test_histogram"
		result     []string
		mtx        sync.Mutex
		onceDecode sync.Once
	)
	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		type postHistogram struct {
			Value []string `json:"_value"`
		}
		onceDecode.Do(func() {
			m := map[string]postHistogram{}
			json.NewDecoder(r.Body).Decode(&m)
			mtx.Lock()
			defer mtx.Unlock()
			result = m[name].Value
		})
	}))
	defer s.Close()

	circonusgometrics.WithSubmissionUrl(s.URL)
	circonusgometrics.WithInterval(submissionInterval)

	h := NewHistogram(name)

	var (
		seed  = int64(123)
		mean  = int64(500)
		stdev = int64(123)
		min   = int64(0)
		max   = 2 * mean
	)
	teststat.PopulateNormalHistogram(t, h, seed, mean, stdev)

	onceStart.Do(func() { circonusgometrics.Start() })

	if err := within(time.Second, func() bool {
		mtx.Lock()
		defer mtx.Unlock()
		return len(result) > 0
	}); err != nil {
		t.Fatalf("error collecting results: %v", err)
	}

	teststat.AssertCirconusNormalHistogram(t, mean, stdev, min, max, result)
}
Example #6
0
func TestPrometheusHistogram(t *testing.T) {
	buckets := []float64{20, 40, 60, 80, 100}
	h := prometheus.NewHistogram(stdprometheus.HistogramOpts{
		Namespace: "test",
		Subsystem: "prometheus_histogram_histogram",
		Name:      "quux",
		Help:      "Qwerty asdf.",
		Buckets:   buckets,
	}, []string{})

	const mean, stdev int64 = 50, 10
	teststat.PopulateNormalHistogram(t, h, 34, mean, stdev)
	teststat.AssertPrometheusBucketedHistogram(t, "test_prometheus_histogram_histogram_quux_bucket", mean, stdev, buckets)
}
Example #7
0
func TestScaledHistogram(t *testing.T) {
	var (
		quantiles  = []int{50, 90, 99}
		scale      = int64(10)
		metricName = "test_scaled_histogram"
	)

	var h metrics.Histogram
	h = expvar.NewHistogram(metricName, 0, 1000, 3, quantiles...)
	h = metrics.NewScaledHistogram(h, scale)
	h = h.With(metrics.Field{Key: "a", Value: "b"})

	const seed, mean, stdev = 333, 500, 100                   // input values
	teststat.PopulateNormalHistogram(t, h, seed, mean, stdev) // will be scaled down
	assertExpvarNormalHistogram(t, metricName, mean/scale, stdev/scale, quantiles)
}
Example #8
0
func TestMultiHistogram(t *testing.T) {
	quantiles := []int{50, 90, 99}
	h := metrics.NewMultiHistogram(
		"multiomicron",
		expvar.NewHistogram("omicron", 0, 100, 3, quantiles...),
		prometheus.NewSummary(stdprometheus.SummaryOpts{
			Namespace: "test",
			Subsystem: "multi_histogram",
			Name:      "nu",
			Help:      "Nu histogram.",
		}, []string{}),
	)

	const seed, mean, stdev int64 = 123, 50, 10
	teststat.PopulateNormalHistogram(t, h, seed, mean, stdev)
	assertExpvarNormalHistogram(t, "omicron", mean, stdev, quantiles)
	assertPrometheusNormalHistogram(t, `test_multi_histogram_nu`, mean, stdev)
}
Example #9
0
func TestHistogramQuantiles(t *testing.T) {
	prefix := "prefix."
	e := NewEmitter("", "", prefix, time.Second, log.NewNopLogger())
	var (
		name      = "test_histogram_quantiles"
		quantiles = []int{50, 90, 95, 99}
	)
	h, err := e.NewHistogram(name, 0, 100, 3, quantiles...)
	if err != nil {
		t.Fatalf("unable to create test histogram: %v", err)
	}
	h = h.With(metrics.Field{Key: "ignored", Value: "field"})
	const seed, mean, stdev int64 = 424242, 50, 10
	teststat.PopulateNormalHistogram(t, h, seed, mean, stdev)

	// flush the current metrics into a buffer to examine
	var b bytes.Buffer
	e.flush(&b)
	teststat.AssertGraphiteNormalHistogram(t, prefix, name, mean, stdev, quantiles, b.String())
}
Example #10
0
func TestHistogram(t *testing.T) {
	// Prometheus reports histograms as a count of observations that fell into
	// each predefined bucket, with the bucket value representing a global upper
	// limit. That is, the count monotonically increases over the buckets. This
	// requires a different strategy to test.

	s := httptest.NewServer(stdprometheus.UninstrumentedHandler())
	defer s.Close()

	scrape := func() string {
		resp, _ := http.Get(s.URL)
		buf, _ := ioutil.ReadAll(resp.Body)
		return string(buf)
	}

	namespace, subsystem, name := "test", "prometheus", "histogram"
	re := regexp.MustCompile(namespace + `_` + subsystem + `_` + name + `_bucket{x="1",le="([0-9]+|\+Inf)"} ([0-9\.]+)`)

	numStdev := 3
	bucketMin := (teststat.Mean - (numStdev * teststat.Stdev))
	bucketMax := (teststat.Mean + (numStdev * teststat.Stdev))
	if bucketMin < 0 {
		bucketMin = 0
	}
	bucketCount := 10
	bucketDelta := (bucketMax - bucketMin) / bucketCount
	buckets := []float64{}
	for i := bucketMin; i <= bucketMax; i += bucketDelta {
		buckets = append(buckets, float64(i))
	}

	histogram := NewHistogramFrom(stdprometheus.HistogramOpts{
		Namespace: namespace,
		Subsystem: subsystem,
		Name:      name,
		Help:      "This is the help string for the histogram.",
		Buckets:   buckets,
	}, []string{"x"}).With("x", "1")

	// Can't TestHistogram, because Prometheus Histograms don't dynamically
	// compute quantiles. Instead, they fill up buckets. So, let's populate the
	// histogram kind of manually.
	teststat.PopulateNormalHistogram(histogram, rand.Int())

	// Then, we use ExpectedObservationsLessThan to validate.
	for _, line := range strings.Split(scrape(), "\n") {
		match := re.FindStringSubmatch(line)
		if match == nil {
			continue
		}

		bucket, _ := strconv.ParseInt(match[1], 10, 64)
		have, _ := strconv.ParseInt(match[2], 10, 64)

		want := teststat.ExpectedObservationsLessThan(bucket)
		if match[1] == "+Inf" {
			want = int64(teststat.Count) // special case
		}

		// Unfortunately, we observe experimentally that Prometheus is quite
		// imprecise at the extremes. I'm setting a very high tolerance for now.
		// It would be great to dig in and figure out whether that's a problem
		// with my Expected calculation, or in Prometheus.
		tolerance := 0.25
		if delta := math.Abs(float64(want) - float64(have)); (delta / float64(want)) > tolerance {
			t.Errorf("Bucket %d: want %d, have %d (%.1f%%)", bucket, want, have, (100.0 * delta / float64(want)))
		}
	}
}