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  }