Scott Baker | eee8dd8 | 2019-09-24 12:52:34 -0700 | [diff] [blame] | 1 | package metrics |
| 2 | |
| 3 | import ( |
| 4 | "bufio" |
| 5 | "fmt" |
| 6 | "log" |
| 7 | "net" |
| 8 | "strconv" |
| 9 | "strings" |
| 10 | "time" |
| 11 | ) |
| 12 | |
| 13 | // GraphiteConfig provides a container with configuration parameters for |
| 14 | // the Graphite exporter |
| 15 | type GraphiteConfig struct { |
| 16 | Addr *net.TCPAddr // Network address to connect to |
| 17 | Registry Registry // Registry to be exported |
| 18 | FlushInterval time.Duration // Flush interval |
| 19 | DurationUnit time.Duration // Time conversion unit for durations |
| 20 | Prefix string // Prefix to be prepended to metric names |
| 21 | Percentiles []float64 // Percentiles to export from timers and histograms |
| 22 | } |
| 23 | |
| 24 | // Graphite is a blocking exporter function which reports metrics in r |
| 25 | // to a graphite server located at addr, flushing them every d duration |
| 26 | // and prepending metric names with prefix. |
| 27 | func Graphite(r Registry, d time.Duration, prefix string, addr *net.TCPAddr) { |
| 28 | GraphiteWithConfig(GraphiteConfig{ |
| 29 | Addr: addr, |
| 30 | Registry: r, |
| 31 | FlushInterval: d, |
| 32 | DurationUnit: time.Nanosecond, |
| 33 | Prefix: prefix, |
| 34 | Percentiles: []float64{0.5, 0.75, 0.95, 0.99, 0.999}, |
| 35 | }) |
| 36 | } |
| 37 | |
| 38 | // GraphiteWithConfig is a blocking exporter function just like Graphite, |
| 39 | // but it takes a GraphiteConfig instead. |
| 40 | func GraphiteWithConfig(c GraphiteConfig) { |
| 41 | log.Printf("WARNING: This go-metrics client has been DEPRECATED! It has been moved to https://github.com/cyberdelia/go-metrics-graphite and will be removed from rcrowley/go-metrics on August 12th 2015") |
| 42 | for _ = range time.Tick(c.FlushInterval) { |
| 43 | if err := graphite(&c); nil != err { |
| 44 | log.Println(err) |
| 45 | } |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | // GraphiteOnce performs a single submission to Graphite, returning a |
| 50 | // non-nil error on failed connections. This can be used in a loop |
| 51 | // similar to GraphiteWithConfig for custom error handling. |
| 52 | func GraphiteOnce(c GraphiteConfig) error { |
| 53 | log.Printf("WARNING: This go-metrics client has been DEPRECATED! It has been moved to https://github.com/cyberdelia/go-metrics-graphite and will be removed from rcrowley/go-metrics on August 12th 2015") |
| 54 | return graphite(&c) |
| 55 | } |
| 56 | |
| 57 | func graphite(c *GraphiteConfig) error { |
| 58 | now := time.Now().Unix() |
| 59 | du := float64(c.DurationUnit) |
| 60 | conn, err := net.DialTCP("tcp", nil, c.Addr) |
| 61 | if nil != err { |
| 62 | return err |
| 63 | } |
| 64 | defer conn.Close() |
| 65 | w := bufio.NewWriter(conn) |
| 66 | c.Registry.Each(func(name string, i interface{}) { |
| 67 | switch metric := i.(type) { |
| 68 | case Counter: |
| 69 | fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Count(), now) |
| 70 | case Gauge: |
| 71 | fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now) |
| 72 | case GaugeFloat64: |
| 73 | fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Value(), now) |
| 74 | case Histogram: |
| 75 | h := metric.Snapshot() |
| 76 | ps := h.Percentiles(c.Percentiles) |
| 77 | fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, h.Count(), now) |
| 78 | fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, h.Min(), now) |
| 79 | fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, h.Max(), now) |
| 80 | fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, h.Mean(), now) |
| 81 | fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, h.StdDev(), now) |
| 82 | for psIdx, psKey := range c.Percentiles { |
| 83 | key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) |
| 84 | fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now) |
| 85 | } |
| 86 | case Meter: |
| 87 | m := metric.Snapshot() |
| 88 | fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, m.Count(), now) |
| 89 | fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, m.Rate1(), now) |
| 90 | fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, m.Rate5(), now) |
| 91 | fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, m.Rate15(), now) |
| 92 | fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, m.RateMean(), now) |
| 93 | case Timer: |
| 94 | t := metric.Snapshot() |
| 95 | ps := t.Percentiles(c.Percentiles) |
| 96 | fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, t.Count(), now) |
| 97 | fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, t.Min()/int64(du), now) |
| 98 | fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, t.Max()/int64(du), now) |
| 99 | fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, t.Mean()/du, now) |
| 100 | fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, t.StdDev()/du, now) |
| 101 | for psIdx, psKey := range c.Percentiles { |
| 102 | key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) |
| 103 | fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now) |
| 104 | } |
| 105 | fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, t.Rate1(), now) |
| 106 | fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, t.Rate5(), now) |
| 107 | fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, t.Rate15(), now) |
| 108 | fmt.Fprintf(w, "%s.%s.mean-rate %.2f %d\n", c.Prefix, name, t.RateMean(), now) |
| 109 | } |
| 110 | w.Flush() |
| 111 | }) |
| 112 | return nil |
| 113 | } |