github.com/turingchain2020/turingchain@v1.1.21/metrics/influxdb/influxdb.go (about) 1 package influxdb 2 3 import ( 4 "fmt" 5 uurl "net/url" 6 "time" 7 8 turingchainlog "github.com/turingchain2020/turingchain/common/log/log15" 9 "github.com/influxdata/influxdb/client" 10 metrics "github.com/rcrowley/go-metrics" 11 ) 12 13 type reporter struct { 14 reg metrics.Registry 15 interval time.Duration 16 17 url uurl.URL 18 database string 19 username string 20 password string 21 namespace string 22 tags map[string]string 23 24 client *client.Client 25 26 cache map[string]int64 27 } 28 29 var ( 30 log = turingchainlog.New("module", "influxdb") 31 ) 32 33 // InfluxDB starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval. 34 func InfluxDB(r metrics.Registry, d time.Duration, url, database, username, password, namespace string) { 35 Emit2InfluxDBWithTags(r, d, url, database, username, password, namespace, nil) 36 } 37 38 // Emit2InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags 39 func Emit2InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, username, password, namespace string, tags map[string]string) { 40 u, err := uurl.Parse(url) 41 if err != nil { 42 log.Warn("Unable to parse InfluxDB", "url", url, "err", err) 43 return 44 } 45 46 rep := &reporter{ 47 reg: r, 48 interval: d, 49 url: *u, 50 database: database, 51 username: username, 52 password: password, 53 namespace: namespace, 54 tags: tags, 55 cache: make(map[string]int64), 56 } 57 if err := rep.makeClient(); err != nil { 58 log.Warn("Unable to make InfluxDB client", "err", err) 59 return 60 } 61 62 rep.run() 63 } 64 65 // Emit2InfluxDBWithTagsOnce runs once an InfluxDB reporter and post the given metrics.Registry with the specified tags 66 func Emit2InfluxDBWithTagsOnce(r metrics.Registry, url, database, username, password, namespace string, tags map[string]string) error { 67 u, err := uurl.Parse(url) 68 if err != nil { 69 return fmt.Errorf("unable to parse InfluxDB. url: %s, err: %v", url, err) 70 } 71 72 rep := &reporter{ 73 reg: r, 74 url: *u, 75 database: database, 76 username: username, 77 password: password, 78 namespace: namespace, 79 tags: tags, 80 cache: make(map[string]int64), 81 } 82 if err := rep.makeClient(); err != nil { 83 return fmt.Errorf("unable to make InfluxDB client. err: %v", err) 84 } 85 86 if err := rep.send(); err != nil { 87 return fmt.Errorf("unable to send to InfluxDB. err: %v", err) 88 } 89 90 return nil 91 } 92 93 func (r *reporter) makeClient() (err error) { 94 r.client, err = client.NewClient(client.Config{ 95 URL: r.url, 96 Username: r.username, 97 Password: r.password, 98 Timeout: 10 * time.Second, 99 }) 100 101 return 102 } 103 104 func (r *reporter) run() { 105 intervalTicker := time.Tick(r.interval) 106 pingTicker := time.Tick(time.Second * 5) 107 108 for { 109 select { 110 case <-intervalTicker: 111 if err := r.send(); err != nil { 112 log.Warn("Unable to send to InfluxDB", "err", err) 113 } 114 case <-pingTicker: 115 _, _, err := r.client.Ping() 116 if err != nil { 117 log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err) 118 119 if err = r.makeClient(); err != nil { 120 log.Warn("Unable to make InfluxDB client", "err", err) 121 } 122 } 123 } 124 } 125 } 126 127 func (r *reporter) send() error { 128 var pts []client.Point 129 130 r.reg.Each(func(name string, i interface{}) { 131 now := time.Now() 132 namespace := r.namespace 133 134 switch metric := i.(type) { 135 case metrics.Counter: 136 v := metric.Count() 137 l := r.cache[name] 138 pts = append(pts, client.Point{ 139 Measurement: fmt.Sprintf("%s%s.count", namespace, name), 140 Tags: r.tags, 141 Fields: map[string]interface{}{ 142 "value": v - l, 143 }, 144 Time: now, 145 }) 146 r.cache[name] = v 147 case metrics.Gauge: 148 ms := metric.Snapshot() 149 pts = append(pts, client.Point{ 150 Measurement: fmt.Sprintf("%s%s.gauge", namespace, name), 151 Tags: r.tags, 152 Fields: map[string]interface{}{ 153 "value": ms.Value(), 154 }, 155 Time: now, 156 }) 157 case metrics.GaugeFloat64: 158 ms := metric.Snapshot() 159 pts = append(pts, client.Point{ 160 Measurement: fmt.Sprintf("%s%s.gauge", namespace, name), 161 Tags: r.tags, 162 Fields: map[string]interface{}{ 163 "value": ms.Value(), 164 }, 165 Time: now, 166 }) 167 case metrics.Histogram: 168 ms := metric.Snapshot() 169 ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) 170 pts = append(pts, client.Point{ 171 Measurement: fmt.Sprintf("%s%s.histogram", namespace, name), 172 Tags: r.tags, 173 Fields: map[string]interface{}{ 174 "count": ms.Count(), 175 "max": ms.Max(), 176 "mean": ms.Mean(), 177 "min": ms.Min(), 178 "stddev": ms.StdDev(), 179 "variance": ms.Variance(), 180 "p50": ps[0], 181 "p75": ps[1], 182 "p95": ps[2], 183 "p99": ps[3], 184 "p999": ps[4], 185 "p9999": ps[5], 186 }, 187 Time: now, 188 }) 189 case metrics.Meter: 190 ms := metric.Snapshot() 191 pts = append(pts, client.Point{ 192 Measurement: fmt.Sprintf("%s%s.meter", namespace, name), 193 Tags: r.tags, 194 Fields: map[string]interface{}{ 195 "count": ms.Count(), 196 "m1": ms.Rate1(), 197 "m5": ms.Rate5(), 198 "m15": ms.Rate15(), 199 "mean": ms.RateMean(), 200 }, 201 Time: now, 202 }) 203 case metrics.Timer: 204 ms := metric.Snapshot() 205 ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) 206 pts = append(pts, client.Point{ 207 Measurement: fmt.Sprintf("%s%s.timer", namespace, name), 208 Tags: r.tags, 209 Fields: map[string]interface{}{ 210 "count": ms.Count(), 211 "max": ms.Max(), 212 "mean": ms.Mean(), 213 "min": ms.Min(), 214 "stddev": ms.StdDev(), 215 "variance": ms.Variance(), 216 "p50": ps[0], 217 "p75": ps[1], 218 "p95": ps[2], 219 "p99": ps[3], 220 "p999": ps[4], 221 "p9999": ps[5], 222 "m1": ms.Rate1(), 223 "m5": ms.Rate5(), 224 "m15": ms.Rate15(), 225 "meanrate": ms.RateMean(), 226 }, 227 Time: now, 228 }) 229 } 230 }) 231 232 bps := client.BatchPoints{ 233 Points: pts, 234 Database: r.database, 235 } 236 237 _, err := r.client.Write(bps) 238 return err 239 }