diff options
Diffstat (limited to 'vendor/github.com/prometheus/client_golang/prometheus/graphite')
-rw-r--r-- | vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge.go | 280 | ||||
-rw-r--r-- | vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge_test.go | 309 |
2 files changed, 0 insertions, 589 deletions
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge.go b/vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge.go deleted file mode 100644 index 11533374b..000000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2016 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package graphite provides a bridge to push Prometheus metrics to a Graphite -// server. -package graphite - -import ( - "bufio" - "errors" - "fmt" - "io" - "net" - "sort" - "time" - - "github.com/prometheus/common/expfmt" - "github.com/prometheus/common/model" - "golang.org/x/net/context" - - dto "github.com/prometheus/client_model/go" - - "github.com/prometheus/client_golang/prometheus" -) - -const ( - defaultInterval = 15 * time.Second - millisecondsPerSecond = 1000 -) - -// HandlerErrorHandling defines how a Handler serving metrics will handle -// errors. -type HandlerErrorHandling int - -// These constants cause handlers serving metrics to behave as described if -// errors are encountered. -const ( - // Ignore errors and try to push as many metrics to Graphite as possible. - ContinueOnError HandlerErrorHandling = iota - - // Abort the push to Graphite upon the first error encountered. - AbortOnError -) - -// Config defines the Graphite bridge config. -type Config struct { - // The url to push data to. Required. - URL string - - // The prefix for the pushed Graphite metrics. Defaults to empty string. - Prefix string - - // The interval to use for pushing data to Graphite. Defaults to 15 seconds. - Interval time.Duration - - // The timeout for pushing metrics to Graphite. Defaults to 15 seconds. - Timeout time.Duration - - // The Gatherer to use for metrics. Defaults to prometheus.DefaultGatherer. - Gatherer prometheus.Gatherer - - // The logger that messages are written to. Defaults to no logging. - Logger Logger - - // ErrorHandling defines how errors are handled. Note that errors are - // logged regardless of the configured ErrorHandling provided Logger - // is not nil. - ErrorHandling HandlerErrorHandling -} - -// Bridge pushes metrics to the configured Graphite server. -type Bridge struct { - url string - prefix string - interval time.Duration - timeout time.Duration - - errorHandling HandlerErrorHandling - logger Logger - - g prometheus.Gatherer -} - -// Logger is the minimal interface Bridge needs for logging. Note that -// log.Logger from the standard library implements this interface, and it is -// easy to implement by custom loggers, if they don't do so already anyway. -type Logger interface { - Println(v ...interface{}) -} - -// NewBridge returns a pointer to a new Bridge struct. -func NewBridge(c *Config) (*Bridge, error) { - b := &Bridge{} - - if c.URL == "" { - return nil, errors.New("missing URL") - } - b.url = c.URL - - if c.Gatherer == nil { - b.g = prometheus.DefaultGatherer - } else { - b.g = c.Gatherer - } - - if c.Logger != nil { - b.logger = c.Logger - } - - if c.Prefix != "" { - b.prefix = c.Prefix - } - - var z time.Duration - if c.Interval == z { - b.interval = defaultInterval - } else { - b.interval = c.Interval - } - - if c.Timeout == z { - b.timeout = defaultInterval - } else { - b.timeout = c.Timeout - } - - b.errorHandling = c.ErrorHandling - - return b, nil -} - -// Run starts the event loop that pushes Prometheus metrics to Graphite at the -// configured interval. -func (b *Bridge) Run(ctx context.Context) { - ticker := time.NewTicker(b.interval) - defer ticker.Stop() - for { - select { - case <-ticker.C: - if err := b.Push(); err != nil && b.logger != nil { - b.logger.Println("error pushing to Graphite:", err) - } - case <-ctx.Done(): - return - } - } -} - -// Push pushes Prometheus metrics to the configured Graphite server. -func (b *Bridge) Push() error { - mfs, err := b.g.Gather() - if err != nil || len(mfs) == 0 { - switch b.errorHandling { - case AbortOnError: - return err - case ContinueOnError: - if b.logger != nil { - b.logger.Println("continue on error:", err) - } - default: - panic("unrecognized error handling value") - } - } - - conn, err := net.DialTimeout("tcp", b.url, b.timeout) - if err != nil { - return err - } - defer conn.Close() - - return writeMetrics(conn, mfs, b.prefix, model.Now()) -} - -func writeMetrics(w io.Writer, mfs []*dto.MetricFamily, prefix string, now model.Time) error { - vec, err := expfmt.ExtractSamples(&expfmt.DecodeOptions{ - Timestamp: now, - }, mfs...) - if err != nil { - return err - } - - buf := bufio.NewWriter(w) - for _, s := range vec { - if err := writeSanitized(buf, prefix); err != nil { - return err - } - if err := buf.WriteByte('.'); err != nil { - return err - } - if err := writeMetric(buf, s.Metric); err != nil { - return err - } - if _, err := fmt.Fprintf(buf, " %g %d\n", s.Value, int64(s.Timestamp)/millisecondsPerSecond); err != nil { - return err - } - if err := buf.Flush(); err != nil { - return err - } - } - - return nil -} - -func writeMetric(buf *bufio.Writer, m model.Metric) error { - metricName, hasName := m[model.MetricNameLabel] - numLabels := len(m) - 1 - if !hasName { - numLabels = len(m) - } - - labelStrings := make([]string, 0, numLabels) - for label, value := range m { - if label != model.MetricNameLabel { - labelStrings = append(labelStrings, fmt.Sprintf("%s %s", string(label), string(value))) - } - } - - var err error - switch numLabels { - case 0: - if hasName { - return writeSanitized(buf, string(metricName)) - } - default: - sort.Strings(labelStrings) - if err = writeSanitized(buf, string(metricName)); err != nil { - return err - } - for _, s := range labelStrings { - if err = buf.WriteByte('.'); err != nil { - return err - } - if err = writeSanitized(buf, s); err != nil { - return err - } - } - } - return nil -} - -func writeSanitized(buf *bufio.Writer, s string) error { - prevUnderscore := false - - for _, c := range s { - c = replaceInvalidRune(c) - if c == '_' { - if prevUnderscore { - continue - } - prevUnderscore = true - } else { - prevUnderscore = false - } - if _, err := buf.WriteRune(c); err != nil { - return err - } - } - - return nil -} - -func replaceInvalidRune(c rune) rune { - if c == ' ' { - return '.' - } - if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == ':' || (c >= '0' && c <= '9')) { - return '_' - } - return c -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge_test.go b/vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge_test.go deleted file mode 100644 index c2b274c6a..000000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge_test.go +++ /dev/null @@ -1,309 +0,0 @@ -package graphite - -import ( - "bufio" - "bytes" - "io" - "log" - "net" - "os" - "regexp" - "testing" - "time" - - "github.com/prometheus/common/model" - "golang.org/x/net/context" - - "github.com/prometheus/client_golang/prometheus" -) - -func TestSanitize(t *testing.T) { - testCases := []struct { - in, out string - }{ - {in: "hello", out: "hello"}, - {in: "hE/l1o", out: "hE_l1o"}, - {in: "he,*ll(.o", out: "he_ll_o"}, - {in: "hello_there%^&", out: "hello_there_"}, - } - - var buf bytes.Buffer - w := bufio.NewWriter(&buf) - - for i, tc := range testCases { - if err := writeSanitized(w, tc.in); err != nil { - t.Fatalf("write failed: %v", err) - } - if err := w.Flush(); err != nil { - t.Fatalf("flush failed: %v", err) - } - - if want, got := tc.out, buf.String(); want != got { - t.Fatalf("test case index %d: got sanitized string %s, want %s", i, got, want) - } - - buf.Reset() - } -} - -func TestWriteSummary(t *testing.T) { - sumVec := prometheus.NewSummaryVec( - prometheus.SummaryOpts{ - Name: "name", - Help: "docstring", - ConstLabels: prometheus.Labels{"constname": "constvalue"}, - Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, - }, - []string{"labelname"}, - ) - - sumVec.WithLabelValues("val1").Observe(float64(10)) - sumVec.WithLabelValues("val1").Observe(float64(20)) - sumVec.WithLabelValues("val1").Observe(float64(30)) - sumVec.WithLabelValues("val2").Observe(float64(20)) - sumVec.WithLabelValues("val2").Observe(float64(30)) - sumVec.WithLabelValues("val2").Observe(float64(40)) - - reg := prometheus.NewRegistry() - reg.MustRegister(sumVec) - - mfs, err := reg.Gather() - if err != nil { - t.Fatalf("error: %v", err) - } - - now := model.Time(1477043083) - var buf bytes.Buffer - err = writeMetrics(&buf, mfs, "prefix", now) - if err != nil { - t.Fatalf("error: %v", err) - } - - want := `prefix.name.constname.constvalue.labelname.val1.quantile.0_5 20 1477043 -prefix.name.constname.constvalue.labelname.val1.quantile.0_9 30 1477043 -prefix.name.constname.constvalue.labelname.val1.quantile.0_99 30 1477043 -prefix.name_sum.constname.constvalue.labelname.val1 60 1477043 -prefix.name_count.constname.constvalue.labelname.val1 3 1477043 -prefix.name.constname.constvalue.labelname.val2.quantile.0_5 30 1477043 -prefix.name.constname.constvalue.labelname.val2.quantile.0_9 40 1477043 -prefix.name.constname.constvalue.labelname.val2.quantile.0_99 40 1477043 -prefix.name_sum.constname.constvalue.labelname.val2 90 1477043 -prefix.name_count.constname.constvalue.labelname.val2 3 1477043 -` - - if got := buf.String(); want != got { - t.Fatalf("wanted \n%s\n, got \n%s\n", want, got) - } -} - -func TestWriteHistogram(t *testing.T) { - histVec := prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "name", - Help: "docstring", - ConstLabels: prometheus.Labels{"constname": "constvalue"}, - Buckets: []float64{0.01, 0.02, 0.05, 0.1}, - }, - []string{"labelname"}, - ) - - histVec.WithLabelValues("val1").Observe(float64(10)) - histVec.WithLabelValues("val1").Observe(float64(20)) - histVec.WithLabelValues("val1").Observe(float64(30)) - histVec.WithLabelValues("val2").Observe(float64(20)) - histVec.WithLabelValues("val2").Observe(float64(30)) - histVec.WithLabelValues("val2").Observe(float64(40)) - - reg := prometheus.NewRegistry() - reg.MustRegister(histVec) - - mfs, err := reg.Gather() - if err != nil { - t.Fatalf("error: %v", err) - } - - now := model.Time(1477043083) - var buf bytes.Buffer - err = writeMetrics(&buf, mfs, "prefix", now) - if err != nil { - t.Fatalf("error: %v", err) - } - - want := `prefix.name_bucket.constname.constvalue.labelname.val1.le.0_01 0 1477043 -prefix.name_bucket.constname.constvalue.labelname.val1.le.0_02 0 1477043 -prefix.name_bucket.constname.constvalue.labelname.val1.le.0_05 0 1477043 -prefix.name_bucket.constname.constvalue.labelname.val1.le.0_1 0 1477043 -prefix.name_sum.constname.constvalue.labelname.val1 60 1477043 -prefix.name_count.constname.constvalue.labelname.val1 3 1477043 -prefix.name_bucket.constname.constvalue.labelname.val1.le._Inf 3 1477043 -prefix.name_bucket.constname.constvalue.labelname.val2.le.0_01 0 1477043 -prefix.name_bucket.constname.constvalue.labelname.val2.le.0_02 0 1477043 -prefix.name_bucket.constname.constvalue.labelname.val2.le.0_05 0 1477043 -prefix.name_bucket.constname.constvalue.labelname.val2.le.0_1 0 1477043 -prefix.name_sum.constname.constvalue.labelname.val2 90 1477043 -prefix.name_count.constname.constvalue.labelname.val2 3 1477043 -prefix.name_bucket.constname.constvalue.labelname.val2.le._Inf 3 1477043 -` - if got := buf.String(); want != got { - t.Fatalf("wanted \n%s\n, got \n%s\n", want, got) - } -} - -func TestToReader(t *testing.T) { - cntVec := prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "name", - Help: "docstring", - ConstLabels: prometheus.Labels{"constname": "constvalue"}, - }, - []string{"labelname"}, - ) - cntVec.WithLabelValues("val1").Inc() - cntVec.WithLabelValues("val2").Inc() - - reg := prometheus.NewRegistry() - reg.MustRegister(cntVec) - - want := `prefix.name.constname.constvalue.labelname.val1 1 1477043 -prefix.name.constname.constvalue.labelname.val2 1 1477043 -` - mfs, err := reg.Gather() - if err != nil { - t.Fatalf("error: %v", err) - } - - now := model.Time(1477043083) - var buf bytes.Buffer - err = writeMetrics(&buf, mfs, "prefix", now) - if err != nil { - t.Fatalf("error: %v", err) - } - - if got := buf.String(); want != got { - t.Fatalf("wanted \n%s\n, got \n%s\n", want, got) - } -} - -func TestPush(t *testing.T) { - reg := prometheus.NewRegistry() - cntVec := prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "name", - Help: "docstring", - ConstLabels: prometheus.Labels{"constname": "constvalue"}, - }, - []string{"labelname"}, - ) - cntVec.WithLabelValues("val1").Inc() - cntVec.WithLabelValues("val2").Inc() - reg.MustRegister(cntVec) - - host := "localhost" - port := ":56789" - b, err := NewBridge(&Config{ - URL: host + port, - Gatherer: reg, - Prefix: "prefix", - }) - if err != nil { - t.Fatalf("error creating bridge: %v", err) - } - - nmg, err := newMockGraphite(port) - if err != nil { - t.Fatalf("error creating mock graphite: %v", err) - } - defer nmg.Close() - - err = b.Push() - if err != nil { - t.Fatalf("error pushing: %v", err) - } - - wants := []string{ - "prefix.name.constname.constvalue.labelname.val1 1", - "prefix.name.constname.constvalue.labelname.val2 1", - } - - select { - case got := <-nmg.readc: - for _, want := range wants { - matched, err := regexp.MatchString(want, got) - if err != nil { - t.Fatalf("error pushing: %v", err) - } - if !matched { - t.Fatalf("missing metric:\nno match for %s received by server:\n%s", want, got) - } - } - return - case err := <-nmg.errc: - t.Fatalf("error reading push: %v", err) - case <-time.After(50 * time.Millisecond): - t.Fatalf("no result from graphite server") - } -} - -func newMockGraphite(port string) (*mockGraphite, error) { - readc := make(chan string) - errc := make(chan error) - ln, err := net.Listen("tcp", port) - if err != nil { - return nil, err - } - - go func() { - conn, err := ln.Accept() - if err != nil { - errc <- err - } - var b bytes.Buffer - io.Copy(&b, conn) - readc <- b.String() - }() - - return &mockGraphite{ - readc: readc, - errc: errc, - Listener: ln, - }, nil -} - -type mockGraphite struct { - readc chan string - errc chan error - - net.Listener -} - -func ExampleBridge() { - b, err := NewBridge(&Config{ - URL: "graphite.example.org:3099", - Gatherer: prometheus.DefaultGatherer, - Prefix: "prefix", - Interval: 15 * time.Second, - Timeout: 10 * time.Second, - ErrorHandling: AbortOnError, - Logger: log.New(os.Stdout, "graphite bridge: ", log.Lshortfile), - }) - if err != nil { - panic(err) - } - - go func() { - // Start something in a goroutine that uses metrics. - }() - - // Push initial metrics to Graphite. Fail fast if the push fails. - if err := b.Push(); err != nil { - panic(err) - } - - // Create a Context to control stopping the Run() loop that pushes - // metrics to Graphite. - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // Start pushing metrics to Graphite in the Run() loop. - b.Run(ctx) -} |