Scott Baker | 2d89798 | 2019-09-24 11:50:08 -0700 | [diff] [blame] | 1 | package metrics |
| 2 | |
| 3 | import ( |
| 4 | "bufio" |
| 5 | "fmt" |
| 6 | "log" |
| 7 | "net" |
| 8 | "os" |
| 9 | "strings" |
| 10 | "time" |
| 11 | ) |
| 12 | |
| 13 | var shortHostName string = "" |
| 14 | |
| 15 | // OpenTSDBConfig provides a container with configuration parameters for |
| 16 | // the OpenTSDB exporter |
| 17 | type OpenTSDBConfig struct { |
| 18 | Addr *net.TCPAddr // Network address to connect to |
| 19 | Registry Registry // Registry to be exported |
| 20 | FlushInterval time.Duration // Flush interval |
| 21 | DurationUnit time.Duration // Time conversion unit for durations |
| 22 | Prefix string // Prefix to be prepended to metric names |
| 23 | } |
| 24 | |
| 25 | // OpenTSDB is a blocking exporter function which reports metrics in r |
| 26 | // to a TSDB server located at addr, flushing them every d duration |
| 27 | // and prepending metric names with prefix. |
| 28 | func OpenTSDB(r Registry, d time.Duration, prefix string, addr *net.TCPAddr) { |
| 29 | OpenTSDBWithConfig(OpenTSDBConfig{ |
| 30 | Addr: addr, |
| 31 | Registry: r, |
| 32 | FlushInterval: d, |
| 33 | DurationUnit: time.Nanosecond, |
| 34 | Prefix: prefix, |
| 35 | }) |
| 36 | } |
| 37 | |
| 38 | // OpenTSDBWithConfig is a blocking exporter function just like OpenTSDB, |
| 39 | // but it takes a OpenTSDBConfig instead. |
| 40 | func OpenTSDBWithConfig(c OpenTSDBConfig) { |
| 41 | for _ = range time.Tick(c.FlushInterval) { |
| 42 | if err := openTSDB(&c); nil != err { |
| 43 | log.Println(err) |
| 44 | } |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | func getShortHostname() string { |
| 49 | if shortHostName == "" { |
| 50 | host, _ := os.Hostname() |
| 51 | if index := strings.Index(host, "."); index > 0 { |
| 52 | shortHostName = host[:index] |
| 53 | } else { |
| 54 | shortHostName = host |
| 55 | } |
| 56 | } |
| 57 | return shortHostName |
| 58 | } |
| 59 | |
| 60 | func openTSDB(c *OpenTSDBConfig) error { |
| 61 | shortHostname := getShortHostname() |
| 62 | now := time.Now().Unix() |
| 63 | du := float64(c.DurationUnit) |
| 64 | conn, err := net.DialTCP("tcp", nil, c.Addr) |
| 65 | if nil != err { |
| 66 | return err |
| 67 | } |
| 68 | defer conn.Close() |
| 69 | w := bufio.NewWriter(conn) |
| 70 | c.Registry.Each(func(name string, i interface{}) { |
| 71 | switch metric := i.(type) { |
| 72 | case Counter: |
| 73 | fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Count(), shortHostname) |
| 74 | case Gauge: |
| 75 | fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname) |
| 76 | case GaugeFloat64: |
| 77 | fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname) |
| 78 | case Histogram: |
| 79 | h := metric.Snapshot() |
| 80 | ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) |
| 81 | fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, h.Count(), shortHostname) |
| 82 | fmt.Fprintf(w, "put %s.%s.min %d %d host=%s\n", c.Prefix, name, now, h.Min(), shortHostname) |
| 83 | fmt.Fprintf(w, "put %s.%s.max %d %d host=%s\n", c.Prefix, name, now, h.Max(), shortHostname) |
| 84 | fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, h.Mean(), shortHostname) |
| 85 | fmt.Fprintf(w, "put %s.%s.std-dev %d %.2f host=%s\n", c.Prefix, name, now, h.StdDev(), shortHostname) |
| 86 | fmt.Fprintf(w, "put %s.%s.50-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[0], shortHostname) |
| 87 | fmt.Fprintf(w, "put %s.%s.75-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[1], shortHostname) |
| 88 | fmt.Fprintf(w, "put %s.%s.95-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[2], shortHostname) |
| 89 | fmt.Fprintf(w, "put %s.%s.99-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[3], shortHostname) |
| 90 | fmt.Fprintf(w, "put %s.%s.999-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[4], shortHostname) |
| 91 | case Meter: |
| 92 | m := metric.Snapshot() |
| 93 | fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, m.Count(), shortHostname) |
| 94 | fmt.Fprintf(w, "put %s.%s.one-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate1(), shortHostname) |
| 95 | fmt.Fprintf(w, "put %s.%s.five-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate5(), shortHostname) |
| 96 | fmt.Fprintf(w, "put %s.%s.fifteen-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate15(), shortHostname) |
| 97 | fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, m.RateMean(), shortHostname) |
| 98 | case Timer: |
| 99 | t := metric.Snapshot() |
| 100 | ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) |
| 101 | fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, t.Count(), shortHostname) |
| 102 | fmt.Fprintf(w, "put %s.%s.min %d %d host=%s\n", c.Prefix, name, now, t.Min()/int64(du), shortHostname) |
| 103 | fmt.Fprintf(w, "put %s.%s.max %d %d host=%s\n", c.Prefix, name, now, t.Max()/int64(du), shortHostname) |
| 104 | fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, t.Mean()/du, shortHostname) |
| 105 | fmt.Fprintf(w, "put %s.%s.std-dev %d %.2f host=%s\n", c.Prefix, name, now, t.StdDev()/du, shortHostname) |
| 106 | fmt.Fprintf(w, "put %s.%s.50-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[0]/du, shortHostname) |
| 107 | fmt.Fprintf(w, "put %s.%s.75-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[1]/du, shortHostname) |
| 108 | fmt.Fprintf(w, "put %s.%s.95-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[2]/du, shortHostname) |
| 109 | fmt.Fprintf(w, "put %s.%s.99-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[3]/du, shortHostname) |
| 110 | fmt.Fprintf(w, "put %s.%s.999-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[4]/du, shortHostname) |
| 111 | fmt.Fprintf(w, "put %s.%s.one-minute %d %.2f host=%s\n", c.Prefix, name, now, t.Rate1(), shortHostname) |
| 112 | fmt.Fprintf(w, "put %s.%s.five-minute %d %.2f host=%s\n", c.Prefix, name, now, t.Rate5(), shortHostname) |
| 113 | fmt.Fprintf(w, "put %s.%s.fifteen-minute %d %.2f host=%s\n", c.Prefix, name, now, t.Rate15(), shortHostname) |
| 114 | fmt.Fprintf(w, "put %s.%s.mean-rate %d %.2f host=%s\n", c.Prefix, name, now, t.RateMean(), shortHostname) |
| 115 | } |
| 116 | w.Flush() |
| 117 | }) |
| 118 | return nil |
| 119 | } |