github.com/theQRL/go-zond@v0.1.1/metrics/influxdb/influxdbv2.go (about) 1 package influxdb 2 3 import ( 4 "context" 5 "time" 6 7 influxdb2 "github.com/influxdata/influxdb-client-go/v2" 8 "github.com/influxdata/influxdb-client-go/v2/api" 9 "github.com/theQRL/go-zond/log" 10 "github.com/theQRL/go-zond/metrics" 11 ) 12 13 type v2Reporter struct { 14 reg metrics.Registry 15 interval time.Duration 16 17 endpoint string 18 token string 19 bucket string 20 organization string 21 namespace string 22 tags map[string]string 23 24 client influxdb2.Client 25 write api.WriteAPI 26 } 27 28 // InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags 29 func InfluxDBV2WithTags(r metrics.Registry, d time.Duration, endpoint string, token string, bucket string, organization string, namespace string, tags map[string]string) { 30 rep := &v2Reporter{ 31 reg: r, 32 interval: d, 33 endpoint: endpoint, 34 token: token, 35 bucket: bucket, 36 organization: organization, 37 namespace: namespace, 38 tags: tags, 39 } 40 41 rep.client = influxdb2.NewClient(rep.endpoint, rep.token) 42 defer rep.client.Close() 43 44 // async write client 45 rep.write = rep.client.WriteAPI(rep.organization, rep.bucket) 46 errorsCh := rep.write.Errors() 47 48 // have to handle write errors in a separate goroutine like this b/c the channel is unbuffered and will block writes if not read 49 go func() { 50 for err := range errorsCh { 51 log.Warn("write error", "err", err.Error()) 52 } 53 }() 54 rep.run() 55 } 56 57 func (r *v2Reporter) run() { 58 intervalTicker := time.NewTicker(r.interval) 59 pingTicker := time.NewTicker(time.Second * 5) 60 61 defer intervalTicker.Stop() 62 defer pingTicker.Stop() 63 64 for { 65 select { 66 case <-intervalTicker.C: 67 r.send(0) 68 case <-pingTicker.C: 69 _, err := r.client.Health(context.Background()) 70 if err != nil { 71 log.Warn("Got error from influxdb client health check", "err", err.Error()) 72 } 73 } 74 } 75 } 76 77 // send sends the measurements. If provided tstamp is >0, it is used. Otherwise, 78 // a 'fresh' timestamp is used. 79 func (r *v2Reporter) send(tstamp int64) { 80 r.reg.Each(func(name string, i interface{}) { 81 var now time.Time 82 if tstamp <= 0 { 83 now = time.Now() 84 } else { 85 now = time.Unix(tstamp, 0) 86 } 87 measurement, fields := readMeter(r.namespace, name, i) 88 if fields == nil { 89 return 90 } 91 pt := influxdb2.NewPoint(measurement, r.tags, fields, now) 92 r.write.WritePoint(pt) 93 }) 94 // Force all unwritten data to be sent 95 r.write.Flush() 96 }