From d103ed6ca97ca5a2669f6cf5fe4b3d2a9c945f26 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Wed, 17 May 2017 16:51:25 -0400 Subject: Upgrading server dependancies (#6431) --- .../armon/go-metrics/circonus/circonus.go | 92 +++++++++++++ .../armon/go-metrics/circonus/circonus_test.go | 153 +++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 vendor/github.com/armon/go-metrics/circonus/circonus.go create mode 100644 vendor/github.com/armon/go-metrics/circonus/circonus_test.go (limited to 'vendor/github.com/armon/go-metrics/circonus') diff --git a/vendor/github.com/armon/go-metrics/circonus/circonus.go b/vendor/github.com/armon/go-metrics/circonus/circonus.go new file mode 100644 index 000000000..c6e3974b5 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/circonus/circonus.go @@ -0,0 +1,92 @@ +// Circonus Metrics Sink + +package circonus + +import ( + "strings" + + cgm "github.com/circonus-labs/circonus-gometrics" +) + +// CirconusSink provides an interface to forward metrics to Circonus with +// automatic check creation and metric management +type CirconusSink struct { + metrics *cgm.CirconusMetrics +} + +// Config options for CirconusSink +// See https://github.com/circonus-labs/circonus-gometrics for configuration options +type Config cgm.Config + +// NewCirconusSink - create new metric sink for circonus +// +// one of the following must be supplied: +// - API Token - search for an existing check or create a new check +// - API Token + Check Id - the check identified by check id will be used +// - API Token + Check Submission URL - the check identified by the submission url will be used +// - Check Submission URL - the check identified by the submission url will be used +// metric management will be *disabled* +// +// Note: If submission url is supplied w/o an api token, the public circonus ca cert will be used +// to verify the broker for metrics submission. +func NewCirconusSink(cc *Config) (*CirconusSink, error) { + cfg := cgm.Config{} + if cc != nil { + cfg = cgm.Config(*cc) + } + + metrics, err := cgm.NewCirconusMetrics(&cfg) + if err != nil { + return nil, err + } + + return &CirconusSink{ + metrics: metrics, + }, nil +} + +// Start submitting metrics to Circonus (flush every SubmitInterval) +func (s *CirconusSink) Start() { + s.metrics.Start() +} + +// Flush manually triggers metric submission to Circonus +func (s *CirconusSink) Flush() { + s.metrics.Flush() +} + +// SetGauge sets value for a gauge metric +func (s *CirconusSink) SetGauge(key []string, val float32) { + flatKey := s.flattenKey(key) + s.metrics.SetGauge(flatKey, int64(val)) +} + +// EmitKey is not implemented in circonus +func (s *CirconusSink) EmitKey(key []string, val float32) { + // NOP +} + +// IncrCounter increments a counter metric +func (s *CirconusSink) IncrCounter(key []string, val float32) { + flatKey := s.flattenKey(key) + 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)) +} + +// Flattens key to Circonus metric name +func (s *CirconusSink) flattenKey(parts []string) string { + joined := strings.Join(parts, "`") + return strings.Map(func(r rune) rune { + switch r { + case ' ': + return '_' + default: + return r + } + }, joined) +} diff --git a/vendor/github.com/armon/go-metrics/circonus/circonus_test.go b/vendor/github.com/armon/go-metrics/circonus/circonus_test.go new file mode 100644 index 000000000..234a3cb89 --- /dev/null +++ b/vendor/github.com/armon/go-metrics/circonus/circonus_test.go @@ -0,0 +1,153 @@ +package circonus + +import ( + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" +) + +func TestNewCirconusSink(t *testing.T) { + + // test with invalid config (nil) + 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) + } + + // test w/submission url and w/o token + cfg := &Config{} + cfg.CheckManager.Check.SubmissionURL = "http://127.0.0.1:43191/" + _, err = NewCirconusSink(cfg) + if err != nil { + t.Errorf("Expected no error, got '%v'", err) + } + + // note: a test with a valid token is *not* done as it *will* create a + // check resulting in testing the api more than the circonus sink + // see circonus-gometrics/checkmgr/checkmgr_test.go for testing of api token +} + +func TestFlattenKey(t *testing.T) { + var testKeys = []struct { + input []string + expected string + }{ + {[]string{"a", "b", "c"}, "a`b`c"}, + {[]string{"a-a", "b_b", "c/c"}, "a-a`b_b`c/c"}, + {[]string{"spaces must", "flatten", "to", "underscores"}, "spaces_must`flatten`to`underscores"}, + } + + c := &CirconusSink{} + + for _, test := range testKeys { + if actual := c.flattenKey(test.input); actual != test.expected { + t.Fatalf("Flattening %v failed, expected '%s' got '%s'", test.input, test.expected, actual) + } + } +} + +func fakeBroker(q chan string) *httptest.Server { + handler := func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + w.Header().Set("Content-Type", "application/json") + defer r.Body.Close() + body, err := ioutil.ReadAll(r.Body) + if err != nil { + q <- err.Error() + fmt.Fprintln(w, err.Error()) + } else { + q <- string(body) + fmt.Fprintln(w, `{"stats":1}`) + } + } + + return httptest.NewServer(http.HandlerFunc(handler)) +} + +func TestSetGauge(t *testing.T) { + q := make(chan string) + + server := fakeBroker(q) + defer server.Close() + + cfg := &Config{} + cfg.CheckManager.Check.SubmissionURL = server.URL + + cs, err := NewCirconusSink(cfg) + if err != nil { + t.Errorf("Expected no error, got '%v'", err) + } + + go func() { + cs.SetGauge([]string{"foo", "bar"}, 1) + cs.Flush() + }() + + expect := "{\"foo`bar\":{\"_type\":\"n\",\"_value\":1}}" + actual := <-q + + if actual != expect { + t.Errorf("Expected '%s', got '%s'", expect, actual) + + } +} + +func TestIncrCounter(t *testing.T) { + q := make(chan string) + + server := fakeBroker(q) + defer server.Close() + + cfg := &Config{} + cfg.CheckManager.Check.SubmissionURL = server.URL + + cs, err := NewCirconusSink(cfg) + if err != nil { + t.Errorf("Expected no error, got '%v'", err) + } + + go func() { + cs.IncrCounter([]string{"foo", "bar"}, 1) + cs.Flush() + }() + + expect := "{\"foo`bar\":{\"_type\":\"n\",\"_value\":1}}" + actual := <-q + + if actual != expect { + t.Errorf("Expected '%s', got '%s'", expect, actual) + + } +} + +func TestAddSample(t *testing.T) { + q := make(chan string) + + server := fakeBroker(q) + defer server.Close() + + cfg := &Config{} + cfg.CheckManager.Check.SubmissionURL = server.URL + + cs, err := NewCirconusSink(cfg) + if err != nil { + t.Errorf("Expected no error, got '%v'", err) + } + + go func() { + cs.AddSample([]string{"foo", "bar"}, 1) + cs.Flush() + }() + + expect := "{\"foo`bar\":{\"_type\":\"n\",\"_value\":[\"H[1.0e+00]=1\"]}}" + actual := <-q + + if actual != expect { + t.Errorf("Expected '%s', got '%s'", expect, actual) + + } +} -- cgit v1.2.3-1-g7c22