Этот коммит содержится в:
Christopher Speller
2017-08-17 17:19:06 -07:00
коммит произвёл GitHub
родитель 2c895ee66e
Коммит 96eab12027
400 изменённых файлов: 45331 добавлений и 11832 удалений

27
vendor/github.com/armon/go-metrics/circonus/circonus.go сгенерированный поставляемый
Просмотреть файл

@@ -5,6 +5,7 @@ package circonus
import (
"strings"
"github.com/armon/go-metrics"
cgm "github.com/circonus-labs/circonus-gometrics"
)
@@ -61,6 +62,12 @@ func (s *CirconusSink) SetGauge(key []string, val float32) {
s.metrics.SetGauge(flatKey, int64(val))
}
// SetGaugeWithLabels sets value for a gauge metric with the given labels
func (s *CirconusSink) SetGaugeWithLabels(key []string, val float32, labels []metrics.Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.metrics.SetGauge(flatKey, int64(val))
}
// EmitKey is not implemented in circonus
func (s *CirconusSink) EmitKey(key []string, val float32) {
// NOP
@@ -72,12 +79,24 @@ func (s *CirconusSink) IncrCounter(key []string, val float32) {
s.metrics.IncrementByValue(flatKey, uint64(val))
}
// IncrCounterWithLabels increments a counter metric with the given labels
func (s *CirconusSink) IncrCounterWithLabels(key []string, val float32, labels []metrics.Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.metrics.IncrementByValue(flatKey, uint64(val))
}
// AddSample adds a sample to a histogram metric
func (s *CirconusSink) AddSample(key []string, val float32) {
flatKey := s.flattenKey(key)
s.metrics.RecordValue(flatKey, float64(val))
}
// AddSampleWithLabels adds a sample to a histogram metric with the given labels
func (s *CirconusSink) AddSampleWithLabels(key []string, val float32, labels []metrics.Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.metrics.RecordValue(flatKey, float64(val))
}
// Flattens key to Circonus metric name
func (s *CirconusSink) flattenKey(parts []string) string {
joined := strings.Join(parts, "`")
@@ -90,3 +109,11 @@ func (s *CirconusSink) flattenKey(parts []string) string {
}
}, joined)
}
// Flattens the key along with labels for formatting, removes spaces
func (s *CirconusSink) flattenKeyLabels(parts []string, labels []metrics.Label) string {
for _, label := range labels {
parts = append(parts, label.Value)
}
return s.flattenKey(parts)
}

4
vendor/github.com/armon/go-metrics/circonus/circonus_test.go сгенерированный поставляемый
Просмотреть файл

