Этот коммит содержится в:
Christopher Speller
2017-06-21 19:06:17 -07:00
коммит произвёл Corey Hulen
родитель 6b39c308d8
Коммит 42f28ab8e3
714 изменённых файлов: 54430 добавлений и 51180 удалений

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

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

@@ -3,6 +3,7 @@ package metrics
import (
"fmt"
"math"
"net/url"
"strings"
"sync"
"time"
@@ -25,7 +26,7 @@ type InmemSink struct {
// intervals is a slice of the retained intervals
intervals []*IntervalMetrics
intervalLock sync.RWMutex
rateDenom float64
}
@@ -68,7 +69,7 @@ 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 // The count of emitted pairs per time unit (usually 1 second)
Sum float64 // The sum of values
SumSq float64 // The sum of squared values
Min float64 // Minimum value
@@ -105,7 +106,7 @@ func (a *AggregateSample) Ingest(v float64, rateDenom float64) {
if v > a.Max || a.Count == 1 {
a.Max = v
}
a.Rate = float64(a.Count)/rateDenom
a.Rate = float64(a.Count) / rateDenom
a.LastUpdated = time.Now()
}
@@ -120,6 +121,24 @@ func (a *AggregateSample) String() string {
}
}
// NewInmemSinkFromURL creates an InmemSink from a URL. It is used
// (and tested) from NewMetricSinkFromURL.
func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
params := u.Query()
interval, err := time.ParseDuration(params.Get("interval"))
if err != nil {
return nil, fmt.Errorf("Bad 'interval' param: %s", err)
}
retain, err := time.ParseDuration(params.Get("retain"))
if err != nil {
return nil, fmt.Errorf("Bad 'retain' param: %s", err)
}
return NewInmemSink(interval, retain), nil
}
// NewInmemSink is used to construct a new in-memory sink.
// Uses an aggregation interval and maximum retention period.
func NewInmemSink(interval, retain time.Duration) *InmemSink {
@@ -128,7 +147,7 @@ func NewInmemSink(interval, retain time.Duration) *InmemSink {
interval: interval,
retain: retain,
maxIntervals: int(retain / interval),
rateDenom: float64(interval.Nanoseconds()) / float64(rateTimeUnit.Nanoseconds()),
rateDenom: float64(interval.Nanoseconds()) / float64(rateTimeUnit.Nanoseconds()),
}
i.intervals = make([]*IntervalMetrics, 0, i.maxIntervals)
return i

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

@@ -2,6 +2,8 @@ package metrics
import (
"math"
"net/url"
"strings"
"testing"
"time"
)
@@ -99,9 +101,78 @@ func TestInmemSink(t *testing.T) {
}
}
func TestNewInmemSinkFromURL(t *testing.T) {
for _, tc := range []struct {
desc string
input string
expectErr string
expectInterval time.Duration
expectRetain time.Duration
}{
{
desc: "interval and duration are set via query params",
input: "inmem://?interval=11s&retain=22s",
expectInterval: duration(t, "11s"),
expectRetain: duration(t, "22s"),
},
{
desc: "interval is required",
input: "inmem://?retain=22s",
expectErr: "Bad 'interval' param",
},
{
desc: "interval must be a duration",
input: "inmem://?retain=30s&interval=HIYA",
expectErr: "Bad 'interval' param",
},
{
desc: "retain is required",
input: "inmem://?interval=30s",
expectErr: "Bad 'retain' param",
},
{
desc: "retain must be a valid duration",
input: "inmem://?interval=30s&retain=HELLO",
expectErr: "Bad 'retain' param",
},
} {
t.Run(tc.desc, func(t *testing.T) {
u, err := url.Parse(tc.input)
if err != nil {
t.Fatalf("error parsing URL: %s", err)
}
ms, err := NewInmemSinkFromURL(u)
if tc.expectErr != "" {
if !strings.Contains(err.Error(), tc.expectErr) {
t.Fatalf("expected err: %q, to contain: %q", err, tc.expectErr)
}
} else {
if err != nil {
t.Fatalf("unexpected err: %s", err)
}
is := ms.(*InmemSink)
if is.interval != tc.expectInterval {
t.Fatalf("expected interval %s, got: %s", tc.expectInterval, is.interval)
}
if is.retain != tc.expectRetain {
t.Fatalf("expected retain %s, got: %s", tc.expectRetain, is.retain)
}
}
})
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func duration(t *testing.T, s string) time.Duration {
dur, err := time.ParseDuration(s)
if err != nil {
t.Fatalf("error parsing duration: %s", err)
}
return dur
}

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

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

@@ -1,5 +1,10 @@
package metrics
import (
"fmt"
"net/url"
)
// The MetricSink interface is used to transmit metrics information
// to an external system
type MetricSink interface {
@@ -50,3 +55,43 @@ func (fh FanoutSink) AddSample(key []string, val float32) {
s.AddSample(key, val)
}
}
// sinkURLFactoryFunc is an generic interface around the *SinkFromURL() function provided
// by each sink type
type sinkURLFactoryFunc func(*url.URL) (MetricSink, error)
// sinkRegistry supports the generic NewMetricSink function by mapping URL
// schemes to metric sink factory functions
var sinkRegistry = map[string]sinkURLFactoryFunc{
"statsd": NewStatsdSinkFromURL,
"statsite": NewStatsiteSinkFromURL,
"inmem": NewInmemSinkFromURL,
}
// NewMetricSinkFromURL allows a generic URL input to configure any of the
// supported sinks. The scheme of the URL identifies the type of the sink, the
// and query parameters are used to set options.
//
// "statsd://" - Initializes a StatsdSink. The host and port are passed through
// as the "addr" of the sink
//
// "statsite://" - Initializes a StatsiteSink. The host and port become the
// "addr" of the sink
//
// "inmem://" - Initializes an InmemSink. The host and port are ignored. The
// "interval" and "duration" query parameters must be specified with valid
// durations, see NewInmemSink for details.
func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
u, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
sinkURLFactoryFunc := sinkRegistry[u.Scheme]
if sinkURLFactoryFunc == nil {
return nil, fmt.Errorf(
"cannot create metric sink, unrecognized sink name: %q", u.Scheme)
}
return sinkURLFactoryFunc(u)
}

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

@@ -2,6 +2,7 @@ package metrics
import (
"reflect"
"strings"
"testing"
)
@@ -118,3 +119,50 @@ func TestFanoutSink_Sample(t *testing.T) {
t.Fatalf("val not equal")
}
}
func TestNewMetricSinkFromURL(t *testing.T) {
for _, tc := range []struct {
desc string
input string
expect reflect.Type
expectErr string
}{
{
desc: "statsd scheme yields a StatsdSink",
input: "statsd://someserver:123",
expect: reflect.TypeOf(&StatsdSink{}),
},
{
desc: "statsite scheme yields a StatsiteSink",
input: "statsite://someserver:123",
expect: reflect.TypeOf(&StatsiteSink{}),
},
{
desc: "inmem scheme yields an InmemSink",
input: "inmem://?interval=30s&retain=30s",
expect: reflect.TypeOf(&InmemSink{}),
},
{
desc: "unknown scheme yields an error",
input: "notasink://whatever",
expectErr: "unrecognized sink name: \"notasink\"",
},
} {
t.Run(tc.desc, func(t *testing.T) {
ms, err := NewMetricSinkFromURL(tc.input)
if tc.expectErr != "" {
if !strings.Contains(err.Error(), tc.expectErr) {
t.Fatalf("expected err: %q to contain: %q", err, tc.expectErr)
}
} else {
if err != nil {
t.Fatalf("unexpected err: %s", err)
}
got := reflect.TypeOf(ms)
if got != tc.expect {
t.Fatalf("expected return type to be %v, got: %v", tc.expect, got)
}
}
})
}
}

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

