1package metrics 2 3import ( 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 15type 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. 27func 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. 40func GraphiteWithConfig(c GraphiteConfig) { 41 for _ = range time.Tick(c.FlushInterval) { 42 if err := graphite(&c); nil != err { 43 log.Println(err) 44 } 45 } 46} 47 48func graphite(c *GraphiteConfig) error { 49 now := time.Now().Unix() 50 du := float64(c.DurationUnit) 51 conn, err := net.DialTCP("tcp", nil, c.Addr) 52 if nil != err { 53 return err 54 } 55 defer conn.Close() 56 w := bufio.NewWriter(conn) 57 c.Registry.Each(func(name string, i interface{}) { 58 switch metric := i.(type) { 59 case Counter: 60 fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Count(), now) 61 case Gauge: 62 fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now) 63 case GaugeFloat64: 64 fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Value(), now) 65 case Histogram: 66 h := metric.Snapshot() 67 ps := h.Percentiles(c.Percentiles) 68 fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, h.Count(), now) 69 fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, h.Min(), now) 70 fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, h.Max(), now) 71 fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, h.Mean(), now) 72 fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, h.StdDev(), now) 73 for psIdx, psKey := range c.Percentiles { 74 key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) 75 fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now) 76 } 77 case Meter: 78 m := metric.Snapshot() 79 fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, m.Count(), now) 80 fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, m.Rate1(), now) 81 fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, m.Rate5(), now) 82 fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, m.Rate15(), now) 83 fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, m.RateMean(), now) 84 case Timer: 85 t := metric.Snapshot() 86 ps := t.Percentiles(c.Percentiles) 87 fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, t.Count(), now) 88 fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, int64(du)*t.Min(), now) 89 fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, int64(du)*t.Max(), now) 90 fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, du*t.Mean(), now) 91 fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, du*t.StdDev(), now) 92 for psIdx, psKey := range c.Percentiles { 93 key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) 94 fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now) 95 } 96 fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, t.Rate1(), now) 97 fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, t.Rate5(), now) 98 fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, t.Rate15(), now) 99 fmt.Fprintf(w, "%s.%s.mean-rate %.2f %d\n", c.Prefix, name, t.RateMean(), now) 100 } 101 w.Flush() 102 }) 103 return nil 104} 105