github.com/theQRL/go-zond@v0.1.1/metrics/influxdb/influxdbv1.go (about) 1 package influxdb 2 3 import ( 4 "fmt" 5 uurl "net/url" 6 "time" 7 8 client "github.com/influxdata/influxdb1-client/v2" 9 "github.com/theQRL/go-zond/log" 10 "github.com/theQRL/go-zond/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 // 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(0); 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.NewHTTPClient(client.HTTPConfig{ 91 Addr: r.url.String(), 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.NewTicker(r.interval) 102 pingTicker := time.NewTicker(time.Second * 5) 103 104 defer intervalTicker.Stop() 105 defer pingTicker.Stop() 106 107 for { 108 select { 109 case <-intervalTicker.C: 110 if err := r.send(0); err != nil { 111 log.Warn("Unable to send to InfluxDB", "err", err) 112 } 113 case <-pingTicker.C: 114 _, _, err := r.client.Ping(0) 115 if err != nil { 116 log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err) 117 118 if err = r.makeClient(); err != nil { 119 log.Warn("Unable to make InfluxDB client", "err", err) 120 } 121 } 122 } 123 } 124 } 125 126 // send sends the measurements. If provided tstamp is >0, it is used. Otherwise, 127 // a 'fresh' timestamp is used. 128 func (r *reporter) send(tstamp int64) error { 129 bps, err := client.NewBatchPoints( 130 client.BatchPointsConfig{ 131 Database: r.database, 132 }) 133 if err != nil { 134 return err 135 } 136 r.reg.Each(func(name string, i interface{}) { 137 var now time.Time 138 if tstamp <= 0 { 139 now = time.Now() 140 } else { 141 now = time.Unix(tstamp, 0) 142 } 143 measurement, fields := readMeter(r.namespace, name, i) 144 if fields == nil { 145 return 146 } 147 if p, err := client.NewPoint(measurement, r.tags, fields, now); err == nil { 148 bps.AddPoint(p) 149 } 150 }) 151 return r.client.Write(bps) 152 }