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