@@ -12,7 +12,7 @@ import (
func TestNewCirconusSink(t *testing.T) {
// test with invalid config (nil)
expectedError := errors.New("Invalid check manager configuration (no API token AND no submission url).")
expectedError := errors.New("invalid check manager configuration (no API token AND no submission url)")
_, err := NewCirconusSink(nil)
if err == nil || err.Error() != expectedError.Error() {
t.Errorf("Expected an '%#v' error, got '%#v'", expectedError, err)
@@ -87,7 +87,7 @@ func TestSetGauge(t *testing.T) {
cs.Flush()
}()
expect := "{\"foo`bar\":{\"_type\":\"n\",\"_value\":1}}"
expect := "{\"foo`bar\":{\"_type\":\"n\",\"_value\":\"1\"}}"
actual := <-q
if actual != expect {

73
vendor/github.com/armon/go-metrics/datadog/dogstatsd.go сгенерированный поставляемый
Просмотреть файл

@@ -5,6 +5,7 @@ import (
"strings"
"github.com/DataDog/datadog-go/statsd"
"github.com/armon/go-metrics"
)
// DogStatsdSink provides a MetricSink that can be used
@@ -45,46 +46,49 @@ func (s *DogStatsdSink) EnableHostNamePropagation() {
func (s *DogStatsdSink) flattenKey(parts []string) string {
joined := strings.Join(parts, ".")
return strings.Map(func(r rune) rune {
switch r {
case ':':
fallthrough
case ' ':
return '_'
default:
return r
}
}, joined)
return strings.Map(sanitize, joined)
}
func (s *DogStatsdSink) parseKey(key []string) ([]string, []string) {
func sanitize(r rune) rune {
switch r {
case ':':
fallthrough
case ' ':
return '_'
default:
return r
}
}
func (s *DogStatsdSink) parseKey(key []string) ([]string, []metrics.Label) {
// Since DogStatsd supports dimensionality via tags on metric keys, this sink's approach is to splice the hostname out of the key in favor of a `host` tag
// The `host` tag is either forced here, or set downstream by the DogStatsd server
var tags []string
var labels []metrics.Label
hostName := s.hostName
//Splice the hostname out of the key
// Splice the hostname out of the key
for i, el := range key {
if el == hostName {
key = append(key[:i], key[i+1:]...)
break
}
}
if s.propagateHostname {
tags = append(tags, fmt.Sprintf("host:%s", hostName))
labels = append(labels, metrics.Label{"host", hostName})
}
return key, tags
return key, labels
}
// Implementation of methods in the MetricSink interface
func (s *DogStatsdSink) SetGauge(key []string, val float32) {
s.SetGaugeWithTags(key, val, []string{})
s.SetGaugeWithLabels(key, val, nil)
}
func (s *DogStatsdSink) IncrCounter(key []string, val float32) {
s.IncrCounterWithTags(key, val, []string{})
s.IncrCounterWithLabels(key, val, nil)
}
// EmitKey is not implemented since DogStatsd does not provide a metric type that holds an
@@ -93,33 +97,44 @@ func (s *DogStatsdSink) EmitKey(key []string, val float32) {
}
func (s *DogStatsdSink) AddSample(key []string, val float32) {
s.AddSampleWithTags(key, val, []string{})
s.AddSampleWithLabels(key, val, nil)
}
// The following ...WithTags methods correspond to Datadog's Tag extension to Statsd.
// The following ...WithLabels methods correspond to Datadog's Tag extension to Statsd.
// http://docs.datadoghq.com/guides/dogstatsd/#tags
func (s *DogStatsdSink) SetGaugeWithTags(key []string, val float32, tags []string) {
flatKey, tags := s.getFlatkeyAndCombinedTags(key, tags)
func (s *DogStatsdSink) SetGaugeWithLabels(key []string, val float32, labels []metrics.Label) {
flatKey, tags := s.getFlatkeyAndCombinedLabels(key, labels)
rate := 1.0
s.client.Gauge(flatKey, float64(val), tags, rate)
}
func (s *DogStatsdSink) IncrCounterWithTags(key []string, val float32, tags []string) {
flatKey, tags := s.getFlatkeyAndCombinedTags(key, tags)
func (s *DogStatsdSink) IncrCounterWithLabels(key []string, val float32, labels []metrics.Label) {
flatKey, tags := s.getFlatkeyAndCombinedLabels(key, labels)
rate := 1.0
s.client.Count(flatKey, int64(val), tags, rate)
}
func (s *DogStatsdSink) AddSampleWithTags(key []string, val float32, tags []string) {
flatKey, tags := s.getFlatkeyAndCombinedTags(key, tags)
func (s *DogStatsdSink) AddSampleWithLabels(key []string, val float32, labels []metrics.Label) {
flatKey, tags := s.getFlatkeyAndCombinedLabels(key, labels)
rate := 1.0
s.client.TimeInMilliseconds(flatKey, float64(val), tags, rate)
}
func (s *DogStatsdSink) getFlatkeyAndCombinedTags(key []string, tags []string) (flattenedKey string, combinedTags []string) {
key, hostTags := s.parseKey(key)
func (s *DogStatsdSink) getFlatkeyAndCombinedLabels(key []string, labels []metrics.Label) (string, []string) {
key, parsedLabels := s.parseKey(key)
flatKey := s.flattenKey(key)
tags = append(tags, hostTags...)
labels = append(labels, parsedLabels...)
var tags []string
for _, label := range labels {
label.Name = strings.Map(sanitize, label.Name)
label.Value = strings.Map(sanitize, label.Value)
if label.Value != "" {
tags = append(tags, fmt.Sprintf("%s:%s", label.Name, label.Value))
} else {
tags = append(tags, label.Name)
}
}
return flatKey, tags
}

35
vendor/github.com/armon/go-metrics/datadog/dogstatsd_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,13 +1,14 @@
package datadog
import (
"fmt"
"net"
"reflect"
"testing"
"github.com/armon/go-metrics"
)
var EmptyTags []string
var EmptyTags []metrics.Label
const (
DogStatsdAddr = "127.0.0.1:7254"
@@ -22,14 +23,14 @@ func MockGetHostname() string {
var ParseKeyTests = []struct {
KeyToParse []string
Tags []string
Tags []metrics.Label
PropagateHostname bool
ExpectedKey []string
ExpectedTags []string
ExpectedTags []metrics.Label
}{
{[]string{"a", MockGetHostname(), "b", "c"}, EmptyTags, HostnameDisabled, []string{"a", "b", "c"}, EmptyTags},
{[]string{"a", "b", "c"}, EmptyTags, HostnameDisabled, []string{"a", "b", "c"}, EmptyTags},
{[]string{"a", "b", "c"}, EmptyTags, HostnameEnabled, []string{"a", "b", "c"}, []string{fmt.Sprintf("host:%s", MockGetHostname())}},
{[]string{"a", "b", "c"}, EmptyTags, HostnameEnabled, []string{"a", "b", "c"}, []metrics.Label{{"host", MockGetHostname()}}},
}
var FlattenKeyTests = []struct {
@@ -44,7 +45,7 @@ var MetricSinkTests = []struct {
Method string
Metric []string
Value interface{}
Tags []string
Tags []metrics.Label
PropagateHostname bool
Expected string
}{
@@ -53,13 +54,15 @@ var MetricSinkTests = []struct {
{"AddSample", []string{"sample", "thing"}, float32(4), EmptyTags, HostnameDisabled, "sample.thing:4.000000|ms"},
{"IncrCounter", []string{"count", "me"}, float32(3), EmptyTags, HostnameDisabled, "count.me:3|c"},
{"SetGauge", []string{"foo", "baz"}, float32(42), []string{"my_tag:my_value"}, HostnameDisabled, "foo.baz:42.000000|g|#my_tag:my_value"},
{"SetGauge", []string{"foo", "bar"}, float32(42), []string{"my_tag:my_value", "other_tag:other_value"}, HostnameDisabled, "foo.bar:42.000000|g|#my_tag:my_value,other_tag:other_value"},
{"SetGauge", []string{"foo", "bar"}, float32(42), []string{"my_tag:my_value", "other_tag:other_value"}, HostnameEnabled, "foo.bar:42.000000|g|#my_tag:my_value,other_tag:other_value,host:test_hostname"},
{"SetGauge", []string{"foo", "baz"}, float32(42), []metrics.Label{{"my_tag", ""}}, HostnameDisabled, "foo.baz:42.000000|g|#my_tag"},
{"SetGauge", []string{"foo", "baz"}, float32(42), []metrics.Label{{"my tag", "my_value"}}, HostnameDisabled, "foo.baz:42.000000|g|#my_tag:my_value"},
{"SetGauge", []string{"foo", "bar"}, float32(42), []metrics.Label{{"my_tag", "my_value"}, {"other_tag", "other_value"}}, HostnameDisabled, "foo.bar:42.000000|g|#my_tag:my_value,other_tag:other_value"},
{"SetGauge", []string{"foo", "bar"}, float32(42), []metrics.Label{{"my_tag", "my_value"}, {"other_tag", "other_value"}}, HostnameEnabled, "foo.bar:42.000000|g|#my_tag:my_value,other_tag:other_value,host:test_hostname"},
}
func mockNewDogStatsdSink(addr string, tags []string, tagWithHostname bool) *DogStatsdSink {
func mockNewDogStatsdSink(addr string, labels []metrics.Label, tagWithHostname bool) *DogStatsdSink {
dog, _ := NewDogStatsdSink(addr, MockGetHostname())
_, tags := dog.getFlatkeyAndCombinedLabels(nil, labels)
dog.SetTags(tags)
if tagWithHostname {
dog.EnableHostNamePropagation()
@@ -90,7 +93,7 @@ func TestParseKey(t *testing.T) {
}
if !reflect.DeepEqual(tags, tt.ExpectedTags) {
t.Fatalf("Tag Parsing Failed for %v", tt.KeyToParse)
t.Fatalf("Tag Parsing Failed for %v, %v != %v", tt.KeyToParse, tags, tt.ExpectedTags)
}
}
}
@@ -124,17 +127,17 @@ func TestTaggableMetrics(t *testing.T) {
dog := mockNewDogStatsdSink(DogStatsdAddr, EmptyTags, HostnameDisabled)
dog.AddSampleWithTags([]string{"sample", "thing"}, float32(4), []string{"tagkey:tagvalue"})
dog.AddSampleWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
assertServerMatchesExpected(t, server, buf, "sample.thing:4.000000|ms|#tagkey:tagvalue")
dog.SetGaugeWithTags([]string{"sample", "thing"}, float32(4), []string{"tagkey:tagvalue"})
dog.SetGaugeWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
assertServerMatchesExpected(t, server, buf, "sample.thing:4.000000|g|#tagkey:tagvalue")
dog.IncrCounterWithTags([]string{"sample", "thing"}, float32(4), []string{"tagkey:tagvalue"})
dog.IncrCounterWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
assertServerMatchesExpected(t, server, buf, "sample.thing:4|c|#tagkey:tagvalue")
dog = mockNewDogStatsdSink(DogStatsdAddr, []string{"global"}, HostnameEnabled) // with hostname, global tags
dog.IncrCounterWithTags([]string{"sample", "thing"}, float32(4), []string{"tagkey:tagvalue"})
dog = mockNewDogStatsdSink(DogStatsdAddr, []metrics.Label{{Name: "global"}}, HostnameEnabled) // with hostname, global tags
dog.IncrCounterWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
assertServerMatchesExpected(t, server, buf, "sample.thing:4|c|#global,tagkey:tagvalue,host:test_hostname")
}

95
vendor/github.com/armon/go-metrics/inmem.go сгенерированный поставляемый
Просмотреть файл

@@ -1,6 +1,7 @@
package metrics
import (
"bytes"
"fmt"
"math"
"net/url"
@@ -39,7 +40,7 @@ type IntervalMetrics struct {
Interval time.Time
// Gauges maps the key to the last set value
Gauges map[string]float32
Gauges map[string]GaugeValue
// Points maps the string to the list of emitted values
// from EmitKey
@@ -47,21 +48,21 @@ type IntervalMetrics struct {
// Counters maps the string key to a sum of the counter
// values
Counters map[string]*AggregateSample
Counters map[string]SampledValue
// Samples maps the key to an AggregateSample,
// which has the rolled up view of a sample
Samples map[string]*AggregateSample
Samples map[string]SampledValue
}
// NewIntervalMetrics creates a new IntervalMetrics for a given interval
func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
return &IntervalMetrics{
Interval: intv,
Gauges: make(map[string]float32),
Gauges: make(map[string]GaugeValue),
Points: make(map[string][]float32),
Counters: make(map[string]*AggregateSample),
Samples: make(map[string]*AggregateSample),
Counters: make(map[string]SampledValue),
Samples: make(map[string]SampledValue),
}
}
@@ -69,12 +70,12 @@ func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
// about a sample
type AggregateSample struct {
Count int // The count of emitted pairs
Rate float64 // The count of emitted pairs per time unit (usually 1 second)
Rate float64 `json:"-"` // The count of emitted pairs per time unit (usually 1 second)
Sum float64 // The sum of values
SumSq float64 // The sum of squared values
SumSq float64 `json:"-"` // The sum of squared values
Min float64 // Minimum value
Max float64 // Maximum value
LastUpdated time.Time // When value was last updated
LastUpdated time.Time `json:"-"` // When value was last updated
}
// Computes a Stddev of the values
@@ -154,12 +155,16 @@ func NewInmemSink(interval, retain time.Duration) *InmemSink {
}
func (i *InmemSink) SetGauge(key []string, val float32) {
k := i.flattenKey(key)
i.SetGaugeWithLabels(key, val, nil)
}
func (i *InmemSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
k, name := i.flattenKeyLabels(key, labels)
intv := i.getInterval()
intv.Lock()
defer intv.Unlock()
intv.Gauges[k] = val
intv.Gauges[k] = GaugeValue{Name: name, Value: val, Labels: labels}
}
func (i *InmemSink) EmitKey(key []string, val float32) {
@@ -173,30 +178,46 @@ func (i *InmemSink) EmitKey(key []string, val float32) {
}
func (i *InmemSink) IncrCounter(key []string, val float32) {
k := i.flattenKey(key)
i.IncrCounterWithLabels(key, val, nil)
}
func (i *InmemSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
k, name := i.flattenKeyLabels(key, labels)
intv := i.getInterval()
intv.Lock()
defer intv.Unlock()
agg := intv.Counters[k]
if agg == nil {
agg = &AggregateSample{}
agg, ok := intv.Counters[k]
if !ok {
agg = SampledValue{
Name: name,
AggregateSample: &AggregateSample{},
Labels: labels,
}
intv.Counters[k] = agg
}
agg.Ingest(float64(val), i.rateDenom)
}
func (i *InmemSink) AddSample(key []string, val float32) {
k := i.flattenKey(key)
i.AddSampleWithLabels(key, val, nil)
}
func (i *InmemSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
k, name := i.flattenKeyLabels(key, labels)
intv := i.getInterval()
intv.Lock()
defer intv.Unlock()
agg := intv.Samples[k]
if agg == nil {
agg = &AggregateSample{}
agg, ok := intv.Samples[k]
if !ok {
agg = SampledValue{
Name: name,
AggregateSample: &AggregateSample{},
Labels: labels,
}
intv.Samples[k] = agg
}
agg.Ingest(float64(val), i.rateDenom)
@@ -261,6 +282,38 @@ func (i *InmemSink) getInterval() *IntervalMetrics {
// Flattens the key for formatting, removes spaces
func (i *InmemSink) flattenKey(parts []string) string {
joined := strings.Join(parts, ".")
return strings.Replace(joined, " ", "_", -1)
buf := &bytes.Buffer{}
replacer := strings.NewReplacer(" ", "_")
if len(parts) > 0 {
replacer.WriteString(buf, parts[0])
}
for _, part := range parts[1:] {
replacer.WriteString(buf, ".")
replacer.WriteString(buf, part)
}
return buf.String()
}
// Flattens the key for formatting along with its labels, removes spaces
func (i *InmemSink) flattenKeyLabels(parts []string, labels []Label) (string, string) {
buf := &bytes.Buffer{}
replacer := strings.NewReplacer(" ", "_")
if len(parts) > 0 {
replacer.WriteString(buf, parts[0])
}
for _, part := range parts[1:] {
replacer.WriteString(buf, ".")
replacer.WriteString(buf, part)
}
key := buf.String()
for _, label := range labels {
replacer.WriteString(buf, fmt.Sprintf(";%s=%s", label.Name, label.Value))
}
return buf.String(), key
}

118
vendor/github.com/armon/go-metrics/inmem_endpoint.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,118 @@
package metrics
import (
"fmt"
"net/http"
"sort"
"time"
)
// MetricsSummary holds a roll-up of metrics info for a given interval
type MetricsSummary struct {
Timestamp string
Gauges []GaugeValue
Points []PointValue
Counters []SampledValue
Samples []SampledValue
}
type GaugeValue struct {
Name string
Hash string `json:"-"`
Value float32
Labels []Label `json:"-"`
DisplayLabels map[string]string `json:"Labels"`
}
type PointValue struct {
Name string
Points []float32
}
type SampledValue struct {
Name string
Hash string `json:"-"`
*AggregateSample
Mean float64
Stddev float64
Labels []Label `json:"-"`
DisplayLabels map[string]string `json:"Labels"`
}
// DisplayMetrics returns a summary of the metrics from the most recent finished interval.
func (i *InmemSink) DisplayMetrics(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
data := i.Data()
var interval *IntervalMetrics
n := len(data)
switch {
case n == 0:
return nil, fmt.Errorf("no metric intervals have been initialized yet")
case n == 1:
// Show the current interval if it's all we have
interval = i.intervals[0]
default:
// Show the most recent finished interval if we have one
interval = i.intervals[n-2]
}
summary := MetricsSummary{
Timestamp: interval.Interval.Round(time.Second).UTC().String(),
Gauges: make([]GaugeValue, 0, len(interval.Gauges)),
Points: make([]PointValue, 0, len(interval.Points)),
}
// Format and sort the output of each metric type, so it gets displayed in a
// deterministic order.
for name, points := range interval.Points {
summary.Points = append(summary.Points, PointValue{name, points})
}
sort.Slice(summary.Points, func(i, j int) bool {
return summary.Points[i].Name < summary.Points[j].Name
})
for hash, value := range interval.Gauges {
value.Hash = hash
value.DisplayLabels = make(map[string]string)
for _, label := range value.Labels {
value.DisplayLabels[label.Name] = label.Value
}
value.Labels = nil
summary.Gauges = append(summary.Gauges, value)
}
sort.Slice(summary.Gauges, func(i, j int) bool {
return summary.Gauges[i].Hash < summary.Gauges[j].Hash
})
summary.Counters = formatSamples(interval.Counters)
summary.Samples = formatSamples(interval.Samples)
return summary, nil
}
func formatSamples(source map[string]SampledValue) []SampledValue {
output := make([]SampledValue, 0, len(source))
for hash, sample := range source {
displayLabels := make(map[string]string)
for _, label := range sample.Labels {
displayLabels[label.Name] = label.Value
}
output = append(output, SampledValue{
Name: sample.Name,
Hash: hash,
AggregateSample: sample.AggregateSample,
Mean: sample.AggregateSample.Mean(),
Stddev: sample.AggregateSample.Stddev(),
DisplayLabels: displayLabels,
})
}
sort.Slice(output, func(i, j int) bool {
return output[i].Hash < output[j].Hash
})
return output
}

133
vendor/github.com/armon/go-metrics/inmem_endpoint_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,133 @@
package metrics
import (
"testing"
"time"
"github.com/pascaldekloe/goe/verify"
)
func TestDisplayMetrics(t *testing.T) {
interval := 10 * time.Millisecond
inm := NewInmemSink(interval, 50*time.Millisecond)
// Add data points
inm.SetGauge([]string{"foo", "bar"}, 42)
inm.SetGaugeWithLabels([]string{"foo", "bar"}, 23, []Label{{"a", "b"}})
inm.EmitKey([]string{"foo", "bar"}, 42)
inm.IncrCounter([]string{"foo", "bar"}, 20)
inm.IncrCounter([]string{"foo", "bar"}, 22)
inm.IncrCounterWithLabels([]string{"foo", "bar"}, 20, []Label{{"a", "b"}})
inm.IncrCounterWithLabels([]string{"foo", "bar"}, 40, []Label{{"a", "b"}})
inm.AddSample([]string{"foo", "bar"}, 20)
inm.AddSample([]string{"foo", "bar"}, 24)
inm.AddSampleWithLabels([]string{"foo", "bar"}, 23, []Label{{"a", "b"}})
inm.AddSampleWithLabels([]string{"foo", "bar"}, 33, []Label{{"a", "b"}})
data := inm.Data()
if len(data) != 1 {
t.Fatalf("bad: %v", data)
}
expected := MetricsSummary{
Timestamp: data[0].Interval.Round(time.Second).UTC().String(),
Gauges: []GaugeValue{
{
Name: "foo.bar",
Hash: "foo.bar",
Value: float32(42),
DisplayLabels: map[string]string{},
},
{
Name: "foo.bar",
Hash: "foo.bar;a=b",
Value: float32(23),
DisplayLabels: map[string]string{"a": "b"},
},
},
Points: []PointValue{
{
Name: "foo.bar",
Points: []float32{42},
},
},
Counters: []SampledValue{
{
Name: "foo.bar",
Hash: "foo.bar",
AggregateSample: &AggregateSample{
Count: 2,
Min: 20,
Max: 22,
Sum: 42,
SumSq: 884,
Rate: 200,
},
Mean: 21,
Stddev: 1.4142135623730951,
},
{
Name: "foo.bar",
Hash: "foo.bar;a=b",
AggregateSample: &AggregateSample{
Count: 2,
Min: 20,
Max: 40,
Sum: 60,
SumSq: 2000,
Rate: 200,
},
Mean: 30,
Stddev: 14.142135623730951,
DisplayLabels: map[string]string{"a": "b"},
},
},
Samples: []SampledValue{
{
Name: "foo.bar",
Hash: "foo.bar",
AggregateSample: &AggregateSample{
Count: 2,
Min: 20,
Max: 24,
Sum: 44,
SumSq: 976,
Rate: 200,
},
Mean: 22,
Stddev: 2.8284271247461903,
},
{
Name: "foo.bar",
Hash: "foo.bar;a=b",
AggregateSample: &AggregateSample{
Count: 2,
Min: 23,
Max: 33,
Sum: 56,
SumSq: 1618,
Rate: 200,
},
Mean: 28,
Stddev: 7.0710678118654755,
DisplayLabels: map[string]string{"a": "b"},
},
},
}
raw, err := inm.DisplayMetrics(nil, nil)
if err != nil {
t.Fatalf("err: %v", err)
}
result := raw.(MetricsSummary)
// Ignore the LastUpdated field, we don't export that anyway
for i, got := range result.Counters {
expected.Counters[i].LastUpdated = got.LastUpdated
}
for i, got := range result.Samples {
expected.Samples[i].LastUpdated = got.LastUpdated
}
verify.Values(t, "all", result, expected)
}

33
vendor/github.com/armon/go-metrics/inmem_signal.go сгенерированный поставляемый
Просмотреть файл

@@ -6,6 +6,7 @@ import (
"io"
"os"
"os/signal"
"strings"
"sync"
"syscall"
)
@@ -75,22 +76,25 @@ func (i *InmemSignal) dumpStats() {
data := i.inm.Data()
// Skip the last period which is still being aggregated
for i := 0; i < len(data)-1; i++ {
intv := data[i]
for j := 0; j < len(data)-1; j++ {
intv := data[j]
intv.RLock()
for name, val := range intv.Gauges {
fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val)
for _, val := range intv.Gauges {
name := i.flattenLabels(val.Name, val.Labels)
fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val.Value)
}
for name, vals := range intv.Points {
for _, val := range vals {
fmt.Fprintf(buf, "[%v][P] '%s': %0.3f\n", intv.Interval, name, val)
}
}
for name, agg := range intv.Counters {
fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg)
for _, agg := range intv.Counters {
name := i.flattenLabels(agg.Name, agg.Labels)
fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg.AggregateSample)
}
for name, agg := range intv.Samples {
fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg)
for _, agg := range intv.Samples {
name := i.flattenLabels(agg.Name, agg.Labels)
fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg.AggregateSample)
}
intv.RUnlock()
}
@@ -98,3 +102,16 @@ func (i *InmemSignal) dumpStats() {
// Write out the bytes
i.w.Write(buf.Bytes())
}
// Flattens the key for formatting along with its labels, removes spaces
func (i *InmemSignal) flattenLabels(name string, labels []Label) string {
buf := bytes.NewBufferString(name)
replacer := strings.NewReplacer(" ", "_", ":", "_")
for _, label := range labels {
replacer.WriteString(buf, ".")
replacer.WriteString(buf, label.Value)
}
return buf.String()
}

12
vendor/github.com/armon/go-metrics/inmem_signal_test.go сгенерированный поставляемый
Просмотреть файл

@@ -19,6 +19,9 @@ func TestInmemSignal(t *testing.T) {
inm.EmitKey([]string{"bar"}, 42)
inm.IncrCounter([]string{"baz"}, 42)
inm.AddSample([]string{"wow"}, 42)
inm.SetGaugeWithLabels([]string{"asdf"}, 42, []Label{{"a", "b"}})
inm.IncrCounterWithLabels([]string{"qwer"}, 42, []Label{{"a", "b"}})
inm.AddSampleWithLabels([]string{"zxcv"}, 42, []Label{{"a", "b"}})
// Wait for period to end
time.Sleep(15 * time.Millisecond)
@@ -43,4 +46,13 @@ func TestInmemSignal(t *testing.T) {
if !strings.Contains(out, "[S] 'wow': Count: 1 Sum: 42") {
t.Fatalf("bad: %v", out)
}
if !strings.Contains(out, "[G] 'asdf.b': 42") {
t.Fatalf("bad: %v", out)
}
if !strings.Contains(out, "[C] 'qwer.b': Count: 1 Sum: 42") {
t.Fatalf("bad: %v", out)
}
if !strings.Contains(out, "[S] 'zxcv.b': Count: 1 Sum: 42") {
t.Fatalf("bad: %v", out)
}
}

78
vendor/github.com/armon/go-metrics/inmem_test.go сгенерированный поставляемый
Просмотреть файл

@@ -18,11 +18,15 @@ func TestInmemSink(t *testing.T) {
// Add data points
inm.SetGauge([]string{"foo", "bar"}, 42)
inm.SetGaugeWithLabels([]string{"foo", "bar"}, 23, []Label{{"a", "b"}})
inm.EmitKey([]string{"foo", "bar"}, 42)
inm.IncrCounter([]string{"foo", "bar"}, 20)
inm.IncrCounter([]string{"foo", "bar"}, 22)
inm.IncrCounterWithLabels([]string{"foo", "bar"}, 20, []Label{{"a", "b"}})
inm.IncrCounterWithLabels([]string{"foo", "bar"}, 22, []Label{{"a", "b"}})
inm.AddSample([]string{"foo", "bar"}, 20)
inm.AddSample([]string{"foo", "bar"}, 22)
inm.AddSampleWithLabels([]string{"foo", "bar"}, 23, []Label{{"a", "b"}})
data = inm.Data()
if len(data) != 1 {
@@ -35,49 +39,57 @@ func TestInmemSink(t *testing.T) {
if time.Now().Sub(intvM.Interval) > 10*time.Millisecond {
t.Fatalf("interval too old")
}
if intvM.Gauges["foo.bar"] != 42 {
if intvM.Gauges["foo.bar"].Value != 42 {
t.Fatalf("bad val: %v", intvM.Gauges)
}
if intvM.Gauges["foo.bar;a=b"].Value != 23 {
t.Fatalf("bad val: %v", intvM.Gauges)
}
if intvM.Points["foo.bar"][0] != 42 {
t.Fatalf("bad val: %v", intvM.Points)
}
agg := intvM.Counters["foo.bar"]
if agg.Count != 2 {
t.Fatalf("bad val: %v", agg)
}
if agg.Rate != 200 {
t.Fatalf("bad val: %v", agg.Rate)
}
if agg.Sum != 42 {
t.Fatalf("bad val: %v", agg)
}
if agg.SumSq != 884 {
t.Fatalf("bad val: %v", agg)
}
if agg.Min != 20 {
t.Fatalf("bad val: %v", agg)
}
if agg.Max != 22 {
t.Fatalf("bad val: %v", agg)
}
if agg.Mean() != 21 {
t.Fatalf("bad val: %v", agg)
}
if agg.Stddev() != math.Sqrt(2) {
t.Fatalf("bad val: %v", agg)
for _, agg := range []SampledValue{intvM.Counters["foo.bar"], intvM.Counters["foo.bar;a=b"]} {
if agg.Count != 2 {
t.Fatalf("bad val: %v", agg)
}
if agg.Rate != 200 {
t.Fatalf("bad val: %v", agg.Rate)
}
if agg.Sum != 42 {
t.Fatalf("bad val: %v", agg)
}
if agg.SumSq != 884 {
t.Fatalf("bad val: %v", agg)
}
if agg.Min != 20 {
t.Fatalf("bad val: %v", agg)
}
if agg.Max != 22 {
t.Fatalf("bad val: %v", agg)
}
if agg.AggregateSample.Mean() != 21 {
t.Fatalf("bad val: %v", agg)
}
if agg.AggregateSample.Stddev() != math.Sqrt(2) {
t.Fatalf("bad val: %v", agg)
}
if agg.LastUpdated.IsZero() {
t.Fatalf("agg.LastUpdated is not set: %v", agg)
}
diff := time.Now().Sub(agg.LastUpdated).Seconds()
if diff > 1 {
t.Fatalf("time diff too great: %f", diff)
}
}
if agg.LastUpdated.IsZero() {
t.Fatalf("agg.LastUpdated is not set: %v", agg)
if _, ok := intvM.Samples["foo.bar"]; !ok {
t.Fatalf("missing sample")
}
diff := time.Now().Sub(agg.LastUpdated).Seconds()
if diff > 1 {
t.Fatalf("time diff too great: %f", diff)
}
if agg = intvM.Samples["foo.bar"]; agg == nil {
if _, ok := intvM.Samples["foo.bar;a=b"]; !ok {
t.Fatalf("missing sample")
}

121
vendor/github.com/armon/go-metrics/metrics.go сгенерированный поставляемый
Просмотреть файл

@@ -2,20 +2,43 @@ package metrics
import (
"runtime"
"strings"
"time"
"github.com/hashicorp/go-immutable-radix"
)
type Label struct {
Name string
Value string
}
func (m *Metrics) SetGauge(key []string, val float32) {
if m.HostName != "" && m.EnableHostname {
key = insert(0, m.HostName, key)
m.SetGaugeWithLabels(key, val, nil)
}
func (m *Metrics) SetGaugeWithLabels(key []string, val float32, labels []Label) {
if m.HostName != "" {
if m.EnableHostnameLabel {
labels = append(labels, Label{"host", m.HostName})
} else if m.EnableHostname {
key = insert(0, m.HostName, key)
}
}
if m.EnableTypePrefix {
key = insert(0, "gauge", key)
}
if m.ServiceName != "" {
key = insert(0, m.ServiceName, key)
if m.EnableServiceLabel {
labels = append(labels, Label{"service", m.ServiceName})
} else {
key = insert(0, m.ServiceName, key)
}
}
m.sink.SetGauge(key, val)
if !m.allowMetric(key) {
return
}
m.sink.SetGaugeWithLabels(key, val, labels)
}
func (m *Metrics) EmitKey(key []string, val float32) {
@@ -25,40 +48,118 @@ func (m *Metrics) EmitKey(key []string, val float32) {
if m.ServiceName != "" {
key = insert(0, m.ServiceName, key)
}
if !m.allowMetric(key) {
return
}
m.sink.EmitKey(key, val)
}
func (m *Metrics) IncrCounter(key []string, val float32) {
m.IncrCounterWithLabels(key, val, nil)
}
func (m *Metrics) IncrCounterWithLabels(key []string, val float32, labels []Label) {
if m.HostName != "" && m.EnableHostnameLabel {
labels = append(labels, Label{"host", m.HostName})
}
if m.EnableTypePrefix {
key = insert(0, "counter", key)
}
if m.ServiceName != "" {
key = insert(0, m.ServiceName, key)
if m.EnableServiceLabel {
labels = append(labels, Label{"service", m.ServiceName})
} else {
key = insert(0, m.ServiceName, key)
}
}
m.sink.IncrCounter(key, val)
if !m.allowMetric(key) {
return
}
m.sink.IncrCounterWithLabels(key, val, labels)
}
func (m *Metrics) AddSample(key []string, val float32) {
m.AddSampleWithLabels(key, val, nil)
}
func (m *Metrics) AddSampleWithLabels(key []string, val float32, labels []Label) {
if m.HostName != "" && m.EnableHostnameLabel {
labels = append(labels, Label{"host", m.HostName})
}
if m.EnableTypePrefix {
key = insert(0, "sample", key)
}
if m.ServiceName != "" {
key = insert(0, m.ServiceName, key)
if m.EnableServiceLabel {
labels = append(labels, Label{"service", m.ServiceName})
} else {
key = insert(0, m.ServiceName, key)
}
}
m.sink.AddSample(key, val)
if !m.allowMetric(key) {
return
}
m.sink.AddSampleWithLabels(key, val, labels)
}
func (m *Metrics) MeasureSince(key []string, start time.Time) {
m.MeasureSinceWithLabels(key, start, nil)
}
func (m *Metrics) MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
if m.HostName != "" && m.EnableHostnameLabel {
labels = append(labels, Label{"host", m.HostName})
}
if m.EnableTypePrefix {
key = insert(0, "timer", key)
}
if m.ServiceName != "" {
key = insert(0, m.ServiceName, key)
if m.EnableServiceLabel {
labels = append(labels, Label{"service", m.ServiceName})
} else {
key = insert(0, m.ServiceName, key)
}
}
if !m.allowMetric(key) {
return
}
now := time.Now()
elapsed := now.Sub(start)
msec := float32(elapsed.Nanoseconds()) / float32(m.TimerGranularity)
m.sink.AddSample(key, msec)
m.sink.AddSampleWithLabels(key, msec, labels)
}
// UpdateFilter overwrites the existing filter with the given rules.
func (m *Metrics) UpdateFilter(allow, block []string) {
m.filterLock.Lock()
defer m.filterLock.Unlock()
m.AllowedPrefixes = allow
m.BlockedPrefixes = block
m.filter = iradix.New()
for _, prefix := range m.AllowedPrefixes {
m.filter, _, _ = m.filter.Insert([]byte(prefix), true)
}
for _, prefix := range m.BlockedPrefixes {
m.filter, _, _ = m.filter.Insert([]byte(prefix), false)
}
}
// Returns whether the metric should be allowed based on configured prefix filters
func (m *Metrics) allowMetric(key []string) bool {
m.filterLock.RLock()
defer m.filterLock.RUnlock()
if m.filter == nil || m.filter.Len() == 0 {
return m.Config.FilterDefault
}
_, allowed, ok := m.filter.Root().LongestPrefix([]byte(strings.Join(key, ".")))
if !ok {
return m.Config.FilterDefault
}
return allowed.(bool)
}
// Periodically collects runtime stats to publish

151
vendor/github.com/armon/go-metrics/metrics_test.go сгенерированный поставляемый
Просмотреть файл

@@ -9,7 +9,7 @@ import (
func mockMetric() (*MockSink, *Metrics) {
m := &MockSink{}
met := &Metrics{sink: m}
met := &Metrics{Config: Config{FilterDefault: true}, sink: m}
return m, met
}
@@ -23,6 +23,19 @@ func TestMetrics_SetGauge(t *testing.T) {
t.Fatalf("")
}
m, met = mockMetric()
labels := []Label{{"a", "b"}}
met.SetGaugeWithLabels([]string{"key"}, float32(1), labels)
if m.keys[0][0] != "key" {
t.Fatalf("")
}
if m.vals[0] != 1 {
t.Fatalf("")
}
if !reflect.DeepEqual(m.labels[0], labels) {
t.Fatalf("")
}
m, met = mockMetric()
met.HostName = "test"
met.EnableHostname = true
@@ -96,6 +109,19 @@ func TestMetrics_IncrCounter(t *testing.T) {
t.Fatalf("")
}
m, met = mockMetric()
labels := []Label{{"a", "b"}}
met.IncrCounterWithLabels([]string{"key"}, float32(1), labels)
if m.keys[0][0] != "key" {
t.Fatalf("")
}
if m.vals[0] != 1 {
t.Fatalf("")
}
if !reflect.DeepEqual(m.labels[0], labels) {
t.Fatalf("")
}
m, met = mockMetric()
met.EnableTypePrefix = true
met.IncrCounter([]string{"key"}, float32(1))
@@ -127,6 +153,19 @@ func TestMetrics_AddSample(t *testing.T) {
t.Fatalf("")
}
m, met = mockMetric()
labels := []Label{{"a", "b"}}
met.AddSampleWithLabels([]string{"key"}, float32(1), labels)
if m.keys[0][0] != "key" {
t.Fatalf("")
}
if m.vals[0] != 1 {
t.Fatalf("")
}
if !reflect.DeepEqual(m.labels[0], labels) {
t.Fatalf("")
}
m, met = mockMetric()
met.EnableTypePrefix = true
met.AddSample([]string{"key"}, float32(1))
@@ -160,6 +199,20 @@ func TestMetrics_MeasureSince(t *testing.T) {
t.Fatalf("")
}
m, met = mockMetric()
met.TimerGranularity = time.Millisecond
labels := []Label{{"a", "b"}}
met.MeasureSinceWithLabels([]string{"key"}, n, labels)
if m.keys[0][0] != "key" {
t.Fatalf("")
}
if m.vals[0] > 0.1 {
t.Fatalf("")
}
if !reflect.DeepEqual(m.labels[0], labels) {
t.Fatalf("")
}
m, met = mockMetric()
met.TimerGranularity = time.Millisecond
met.EnableTypePrefix = true
@@ -260,3 +313,99 @@ func TestInsert(t *testing.T) {
t.Fatalf("bad insert %v %v", exp, out)
}
}
func TestMetrics_Filter_Blacklist(t *testing.T) {
m := &MockSink{}
conf := DefaultConfig("")
conf.AllowedPrefixes = []string{"service", "debug.thing"}
conf.BlockedPrefixes = []string{"debug"}
conf.EnableHostname = false
met, err := New(conf, m)
if err != nil {
t.Fatal(err)
}
// Allowed by default
key := []string{"thing"}
met.SetGauge(key, 1)
if !reflect.DeepEqual(m.keys[0], key) {
t.Fatalf("key doesn't exist %v, %v", m.keys[0], key)
}
if m.vals[0] != 1 {
t.Fatalf("bad val: %v", m.vals[0])
}
// Allowed by filter
key = []string{"service", "thing"}
met.SetGauge(key, 2)
if !reflect.DeepEqual(m.keys[1], key) {
t.Fatalf("key doesn't exist")
}
if m.vals[1] != 2 {
t.Fatalf("bad val: %v", m.vals[1])
}
// Allowed by filter, subtree of a blocked entry
key = []string{"debug", "thing"}
met.SetGauge(key, 3)
if !reflect.DeepEqual(m.keys[2], key) {
t.Fatalf("key doesn't exist")
}
if m.vals[2] != 3 {
t.Fatalf("bad val: %v", m.vals[2])
}
// Blocked by filter
key = []string{"debug", "other-thing"}
met.SetGauge(key, 4)
if len(m.keys) != 3 {
t.Fatalf("key shouldn't exist")
}
}
func TestMetrics_Filter_Whitelist(t *testing.T) {
m := &MockSink{}
conf := DefaultConfig("")
conf.AllowedPrefixes = []string{"service", "debug.thing"}
conf.BlockedPrefixes = []string{"debug"}
conf.FilterDefault = false
conf.EnableHostname = false
met, err := New(conf, m)
if err != nil {
t.Fatal(err)
}
// Blocked by default
key := []string{"thing"}
met.SetGauge(key, 1)
if len(m.keys) != 0 {
t.Fatalf("key should not exist")
}
// Allowed by filter
key = []string{"service", "thing"}
met.SetGauge(key, 2)
if !reflect.DeepEqual(m.keys[0], key) {
t.Fatalf("key doesn't exist")
}
if m.vals[0] != 2 {
t.Fatalf("bad val: %v", m.vals[0])
}
// Allowed by filter, subtree of a blocked entry
key = []string{"debug", "thing"}
met.SetGauge(key, 3)
if !reflect.DeepEqual(m.keys[1], key) {
t.Fatalf("key doesn't exist")
}
if m.vals[1] != 3 {
t.Fatalf("bad val: %v", m.vals[1])
}
// Blocked by filter
key = []string{"debug", "other-thing"}
met.SetGauge(key, 4)
if len(m.keys) != 2 {
t.Fatalf("key shouldn't exist")
}
}

72
vendor/github.com/armon/go-metrics/prometheus/prometheus.go сгенерированный поставляемый
Просмотреть файл

@@ -2,10 +2,14 @@
package prometheus
import (
"fmt"
"strings"
"sync"
"time"
"regexp"
"github.com/armon/go-metrics"
"github.com/prometheus/client_golang/prometheus"
)
@@ -24,24 +28,42 @@ func NewPrometheusSink() (*PrometheusSink, error) {
}, nil
}
func (p *PrometheusSink) flattenKey(parts []string) string {
joined := strings.Join(parts, "_")
joined = strings.Replace(joined, " ", "_", -1)
joined = strings.Replace(joined, ".", "_", -1)
joined = strings.Replace(joined, "-", "_", -1)
joined = strings.Replace(joined, "=", "_", -1)
return joined
var forbiddenChars = regexp.MustCompile("[ .=\\-]")
func (p *PrometheusSink) flattenKey(parts []string, labels []metrics.Label) (string, string) {
key := strings.Join(parts, "_")
key = forbiddenChars.ReplaceAllString(key, "_")
hash := key
for _, label := range labels {
hash += fmt.Sprintf(";%s=%s", label.Name, label.Value)
}
return key, hash
}
func prometheusLabels(labels []metrics.Label) prometheus.Labels {
l := make(prometheus.Labels)
for _, label := range labels {
l[label.Name] = label.Value
}
return l
}
func (p *PrometheusSink) SetGauge(parts []string, val float32) {
p.SetGaugeWithLabels(parts, val, nil)
}
func (p *PrometheusSink) SetGaugeWithLabels(parts []string, val float32, labels []metrics.Label) {
p.mu.Lock()
defer p.mu.Unlock()
key := p.flattenKey(parts)
g, ok := p.gauges[key]
key, hash := p.flattenKey(parts, labels)
g, ok := p.gauges[hash]
if !ok {
g = prometheus.NewGauge(prometheus.GaugeOpts{
Name: key,
Help: key,
Name: key,
Help: key,
ConstLabels: prometheusLabels(labels),
})
prometheus.MustRegister(g)
p.gauges[key] = g
@@ -50,15 +72,20 @@ func (p *PrometheusSink) SetGauge(parts []string, val float32) {
}
func (p *PrometheusSink) AddSample(parts []string, val float32) {
p.AddSampleWithLabels(parts, val, nil)
}
func (p *PrometheusSink) AddSampleWithLabels(parts []string, val float32, labels []metrics.Label) {
p.mu.Lock()
defer p.mu.Unlock()
key := p.flattenKey(parts)
g, ok := p.summaries[key]
key, hash := p.flattenKey(parts, labels)
g, ok := p.summaries[hash]
if !ok {
g = prometheus.NewSummary(prometheus.SummaryOpts{
Name: key,
Help: key,
MaxAge: 10 * time.Second,
Name: key,
Help: key,
MaxAge: 10 * time.Second,
ConstLabels: prometheusLabels(labels),
})
prometheus.MustRegister(g)
p.summaries[key] = g
@@ -73,14 +100,19 @@ func (p *PrometheusSink) EmitKey(key []string, val float32) {
}
func (p *PrometheusSink) IncrCounter(parts []string, val float32) {
p.IncrCounterWithLabels(parts, val, nil)
}
func (p *PrometheusSink) IncrCounterWithLabels(parts []string, val float32, labels []metrics.Label) {
p.mu.Lock()
defer p.mu.Unlock()
key := p.flattenKey(parts)
g, ok := p.counters[key]
key, hash := p.flattenKey(parts, labels)
g, ok := p.counters[hash]
if !ok {
g = prometheus.NewCounter(prometheus.CounterOpts{
Name: key,
Help: key,
Name: key,
Help: key,
ConstLabels: prometheusLabels(labels),
})
prometheus.MustRegister(g)
p.counters[key] = g

32
vendor/github.com/armon/go-metrics/sink.go сгенерированный поставляемый
Просмотреть файл

@@ -10,31 +10,41 @@ import (
type MetricSink interface {
// A Gauge should retain the last value it is set to
SetGauge(key []string, val float32)
SetGaugeWithLabels(key []string, val float32, labels []Label)
// Should emit a Key/Value pair for each call
EmitKey(key []string, val float32)
// Counters should accumulate values
IncrCounter(key []string, val float32)
IncrCounterWithLabels(key []string, val float32, labels []Label)
// Samples are for timing information, where quantiles are used
AddSample(key []string, val float32)
AddSampleWithLabels(key []string, val float32, labels []Label)
}
// BlackholeSink is used to just blackhole messages
type BlackholeSink struct{}
func (*BlackholeSink) SetGauge(key []string, val float32) {}
func (*BlackholeSink) EmitKey(key []string, val float32) {}
func (*BlackholeSink) IncrCounter(key []string, val float32) {}
func (*BlackholeSink) AddSample(key []string, val float32) {}
func (*BlackholeSink) SetGauge(key []string, val float32) {}
func (*BlackholeSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {}
func (*BlackholeSink) EmitKey(key []string, val float32) {}
func (*BlackholeSink) IncrCounter(key []string, val float32) {}
func (*BlackholeSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {}
func (*BlackholeSink) AddSample(key []string, val float32) {}
func (*BlackholeSink) AddSampleWithLabels(key []string, val float32, labels []Label) {}
// FanoutSink is used to sink to fanout values to multiple sinks
type FanoutSink []MetricSink
func (fh FanoutSink) SetGauge(key []string, val float32) {
fh.SetGaugeWithLabels(key, val, nil)
}
func (fh FanoutSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
for _, s := range fh {
s.SetGauge(key, val)
s.SetGaugeWithLabels(key, val, labels)
}
}
@@ -45,14 +55,22 @@ func (fh FanoutSink) EmitKey(key []string, val float32) {
}
func (fh FanoutSink) IncrCounter(key []string, val float32) {
fh.IncrCounterWithLabels(key, val, nil)
}
func (fh FanoutSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
for _, s := range fh {
s.IncrCounter(key, val)
s.IncrCounterWithLabels(key, val, labels)
}
}
func (fh FanoutSink) AddSample(key []string, val float32) {
fh.AddSampleWithLabels(key, val, nil)
}
func (fh FanoutSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
for _, s := range fh {
s.AddSample(key, val)
s.AddSampleWithLabels(key, val, labels)
}
}

108
vendor/github.com/armon/go-metrics/sink_test.go сгенерированный поставляемый
Просмотреть файл

@@ -7,25 +7,39 @@ import (
)
type MockSink struct {
keys [][]string
vals []float32
keys [][]string
vals []float32
labels [][]Label
}
func (m *MockSink) SetGauge(key []string, val float32) {
m.SetGaugeWithLabels(key, val, nil)
}
func (m *MockSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
m.keys = append(m.keys, key)
m.vals = append(m.vals, val)
m.labels = append(m.labels, labels)
}
func (m *MockSink) EmitKey(key []string, val float32) {
m.keys = append(m.keys, key)
m.vals = append(m.vals, val)
m.labels = append(m.labels, nil)
}
func (m *MockSink) IncrCounter(key []string, val float32) {
m.IncrCounterWithLabels(key, val, nil)
}
func (m *MockSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
m.keys = append(m.keys, key)
m.vals = append(m.vals, val)
m.labels = append(m.labels, labels)
}
func (m *MockSink) AddSample(key []string, val float32) {
m.AddSampleWithLabels(key, val, nil)
}
func (m *MockSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
m.keys = append(m.keys, key)
m.vals = append(m.vals, val)
m.labels = append(m.labels, labels)
}
func TestFanoutSink_Gauge(t *testing.T) {
@@ -51,6 +65,36 @@ func TestFanoutSink_Gauge(t *testing.T) {
}
}
func TestFanoutSink_Gauge_Labels(t *testing.T) {
m1 := &MockSink{}
m2 := &MockSink{}
fh := &FanoutSink{m1, m2}
k := []string{"test"}
v := float32(42.0)
l := []Label{{"a", "b"}}
fh.SetGaugeWithLabels(k, v, l)
if !reflect.DeepEqual(m1.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m2.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m1.vals[0], v) {
t.Fatalf("val not equal")
}
if !reflect.DeepEqual(m2.vals[0], v) {
t.Fatalf("val not equal")
}
if !reflect.DeepEqual(m1.labels[0], l) {
t.Fatalf("labels not equal")
}
if !reflect.DeepEqual(m2.labels[0], l) {
t.Fatalf("labels not equal")
}
}
func TestFanoutSink_Key(t *testing.T) {
m1 := &MockSink{}
m2 := &MockSink{}
@@ -97,6 +141,36 @@ func TestFanoutSink_Counter(t *testing.T) {
}
}
func TestFanoutSink_Counter_Labels(t *testing.T) {
m1 := &MockSink{}
m2 := &MockSink{}
fh := &FanoutSink{m1, m2}
k := []string{"test"}
v := float32(42.0)
l := []Label{{"a", "b"}}
fh.IncrCounterWithLabels(k, v, l)
if !reflect.DeepEqual(m1.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m2.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m1.vals[0], v) {
t.Fatalf("val not equal")
}
if !reflect.DeepEqual(m2.vals[0], v) {
t.Fatalf("val not equal")
}
if !reflect.DeepEqual(m1.labels[0], l) {
t.Fatalf("labels not equal")
}
if !reflect.DeepEqual(m2.labels[0], l) {
t.Fatalf("labels not equal")
}
}
func TestFanoutSink_Sample(t *testing.T) {
m1 := &MockSink{}
m2 := &MockSink{}
@@ -120,6 +194,36 @@ func TestFanoutSink_Sample(t *testing.T) {
}
}
func TestFanoutSink_Sample_Labels(t *testing.T) {
m1 := &MockSink{}
m2 := &MockSink{}
fh := &FanoutSink{m1, m2}
k := []string{"test"}
v := float32(42.0)
l := []Label{{"a", "b"}}
fh.AddSampleWithLabels(k, v, l)
if !reflect.DeepEqual(m1.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m2.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m1.vals[0], v) {
t.Fatalf("val not equal")
}
if !reflect.DeepEqual(m2.vals[0], v) {
t.Fatalf("val not equal")
}
if !reflect.DeepEqual(m1.labels[0], l) {
t.Fatalf("labels not equal")
}
if !reflect.DeepEqual(m2.labels[0], l) {
t.Fatalf("labels not equal")
}
}
func TestNewMetricSinkFromURL(t *testing.T) {
for _, tc := range []struct {
desc string

37
vendor/github.com/armon/go-metrics/start.go сгенерированный поставляемый
Просмотреть файл

@@ -2,8 +2,11 @@ package metrics
import (
"os"
"sync"
"sync/atomic"
"time"
"github.com/hashicorp/go-immutable-radix"
)
// Config is used to configure metrics settings
@@ -11,18 +14,26 @@ type Config struct {
ServiceName string // Prefixed with keys to seperate services
HostName string // Hostname to use. If not provided and EnableHostname, it will be os.Hostname
EnableHostname bool // Enable prefixing gauge values with hostname
EnableHostnameLabel bool // Enable adding hostname to labels
EnableServiceLabel bool // Enable adding service to labels
EnableRuntimeMetrics bool // Enables profiling of runtime metrics (GC, Goroutines, Memory)
EnableTypePrefix bool // Prefixes key with a type ("counter", "gauge", "timer")
TimerGranularity time.Duration // Granularity of timers.
ProfileInterval time.Duration // Interval to profile runtime metrics
AllowedPrefixes []string // A list of metric prefixes to allow, with '.' as the separator
BlockedPrefixes []string // A list of metric prefixes to block, with '.' as the separator
FilterDefault bool // Whether to allow metrics by default
}
// Metrics represents an instance of a metrics sink that can
// be used to emit
type Metrics struct {
Config
lastNumGC uint32
sink MetricSink
lastNumGC uint32
sink MetricSink
filter *iradix.Tree
filterLock sync.RWMutex
}
// Shared global metrics instance
@@ -43,6 +54,7 @@ func DefaultConfig(serviceName string) *Config {
EnableTypePrefix: false, // Disable type prefix
TimerGranularity: time.Millisecond, // Timers are in milliseconds
ProfileInterval: time.Second, // Poll runtime every second
FilterDefault: true, // Don't filter metrics by default
}
// Try to get the hostname
@@ -56,6 +68,7 @@ func New(conf *Config, sink MetricSink) (*Metrics, error) {
met := &Metrics{}
met.Config = *conf
met.sink = sink
met.UpdateFilter(conf.AllowedPrefixes, conf.BlockedPrefixes)
// Start the runtime collector
if conf.EnableRuntimeMetrics {
@@ -79,6 +92,10 @@ func SetGauge(key []string, val float32) {
globalMetrics.Load().(*Metrics).SetGauge(key, val)
}
func SetGaugeWithLabels(key []string, val float32, labels []Label) {
globalMetrics.Load().(*Metrics).SetGaugeWithLabels(key, val, labels)
}
func EmitKey(key []string, val float32) {
globalMetrics.Load().(*Metrics).EmitKey(key, val)
}
@@ -87,10 +104,26 @@ func IncrCounter(key []string, val float32) {
globalMetrics.Load().(*Metrics).IncrCounter(key, val)
}
func IncrCounterWithLabels(key []string, val float32, labels []Label) {
globalMetrics.Load().(*Metrics).IncrCounterWithLabels(key, val, labels)
}
func AddSample(key []string, val float32) {
globalMetrics.Load().(*Metrics).AddSample(key, val)
}
func AddSampleWithLabels(key []string, val float32, labels []Label) {
globalMetrics.Load().(*Metrics).AddSampleWithLabels(key, val, labels)
}
func MeasureSince(key []string, start time.Time) {
globalMetrics.Load().(*Metrics).MeasureSince(key, start)
}
func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
globalMetrics.Load().(*Metrics).MeasureSinceWithLabels(key, start, labels)
}
func UpdateFilter(allow, block []string) {
globalMetrics.Load().(*Metrics).UpdateFilter(allow, block)
}

107
vendor/github.com/armon/go-metrics/start_test.go сгенерированный поставляемый
Просмотреть файл

@@ -30,6 +30,7 @@ func TestDefaultConfig(t *testing.T) {
t.Fatalf("bad interval")
}
}
func Test_GlobalMetrics(t *testing.T) {
var tests = []struct {
desc string
@@ -46,7 +47,7 @@ func Test_GlobalMetrics(t *testing.T) {
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
s := &MockSink{}
globalMetrics.Store(&Metrics{sink: s})
globalMetrics.Store(&Metrics{Config: Config{FilterDefault: true}, sink: s})
tt.fn(tt.key, tt.val)
if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) {
t.Fatalf("got key %s want %s", got, want)
@@ -58,9 +59,83 @@ func Test_GlobalMetrics(t *testing.T) {
}
}
func Test_GlobalMetrics_Labels(t *testing.T) {
labels := []Label{{"a", "b"}}
var tests = []struct {
desc string
key []string
val float32
fn func([]string, float32, []Label)
labels []Label
}{
{"SetGaugeWithLabels", []string{"test"}, 42, SetGaugeWithLabels, labels},
{"IncrCounterWithLabels", []string{"test"}, 42, IncrCounterWithLabels, labels},
{"AddSampleWithLabels", []string{"test"}, 42, AddSampleWithLabels, labels},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
s := &MockSink{}
globalMetrics.Store(&Metrics{Config: Config{FilterDefault: true}, sink: s})
tt.fn(tt.key, tt.val, tt.labels)
if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) {
t.Fatalf("got key %s want %s", got, want)
}
if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) {
t.Fatalf("got val %s want %s", got, want)
}
if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) {
t.Fatalf("got val %s want %s", got, want)
}
})
}
}
func Test_GlobalMetrics_DefaultLabels(t *testing.T) {
config := Config{
HostName: "host1",
ServiceName: "redis",
EnableHostnameLabel: true,
EnableServiceLabel: true,
FilterDefault: true,
}
labels := []Label{
{"host", config.HostName},
{"service", config.ServiceName},
}
var tests = []struct {
desc string
key []string
val float32
fn func([]string, float32, []Label)
labels []Label
}{
{"SetGaugeWithLabels", []string{"test"}, 42, SetGaugeWithLabels, labels},
{"IncrCounterWithLabels", []string{"test"}, 42, IncrCounterWithLabels, labels},
{"AddSampleWithLabels", []string{"test"}, 42, AddSampleWithLabels, labels},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
s := &MockSink{}
globalMetrics.Store(&Metrics{Config: config, sink: s})
tt.fn(tt.key, tt.val, nil)
if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) {
t.Fatalf("got key %s want %s", got, want)
}
if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) {
t.Fatalf("got val %s want %s", got, want)
}
if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) {
t.Fatalf("got val %s want %s", got, want)
}
})
}
}
func Test_GlobalMetrics_MeasureSince(t *testing.T) {
s := &MockSink{}
m := &Metrics{sink: s, Config: Config{TimerGranularity: time.Millisecond}}
m := &Metrics{sink: s, Config: Config{TimerGranularity: time.Millisecond, FilterDefault: true}}
globalMetrics.Store(m)
k := []string{"test"}
@@ -73,6 +148,34 @@ func Test_GlobalMetrics_MeasureSince(t *testing.T) {
if s.vals[0] > 0.1 {
t.Fatalf("val too large %v", s.vals[0])
}
labels := []Label{{"a", "b"}}
MeasureSinceWithLabels(k, now, labels)
if got, want := s.keys[1], k; !reflect.DeepEqual(got, want) {
t.Fatalf("got key %s want %s", got, want)
}
if s.vals[1] > 0.1 {
t.Fatalf("val too large %v", s.vals[0])
}
if got, want := s.labels[1], labels; !reflect.DeepEqual(got, want) {
t.Fatalf("got val %s want %s", got, want)
}
}
func Test_GlobalMetrics_UpdateFilter(t *testing.T) {
globalMetrics.Store(&Metrics{Config: Config{
AllowedPrefixes: []string{"a"},
BlockedPrefixes: []string{"b"},
}})
UpdateFilter([]string{"c"}, []string{"d"})
m := globalMetrics.Load().(*Metrics)
if m.AllowedPrefixes[0] != "c" {
t.Fatalf("bad: %v", m.AllowedPrefixes)
}
if m.BlockedPrefixes[0] != "d" {
t.Fatalf("bad: %v", m.BlockedPrefixes)
}
}
// Benchmark_GlobalMetrics_Direct/direct-8 5000000 278 ns/op

23
vendor/github.com/armon/go-metrics/statsd.go сгенерированный поставляемый
Просмотреть файл

@@ -50,6 +50,11 @@ func (s *StatsdSink) SetGauge(key []string, val float32) {
s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
}
func (s *StatsdSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
}
func (s *StatsdSink) EmitKey(key []string, val float32) {
flatKey := s.flattenKey(key)
s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
@@ -60,11 +65,21 @@ func (s *StatsdSink) IncrCounter(key []string, val float32) {
s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
}
func (s *StatsdSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
}
func (s *StatsdSink) AddSample(key []string, val float32) {
flatKey := s.flattenKey(key)
s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
}
func (s *StatsdSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
}
// Flattens the key for formatting, removes spaces
func (s *StatsdSink) flattenKey(parts []string) string {
joined := strings.Join(parts, ".")
@@ -80,6 +95,14 @@ func (s *StatsdSink) flattenKey(parts []string) string {
}, joined)
}
// Flattens the key along with labels for formatting, removes spaces
func (s *StatsdSink) flattenKeyLabels(parts []string, labels []Label) string {
for _, label := range labels {
parts = append(parts, label.Value)
}
return s.flattenKey(parts)
}
// Does a non-blocking push to the metrics queue
func (s *StatsdSink) pushMetric(m string) {
select {

39
vendor/github.com/armon/go-metrics/statsd_test.go сгенерированный поставляемый
Просмотреть файл

@@ -66,7 +66,7 @@ func TestStatsd_Conn(t *testing.T) {
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "key.other:2.000000|kv\n" {
if line != "gauge_labels.val.label:2.000000|g\n" {
t.Fatalf("bad line %s", line)
}
@@ -74,7 +74,7 @@ func TestStatsd_Conn(t *testing.T) {
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "counter.me:3.000000|c\n" {
if line != "key.other:3.000000|kv\n" {
t.Fatalf("bad line %s", line)
}
@@ -82,7 +82,31 @@ func TestStatsd_Conn(t *testing.T) {
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "sample.slow_thingy:4.000000|ms\n" {
if line != "counter.me:4.000000|c\n" {
t.Fatalf("bad line %s", line)
}
line, err = reader.ReadString('\n')
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "counter_labels.me.label:5.000000|c\n" {
t.Fatalf("bad line %s", line)
}
line, err = reader.ReadString('\n')
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "sample.slow_thingy:6.000000|ms\n" {
t.Fatalf("bad line %s", line)
}
line, err = reader.ReadString('\n')
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "sample_labels.slow_thingy.label:7.000000|ms\n" {
t.Fatalf("bad line %s", line)
}
@@ -94,9 +118,12 @@ func TestStatsd_Conn(t *testing.T) {
}
s.SetGauge([]string{"gauge", "val"}, float32(1))
s.EmitKey([]string{"key", "other"}, float32(2))
s.IncrCounter([]string{"counter", "me"}, float32(3))
s.AddSample([]string{"sample", "slow thingy"}, float32(4))
s.SetGaugeWithLabels([]string{"gauge_labels", "val"}, float32(2), []Label{{"a", "label"}})
s.EmitKey([]string{"key", "other"}, float32(3))
s.IncrCounter([]string{"counter", "me"}, float32(4))
s.IncrCounterWithLabels([]string{"counter_labels", "me"}, float32(5), []Label{{"a", "label"}})
s.AddSample([]string{"sample", "slow thingy"}, float32(6))
s.AddSampleWithLabels([]string{"sample_labels", "slow thingy"}, float32(7), []Label{{"a", "label"}})
select {
case <-done:

23
vendor/github.com/armon/go-metrics/statsite.go сгенерированный поставляемый
Просмотреть файл

@@ -50,6 +50,11 @@ func (s *StatsiteSink) SetGauge(key []string, val float32) {
s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
}
func (s *StatsiteSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
}
func (s *StatsiteSink) EmitKey(key []string, val float32) {
flatKey := s.flattenKey(key)
s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
@@ -60,11 +65,21 @@ func (s *StatsiteSink) IncrCounter(key []string, val float32) {
s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
}
func (s *StatsiteSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
}
func (s *StatsiteSink) AddSample(key []string, val float32) {
flatKey := s.flattenKey(key)
s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
}
func (s *StatsiteSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
flatKey := s.flattenKeyLabels(key, labels)
s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
}
// Flattens the key for formatting, removes spaces
func (s *StatsiteSink) flattenKey(parts []string) string {
joined := strings.Join(parts, ".")
@@ -80,6 +95,14 @@ func (s *StatsiteSink) flattenKey(parts []string) string {
}, joined)
}
// Flattens the key along with labels for formatting, removes spaces
func (s *StatsiteSink) flattenKeyLabels(parts []string, labels []Label) string {
for _, label := range labels {
parts = append(parts, label.Value)
}
return s.flattenKey(parts)
}
// Does a non-blocking push to the metrics queue
func (s *StatsiteSink) pushMetric(m string) {
select {

39
vendor/github.com/armon/go-metrics/statsite_test.go сгенерированный поставляемый
Просмотреть файл

@@ -61,7 +61,7 @@ func TestStatsite_Conn(t *testing.T) {
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "key.other:2.000000|kv\n" {
if line != "gauge_labels.val.label:2.000000|g\n" {
t.Fatalf("bad line %s", line)
}
@@ -69,7 +69,7 @@ func TestStatsite_Conn(t *testing.T) {
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "counter.me:3.000000|c\n" {
if line != "key.other:3.000000|kv\n" {
t.Fatalf("bad line %s", line)
}
@@ -77,7 +77,31 @@ func TestStatsite_Conn(t *testing.T) {
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "sample.slow_thingy:4.000000|ms\n" {
if line != "counter.me:4.000000|c\n" {
t.Fatalf("bad line %s", line)
}
line, err = reader.ReadString('\n')
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "counter_labels.me.label:5.000000|c\n" {
t.Fatalf("bad line %s", line)
}
line, err = reader.ReadString('\n')
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "sample.slow_thingy:6.000000|ms\n" {
t.Fatalf("bad line %s", line)
}
line, err = reader.ReadString('\n')
if err != nil {
t.Fatalf("unexpected err %s", err)
}
if line != "sample_labels.slow_thingy.label:7.000000|ms\n" {
t.Fatalf("bad line %s", line)
}
@@ -90,9 +114,12 @@ func TestStatsite_Conn(t *testing.T) {
}
s.SetGauge([]string{"gauge", "val"}, float32(1))
s.EmitKey([]string{"key", "other"}, float32(2))
s.IncrCounter([]string{"counter", "me"}, float32(3))
s.AddSample([]string{"sample", "slow thingy"}, float32(4))
s.SetGaugeWithLabels([]string{"gauge_labels", "val"}, float32(2), []Label{{"a", "label"}})
s.EmitKey([]string{"key", "other"}, float32(3))
s.IncrCounter([]string{"counter", "me"}, float32(4))
s.IncrCounterWithLabels([]string{"counter_labels", "me"}, float32(5), []Label{{"a", "label"}})
s.AddSample([]string{"sample", "slow thingy"}, float32(6))
s.AddSampleWithLabels([]string{"sample_labels", "slow thingy"}, float32(7), []Label{{"a", "label"}})
select {
case <-done: