Moved to google.golang.org/genproto/googleapis/api/annotations
Fixes #52
This commit is contained in:
165
vendor/github.com/go-kit/kit/metrics/prometheus/prometheus.go
generated
vendored
Normal file
165
vendor/github.com/go-kit/kit/metrics/prometheus/prometheus.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
// Package prometheus provides Prometheus implementations for metrics.
|
||||
// Individual metrics are mapped to their Prometheus counterparts, and
|
||||
// (depending on the constructor used) may be automatically registered in the
|
||||
// global Prometheus metrics registry.
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/go-kit/kit/metrics/internal/lv"
|
||||
)
|
||||
|
||||
// Counter implements Counter, via a Prometheus CounterVec.
|
||||
type Counter struct {
|
||||
cv *prometheus.CounterVec
|
||||
lvs lv.LabelValues
|
||||
}
|
||||
|
||||
// NewCounterFrom constructs and registers a Prometheus CounterVec,
|
||||
// and returns a usable Counter object.
|
||||
func NewCounterFrom(opts prometheus.CounterOpts, labelNames []string) *Counter {
|
||||
cv := prometheus.NewCounterVec(opts, labelNames)
|
||||
prometheus.MustRegister(cv)
|
||||
return NewCounter(cv)
|
||||
}
|
||||
|
||||
// NewCounter wraps the CounterVec and returns a usable Counter object.
|
||||
func NewCounter(cv *prometheus.CounterVec) *Counter {
|
||||
return &Counter{
|
||||
cv: cv,
|
||||
}
|
||||
}
|
||||
|
||||
// With implements Counter.
|
||||
func (c *Counter) With(labelValues ...string) metrics.Counter {
|
||||
return &Counter{
|
||||
cv: c.cv,
|
||||
lvs: c.lvs.With(labelValues...),
|
||||
}
|
||||
}
|
||||
|
||||
// Add implements Counter.
|
||||
func (c *Counter) Add(delta float64) {
|
||||
c.cv.With(makeLabels(c.lvs...)).Add(delta)
|
||||
}
|
||||
|
||||
// Gauge implements Gauge, via a Prometheus GaugeVec.
|
||||
type Gauge struct {
|
||||
gv *prometheus.GaugeVec
|
||||
lvs lv.LabelValues
|
||||
}
|
||||
|
||||
// NewGaugeFrom construts and registers a Prometheus GaugeVec,
|
||||
// and returns a usable Gauge object.
|
||||
func NewGaugeFrom(opts prometheus.GaugeOpts, labelNames []string) *Gauge {
|
||||
gv := prometheus.NewGaugeVec(opts, labelNames)
|
||||
prometheus.MustRegister(gv)
|
||||
return NewGauge(gv)
|
||||
}
|
||||
|
||||
// NewGauge wraps the GaugeVec and returns a usable Gauge object.
|
||||
func NewGauge(gv *prometheus.GaugeVec) *Gauge {
|
||||
return &Gauge{
|
||||
gv: gv,
|
||||
}
|
||||
}
|
||||
|
||||
// With implements Gauge.
|
||||
func (g *Gauge) With(labelValues ...string) metrics.Gauge {
|
||||
return &Gauge{
|
||||
gv: g.gv,
|
||||
lvs: g.lvs.With(labelValues...),
|
||||
}
|
||||
}
|
||||
|
||||
// Set implements Gauge.
|
||||
func (g *Gauge) Set(value float64) {
|
||||
g.gv.With(makeLabels(g.lvs...)).Set(value)
|
||||
}
|
||||
|
||||
// Add is supported by Prometheus GaugeVecs.
|
||||
func (g *Gauge) Add(delta float64) {
|
||||
g.gv.With(makeLabels(g.lvs...)).Add(delta)
|
||||
}
|
||||
|
||||
// Summary implements Histogram, via a Prometheus SummaryVec. The difference
|
||||
// between a Summary and a Histogram is that Summaries don't require predefined
|
||||
// quantile buckets, but cannot be statistically aggregated.
|
||||
type Summary struct {
|
||||
sv *prometheus.SummaryVec
|
||||
lvs lv.LabelValues
|
||||
}
|
||||
|
||||
// NewSummaryFrom constructs and registers a Prometheus SummaryVec,
|
||||
// and returns a usable Summary object.
|
||||
func NewSummaryFrom(opts prometheus.SummaryOpts, labelNames []string) *Summary {
|
||||
sv := prometheus.NewSummaryVec(opts, labelNames)
|
||||
prometheus.MustRegister(sv)
|
||||
return NewSummary(sv)
|
||||
}
|
||||
|
||||
// NewSummary wraps the SummaryVec and returns a usable Summary object.
|
||||
func NewSummary(sv *prometheus.SummaryVec) *Summary {
|
||||
return &Summary{
|
||||
sv: sv,
|
||||
}
|
||||
}
|
||||
|
||||
// With implements Histogram.
|
||||
func (s *Summary) With(labelValues ...string) metrics.Histogram {
|
||||
return &Summary{
|
||||
sv: s.sv,
|
||||
lvs: s.lvs.With(labelValues...),
|
||||
}
|
||||
}
|
||||
|
||||
// Observe implements Histogram.
|
||||
func (s *Summary) Observe(value float64) {
|
||||
s.sv.With(makeLabels(s.lvs...)).Observe(value)
|
||||
}
|
||||
|
||||
// Histogram implements Histogram via a Prometheus HistogramVec. The difference
|
||||
// between a Histogram and a Summary is that Histograms require predefined
|
||||
// quantile buckets, and can be statistically aggregated.
|
||||
type Histogram struct {
|
||||
hv *prometheus.HistogramVec
|
||||
lvs lv.LabelValues
|
||||
}
|
||||
|
||||
// NewHistogramFrom constructs and registers a Prometheus HistogramVec,
|
||||
// and returns a usable Histogram object.
|
||||
func NewHistogramFrom(opts prometheus.HistogramOpts, labelNames []string) *Histogram {
|
||||
hv := prometheus.NewHistogramVec(opts, labelNames)
|
||||
prometheus.MustRegister(hv)
|
||||
return NewHistogram(hv)
|
||||
}
|
||||
|
||||
// NewHistogram wraps the HistogramVec and returns a usable Histogram object.
|
||||
func NewHistogram(hv *prometheus.HistogramVec) *Histogram {
|
||||
return &Histogram{
|
||||
hv: hv,
|
||||
}
|
||||
}
|
||||
|
||||
// With implements Histogram.
|
||||
func (h *Histogram) With(labelValues ...string) metrics.Histogram {
|
||||
return &Histogram{
|
||||
hv: h.hv,
|
||||
lvs: h.lvs.With(labelValues...),
|
||||
}
|
||||
}
|
||||
|
||||
// Observe implements Histogram.
|
||||
func (h *Histogram) Observe(value float64) {
|
||||
h.hv.With(makeLabels(h.lvs...)).Observe(value)
|
||||
}
|
||||
|
||||
func makeLabels(labelValues ...string) prometheus.Labels {
|
||||
labels := prometheus.Labels{}
|
||||
for i := 0; i < len(labelValues); i += 2 {
|
||||
labels[labelValues[i]] = labelValues[i+1]
|
||||
}
|
||||
return labels
|
||||
}
|
||||
214
vendor/github.com/go-kit/kit/metrics/prometheus/prometheus_test.go
generated
vendored
Normal file
214
vendor/github.com/go-kit/kit/metrics/prometheus/prometheus_test.go
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/go-kit/kit/metrics/teststat"
|
||||
)
|
||||
|
||||
func TestCounter(t *testing.T) {
|
||||
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 := "ns", "ss", "foo"
|
||||
re := regexp.MustCompile(namespace + `_` + subsystem + `_` + name + `{alpha="alpha-value",beta="beta-value"} ([0-9\.]+)`)
|
||||
|
||||
counter := NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: name,
|
||||
Help: "This is the help string.",
|
||||
}, []string{"alpha", "beta"}).With("beta", "beta-value", "alpha", "alpha-value") // order shouldn't matter
|
||||
|
||||
value := func() float64 {
|
||||
matches := re.FindStringSubmatch(scrape())
|
||||
f, _ := strconv.ParseFloat(matches[1], 64)
|
||||
return f
|
||||
}
|
||||
|
||||
if err := teststat.TestCounter(counter, value); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGauge(t *testing.T) {
|
||||
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 := "aaa", "bbb", "ccc"
|
||||
re := regexp.MustCompile(namespace + `_` + subsystem + `_` + name + `{foo="bar"} ([0-9\.]+)`)
|
||||
|
||||
gauge := NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: name,
|
||||
Help: "This is a different help string.",
|
||||
}, []string{"foo"}).With("foo", "bar")
|
||||
|
||||
value := func() float64 {
|
||||
matches := re.FindStringSubmatch(scrape())
|
||||
f, _ := strconv.ParseFloat(matches[1], 64)
|
||||
return f
|
||||
}
|
||||
|
||||
if err := teststat.TestGauge(gauge, value); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSummary(t *testing.T) {
|
||||
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", "summary"
|
||||
re50 := regexp.MustCompile(namespace + `_` + subsystem + `_` + name + `{a="a",b="b",quantile="0.5"} ([0-9\.]+)`)
|
||||
re90 := regexp.MustCompile(namespace + `_` + subsystem + `_` + name + `{a="a",b="b",quantile="0.9"} ([0-9\.]+)`)
|
||||
re99 := regexp.MustCompile(namespace + `_` + subsystem + `_` + name + `{a="a",b="b",quantile="0.99"} ([0-9\.]+)`)
|
||||
|
||||
summary := NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: name,
|
||||
Help: "This is the help string for the summary.",
|
||||
}, []string{"a", "b"}).With("b", "b").With("a", "a")
|
||||
|
||||
quantiles := func() (float64, float64, float64, float64) {
|
||||
buf := scrape()
|
||||
match50 := re50.FindStringSubmatch(buf)
|
||||
p50, _ := strconv.ParseFloat(match50[1], 64)
|
||||
match90 := re90.FindStringSubmatch(buf)
|
||||
p90, _ := strconv.ParseFloat(match90[1], 64)
|
||||
match99 := re99.FindStringSubmatch(buf)
|
||||
p99, _ := strconv.ParseFloat(match99[1], 64)
|
||||
p95 := p90 + ((p99 - p90) / 2) // Prometheus, y u no p95??? :< #yolo
|
||||
return p50, p90, p95, p99
|
||||
}
|
||||
|
||||
if err := teststat.TestHistogram(summary, quantiles, 0.01); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInconsistentLabelCardinality(t *testing.T) {
|
||||
defer func() {
|
||||
x := recover()
|
||||
if x == nil {
|
||||
t.Fatal("expected panic, got none")
|
||||
}
|
||||
err, ok := x.(error)
|
||||
if !ok {
|
||||
t.Fatalf("expected error, got %s", reflect.TypeOf(x))
|
||||
}
|
||||
if want, have := "inconsistent label cardinality", err.Error(); want != have {
|
||||
t.Fatalf("want %q, have %q", want, have)
|
||||
}
|
||||
}()
|
||||
|
||||
NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "test",
|
||||
Subsystem: "inconsistent_label_cardinality",
|
||||
Name: "foobar",
|
||||
Help: "This is the help string for the metric.",
|
||||
}, []string{"a", "b"}).With(
|
||||
"a", "1", "b", "2", "c", "KABOOM!",
|
||||
).Add(123)
|
||||
}
|
||||
Reference in New Issue
Block a user