summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/armon
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2017-08-17 17:19:06 -0700
committerGitHub <noreply@github.com>2017-08-17 17:19:06 -0700
commit96eab1202717e073782ec399a4e0820cae15b1bb (patch)
tree011012982be971c7e9ef91466f026bc0956ac9a2 /vendor/github.com/armon
parent2c895ee66eed626721135acfcc48254c6e3f3b29 (diff)
downloadchat-96eab1202717e073782ec399a4e0820cae15b1bb.tar.gz
chat-96eab1202717e073782ec399a4e0820cae15b1bb.tar.bz2
chat-96eab1202717e073782ec399a4e0820cae15b1bb.zip
Updating server dependancies. (#7246)
Diffstat (limited to 'vendor/github.com/armon')
-rw-r--r--vendor/github.com/armon/go-metrics/circonus/circonus.go27
-rw-r--r--vendor/github.com/armon/go-metrics/circonus/circonus_test.go4
-rw-r--r--vendor/github.com/armon/go-metrics/datadog/dogstatsd.go73
-rw-r--r--vendor/github.com/armon/go-metrics/datadog/dogstatsd_test.go35
-rw-r--r--vendor/github.com/armon/go-metrics/inmem.go95
-rw-r--r--vendor/github.com/armon/go-metrics/inmem_endpoint.go118
-rw-r--r--vendor/github.com/armon/go-metrics/inmem_endpoint_test.go133
-rw-r--r--vendor/github.com/armon/go-metrics/inmem_signal.go33
-rw-r--r--vendor/github.com/armon/go-metrics/inmem_signal_test.go12
-rw-r--r--vendor/github.com/armon/go-metrics/inmem_test.go76
-rw-r--r--vendor/github.com/armon/go-metrics/metrics.go121
-rw-r--r--vendor/github.com/armon/go-metrics/metrics_test.go151
-rw-r--r--vendor/github.com/armon/go-metrics/prometheus/prometheus.go72
-rw-r--r--vendor/github.com/armon/go-metrics/sink.go32
-rw-r--r--vendor/github.com/armon/go-metrics/sink_test.go108
-rw-r--r--vendor/github.com/armon/go-metrics/start.go37
-rw-r--r--vendor/github.com/armon/go-metrics/start_test.go107
-rw-r--r--vendor/github.com/armon/go-metrics/statsd.go23
-rw-r--r--vendor/github.com/armon/go-metrics/statsd_test.go39
-rw-r--r--vendor/github.com/armon/go-metrics/statsite.go23
-rw-r--r--vendor/github.com/armon/go-metrics/statsite_test.go39
21 files changed, 1194 insertions, 164 deletions
diff --git a/vendor/github.com/armon/go-metrics/circonus/circonus.go b/vendor/github.com/armon/go-metrics/circonus/circonus.go
index c6e3974b5..eb41b9945 100644
--- a/vendor/github.com/armon/go-metrics/circonus/circonus.go
+++ b/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)
+}
diff --git a/vendor/github.com/armon/go-metrics/circonus/circonus_test.go b/vendor/github.com/armon/go-metrics/circonus/circonus_test.go
index 234a3cb89..4eb76e411 100644
--- a/vendor/github.com/armon/go-metrics/circonus/circonus_test.go
+++ b/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 {
diff --git a/vendor/github.com/armon/go-metrics/datadog/dogstatsd.go b/vendor/github.com/armon/go-metrics/datadog/dogstatsd.go
index aaba9fe0e..fe021d01c 100644
--- a/vendor/github.com/armon/go-metrics/datadog/dogstatsd.go
+++ b/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 sanitize(r rune) rune {
+ switch r {
+ case ':':
+ fallthrough
+ case ' ':
+ return '_'
+ default:
+ return r
+ }
}
-func (s *DogStatsdSink) parseKey(key []string) ([]string, []string) {
+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
}
diff --git a/vendor/github.com/armon/go-metrics/datadog/dogstatsd_test.go b/vendor/github.com/armon/go-metrics/datadog/dogstatsd_test.go
index 0ec51e3f1..43b81ac7f 100644
--- a/vendor/github.com/armon/go-metrics/datadog/dogstatsd_test.go
+++ b/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")
}
diff --git a/vendor/github.com/armon/go-metrics/inmem.go b/vendor/github.com/armon/go-metrics/inmem.go
index ac46443be..cd1773042 100644
--- a/vendor/github.com/armon/go-metrics/inmem.go
+++ b/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
}
diff --git a/vendor/github.com/armon/go-metrics/inmem_endpoint.go b/vendor/github.com/armon/go-metrics/inmem_endpoint.go
new file mode 100644
index 000000000..504f1b374
--- /dev/null
+++ b/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
+}
diff --git a/vendor/github.com/armon/go-metrics/inmem_endpoint_test.go b/vendor/github.com/armon/go-metrics/inmem_endpoint_test.go
new file mode 100644
index 000000000..326d56ada
--- /dev/null
+++ b/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)
+}
diff --git a/vendor/github.com/armon/go-metrics/inmem_signal.go b/vendor/github.com/armon/go-metrics/inmem_signal.go
index 95d08ee10..0937f4aed 100644
--- a/vendor/github.com/armon/go-metrics/inmem_signal.go
+++ b/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()
+}
diff --git a/vendor/github.com/armon/go-metrics/inmem_signal_test.go b/vendor/github.com/armon/go-metrics/inmem_signal_test.go
index 9bbca5f25..c992d6bce 100644
--- a/vendor/github.com/armon/go-metrics/inmem_signal_test.go
+++ b/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)
+ }
}
diff --git a/vendor/github.com/armon/go-metrics/inmem_test.go b/vendor/github.com/armon/go-metrics/inmem_test.go
index ed3b521da..8d30e7c30 100644
--- a/vendor/github.com/armon/go-metrics/inmem_test.go
+++ b/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)
+ }
- 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)
+ }
}
- diff := time.Now().Sub(agg.LastUpdated).Seconds()
- if diff > 1 {
- t.Fatalf("time diff too great: %f", diff)
+ if _, ok := intvM.Samples["foo.bar"]; !ok {
+ t.Fatalf("missing sample")
}
- if agg = intvM.Samples["foo.bar"]; agg == nil {
+ if _, ok := intvM.Samples["foo.bar;a=b"]; !ok {
t.Fatalf("missing sample")
}
diff --git a/vendor/github.com/armon/go-metrics/metrics.go b/vendor/github.com/armon/go-metrics/metrics.go
index b818e4182..d260bd4b2 100644
--- a/vendor/github.com/armon/go-metrics/metrics.go
+++ b/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)
+ }
+ }
+ if !m.allowMetric(key) {
+ return
}
- m.sink.SetGauge(key, val)
+ 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)
+ }
+ }
+ if !m.allowMetric(key) {
+ return
}
- m.sink.AddSample(key, val)
+ 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
diff --git a/vendor/github.com/armon/go-metrics/metrics_test.go b/vendor/github.com/armon/go-metrics/metrics_test.go
index f5b2a4c79..8556a0019 100644
--- a/vendor/github.com/armon/go-metrics/metrics_test.go
+++ b/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
}
@@ -24,6 +24,19 @@ func TestMetrics_SetGauge(t *testing.T) {
}
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
met.SetGauge([]string{"key"}, float32(1))
@@ -97,6 +110,19 @@ func TestMetrics_IncrCounter(t *testing.T) {
}
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))
if m.keys[0][0] != "counter" || m.keys[0][1] != "key" {
@@ -128,6 +154,19 @@ func TestMetrics_AddSample(t *testing.T) {
}
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))
if m.keys[0][0] != "sample" || m.keys[0][1] != "key" {
@@ -162,6 +201,20 @@ func TestMetrics_MeasureSince(t *testing.T) {
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
met.MeasureSince([]string{"key"}, n)
if m.keys[0][0] != "timer" || m.keys[0][1] != "key" {
@@ -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")
+ }
+}
diff --git a/vendor/github.com/armon/go-metrics/prometheus/prometheus.go b/vendor/github.com/armon/go-metrics/prometheus/prometheus.go
index b26d27981..f31f2f9a5 100644
--- a/vendor/github.com/armon/go-metrics/prometheus/prometheus.go
+++ b/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
diff --git a/vendor/github.com/armon/go-metrics/sink.go b/vendor/github.com/armon/go-metrics/sink.go
index 9f7e2f6a2..0b7d6e4be 100644
--- a/vendor/github.com/armon/go-metrics/sink.go
+++ b/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)
}
}
diff --git a/vendor/github.com/armon/go-metrics/sink_test.go b/vendor/github.com/armon/go-metrics/sink_test.go
index 77c5c3278..714f99b81 100644
--- a/vendor/github.com/armon/go-metrics/sink_test.go
+++ b/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
diff --git a/vendor/github.com/armon/go-metrics/start.go b/vendor/github.com/armon/go-metrics/start.go
index 40c8d68c1..46f0c2eb2 100644
--- a/vendor/github.com/armon/go-metrics/start.go
+++ b/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)
+}
diff --git a/vendor/github.com/armon/go-metrics/start_test.go b/vendor/github.com/armon/go-metrics/start_test.go
index 96b73d956..f85a5bec3 100644
--- a/vendor/github.com/armon/go-metrics/start_test.go
+++ b/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
diff --git a/vendor/github.com/armon/go-metrics/statsd.go b/vendor/github.com/armon/go-metrics/statsd.go
index 4241e880c..1bfffce46 100644
--- a/vendor/github.com/armon/go-metrics/statsd.go
+++ b/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 {
diff --git a/vendor/github.com/armon/go-metrics/statsd_test.go b/vendor/github.com/armon/go-metrics/statsd_test.go
index 0602b213f..bdf36cc00 100644
--- a/vendor/github.com/armon/go-metrics/statsd_test.go
+++ b/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:
diff --git a/vendor/github.com/armon/go-metrics/statsite.go b/vendor/github.com/armon/go-metrics/statsite.go
index 572fe0571..6c0d284d2 100644
--- a/vendor/github.com/armon/go-metrics/statsite.go
+++ b/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 {
diff --git a/vendor/github.com/armon/go-metrics/statsite_test.go b/vendor/github.com/armon/go-metrics/statsite_test.go
index 704474f43..92687889b 100644
--- a/vendor/github.com/armon/go-metrics/statsite_test.go
+++ b/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: