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  }