@@ -2,6 +2,7 @@ package metrics
import (
"os"
"sync/atomic"
"time"
)
@@ -25,11 +26,11 @@ type Metrics struct {
}
// Shared global metrics instance
var globalMetrics *Metrics
var globalMetrics atomic.Value // *Metrics
func init() {
// Initialize to a blackhole sink to avoid errors
globalMetrics = &Metrics{sink: &BlackholeSink{}}
globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
}
// DefaultConfig provides a sane default configuration
@@ -68,28 +69,28 @@ func New(conf *Config, sink MetricSink) (*Metrics, error) {
func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
metrics, err := New(conf, sink)
if err == nil {
globalMetrics = metrics
globalMetrics.Store(metrics)
}
return metrics, err
}
// Proxy all the methods to the globalMetrics instance
func SetGauge(key []string, val float32) {
globalMetrics.SetGauge(key, val)
globalMetrics.Load().(*Metrics).SetGauge(key, val)
}
func EmitKey(key []string, val float32) {
globalMetrics.EmitKey(key, val)
globalMetrics.Load().(*Metrics).EmitKey(key, val)
}
func IncrCounter(key []string, val float32) {
globalMetrics.IncrCounter(key, val)
globalMetrics.Load().(*Metrics).IncrCounter(key, val)
}
func AddSample(key []string, val float32) {
globalMetrics.AddSample(key, val)
globalMetrics.Load().(*Metrics).AddSample(key, val)
}
func MeasureSince(key []string, start time.Time) {
globalMetrics.MeasureSince(key, start)
globalMetrics.Load().(*Metrics).MeasureSince(key, start)
}

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

@@ -1,7 +1,10 @@
package metrics
import (
"io/ioutil"
"log"
"reflect"
"sync/atomic"
"testing"
"time"
)
@@ -27,84 +30,70 @@ func TestDefaultConfig(t *testing.T) {
t.Fatalf("bad interval")
}
}
func Test_GlobalMetrics_SetGauge(t *testing.T) {
m := &MockSink{}
globalMetrics = &Metrics{sink: m}
k := []string{"test"}
v := float32(42.0)
SetGauge(k, v)
if !reflect.DeepEqual(m.keys[0], k) {
t.Fatalf("key not equal")
func Test_GlobalMetrics(t *testing.T) {
var tests = []struct {
desc string
key []string
val float32
fn func([]string, float32)
}{
{"SetGauge", []string{"test"}, 42, SetGauge},
{"EmitKey", []string{"test"}, 42, EmitKey},
{"IncrCounter", []string{"test"}, 42, IncrCounter},
{"AddSample", []string{"test"}, 42, AddSample},
}
if !reflect.DeepEqual(m.vals[0], v) {
t.Fatalf("val not equal")
}
}
func Test_GlobalMetrics_EmitKey(t *testing.T) {
m := &MockSink{}
globalMetrics = &Metrics{sink: m}
k := []string{"test"}
v := float32(42.0)
EmitKey(k, v)
if !reflect.DeepEqual(m.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m.vals[0], v) {
t.Fatalf("val not equal")
}
}
func Test_GlobalMetrics_IncrCounter(t *testing.T) {
m := &MockSink{}
globalMetrics = &Metrics{sink: m}
k := []string{"test"}
v := float32(42.0)
IncrCounter(k, v)
if !reflect.DeepEqual(m.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m.vals[0], v) {
t.Fatalf("val not equal")
}
}
func Test_GlobalMetrics_AddSample(t *testing.T) {
m := &MockSink{}
globalMetrics = &Metrics{sink: m}
k := []string{"test"}
v := float32(42.0)
AddSample(k, v)
if !reflect.DeepEqual(m.keys[0], k) {
t.Fatalf("key not equal")
}
if !reflect.DeepEqual(m.vals[0], v) {
t.Fatalf("val not equal")
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
s := &MockSink{}
globalMetrics.Store(&Metrics{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)
}
if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) {
t.Fatalf("got val %s want %s", got, want)
}
})
}
}
func Test_GlobalMetrics_MeasureSince(t *testing.T) {
m := &MockSink{}
globalMetrics = &Metrics{sink: m}
globalMetrics.TimerGranularity = time.Millisecond
s := &MockSink{}
m := &Metrics{sink: s, Config: Config{TimerGranularity: time.Millisecond}}
globalMetrics.Store(m)
k := []string{"test"}
now := time.Now()
MeasureSince(k, now)
if !reflect.DeepEqual(m.keys[0], k) {
if !reflect.DeepEqual(s.keys[0], k) {
t.Fatalf("key not equal")
}
if m.vals[0] > 0.1 {
t.Fatalf("val too large %v", m.vals[0])
if s.vals[0] > 0.1 {
t.Fatalf("val too large %v", s.vals[0])
}
}
// Benchmark_GlobalMetrics_Direct/direct-8 5000000 278 ns/op
// Benchmark_GlobalMetrics_Direct/atomic.Value-8 5000000 235 ns/op
func Benchmark_GlobalMetrics_Direct(b *testing.B) {
log.SetOutput(ioutil.Discard)
s := &MockSink{}
m := &Metrics{sink: s}
var v atomic.Value
v.Store(m)
k := []string{"test"}
b.Run("direct", func(b *testing.B) {
for i := 0; i < b.N; i++ {
m.IncrCounter(k, 1)
}
})
b.Run("atomic.Value", func(b *testing.B) {
for i := 0; i < b.N; i++ {
v.Load().(*Metrics).IncrCounter(k, 1)
}
})
// do something with m so that the compiler does not optimize this away
b.Logf("%d", m.lastNumGC)
}

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

@@ -5,6 +5,7 @@ import (
"fmt"
"log"
"net"
"net/url"
"strings"
"time"
)
@@ -23,6 +24,12 @@ type StatsdSink struct {
metricQueue chan string
}
// NewStatsdSinkFromURL creates an StatsdSink from a URL. It is used
// (and tested) from NewMetricSinkFromURL.
func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
return NewStatsdSink(u.Host)
}
// NewStatsdSink is used to create a new StatsdSink
func NewStatsdSink(addr string) (*StatsdSink, error) {
s := &StatsdSink{

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

@@ -4,6 +4,8 @@ import (
"bufio"
"bytes"
"net"
"net/url"
"strings"
"testing"
"time"
)
@@ -103,3 +105,44 @@ func TestStatsd_Conn(t *testing.T) {
t.Fatalf("timeout")
}
}
func TestNewStatsdSinkFromURL(t *testing.T) {
for _, tc := range []struct {
desc string
input string
expectErr string
expectAddr string
}{
{
desc: "address is populated",
input: "statsd://statsd.service.consul",
expectAddr: "statsd.service.consul",
},
{
desc: "address includes port",
input: "statsd://statsd.service.consul:1234",
expectAddr: "statsd.service.consul:1234",
},
} {
t.Run(tc.desc, func(t *testing.T) {
u, err := url.Parse(tc.input)
if err != nil {
t.Fatalf("error parsing URL: %s", err)
}
ms, err := NewStatsdSinkFromURL(u)
if tc.expectErr != "" {
if !strings.Contains(err.Error(), tc.expectErr) {
t.Fatalf("expected err: %q, to contain: %q", err, tc.expectErr)
}
} else {
if err != nil {
t.Fatalf("unexpected err: %s", err)
}
is := ms.(*StatsdSink)
if is.addr != tc.expectAddr {
t.Fatalf("expected addr %s, got: %s", tc.expectAddr, is.addr)
}
}
})
}
}

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

@@ -5,6 +5,7 @@ import (
"fmt"
"log"
"net"
"net/url"
"strings"
"time"
)
@@ -16,6 +17,12 @@ const (
flushInterval = 100 * time.Millisecond
)
// NewStatsiteSinkFromURL creates an StatsiteSink from a URL. It is used
// (and tested) from NewMetricSinkFromURL.
func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
return NewStatsiteSink(u.Host)
}
// StatsiteSink provides a MetricSink that can be used with a
// statsite metrics server
type StatsiteSink struct {

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

@@ -3,6 +3,8 @@ package metrics
import (
"bufio"
"net"
"net/url"
"strings"
"testing"
"time"
)
@@ -99,3 +101,44 @@ func TestStatsite_Conn(t *testing.T) {
t.Fatalf("timeout")
}
}
func TestNewStatsiteSinkFromURL(t *testing.T) {
for _, tc := range []struct {
desc string
input string
expectErr string
expectAddr string
}{
{
desc: "address is populated",
input: "statsd://statsd.service.consul",
expectAddr: "statsd.service.consul",
},
{
desc: "address includes port",
input: "statsd://statsd.service.consul:1234",
expectAddr: "statsd.service.consul:1234",
},
} {
t.Run(tc.desc, func(t *testing.T) {
u, err := url.Parse(tc.input)
if err != nil {
t.Fatalf("error parsing URL: %s", err)
}
ms, err := NewStatsiteSinkFromURL(u)
if tc.expectErr != "" {
if !strings.Contains(err.Error(), tc.expectErr) {
t.Fatalf("expected err: %q, to contain: %q", err, tc.expectErr)
}
} else {
if err != nil {
t.Fatalf("unexpected err: %s", err)
}
is := ms.(*StatsiteSink)
if is.addr != tc.expectAddr {
t.Fatalf("expected addr %s, got: %s", tc.expectAddr, is.addr)
}
}
})
}
}