github.com/msales/pkg/v3@v3.24.0/stats/statsd.go (about)

     1  package stats
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/cactus/go-statsd-client/statsd"
     8  	"github.com/msales/pkg/v3/bytes"
     9  )
    10  
    11  // Statsd represents a statsd client.
    12  type Statsd struct {
    13  	client statsd.Statter
    14  }
    15  
    16  // NewStatsd create a Statsd instance.
    17  func NewStatsd(addr, prefix string) (Stats, error) {
    18  	c, err := statsd.NewClient(addr, prefix)
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  
    23  	return &Statsd{
    24  		client: c,
    25  	}, nil
    26  }
    27  
    28  // Inc increments a count by the value.
    29  func (s *Statsd) Inc(name string, value int64, rate float32, tags ...interface{}) error {
    30  	name += formatStatsdTags(tags)
    31  	return s.client.Inc(name, value, rate)
    32  }
    33  
    34  // Dec decrements a count by the value.
    35  func (s *Statsd) Dec(name string, value int64, rate float32, tags ...interface{}) error {
    36  	name += formatStatsdTags(tags)
    37  	return s.client.Dec(name, value, rate)
    38  }
    39  
    40  // Gauge measures the value of a metric.
    41  func (s *Statsd) Gauge(name string, value float64, rate float32, tags ...interface{}) error {
    42  	name += formatStatsdTags(tags)
    43  	return s.client.Gauge(name, int64(value), rate)
    44  }
    45  
    46  // Timing sends the value of a Duration.
    47  func (s *Statsd) Timing(name string, value time.Duration, rate float32, tags ...interface{}) error {
    48  	name += formatStatsdTags(tags)
    49  	return s.client.TimingDuration(name, value, rate)
    50  }
    51  
    52  // Close closes the client and flushes buffered stats, if applicable
    53  func (s *Statsd) Close() error {
    54  	return s.client.Close()
    55  }
    56  
    57  // BufferedStatsdFunc represents an configuration function for BufferedStatsd.
    58  type BufferedStatsdFunc func(*BufferedStatsd)
    59  
    60  // WithFlushInterval sets the maximum flushInterval for packet sending.
    61  // Defaults to 300ms.
    62  func WithFlushInterval(interval time.Duration) BufferedStatsdFunc {
    63  	return func(s *BufferedStatsd) {
    64  		s.flushInterval = interval
    65  	}
    66  }
    67  
    68  // WithFlushBytes sets the maximum udp packet size that will be sent.
    69  // Defaults to 1432 flushBytes.
    70  func WithFlushBytes(bytes int) BufferedStatsdFunc {
    71  	return func(s *BufferedStatsd) {
    72  		s.flushBytes = bytes
    73  	}
    74  }
    75  
    76  // BufferedStatsd represents a buffered statsd client.
    77  type BufferedStatsd struct {
    78  	client statsd.Statter
    79  
    80  	flushInterval time.Duration
    81  	flushBytes    int
    82  }
    83  
    84  // NewBufferedStatsd create a buffered Statsd instance.
    85  func NewBufferedStatsd(addr, prefix string, opts ...BufferedStatsdFunc) (*BufferedStatsd, error) {
    86  	s := &BufferedStatsd{}
    87  
    88  	for _, o := range opts {
    89  		o(s)
    90  	}
    91  
    92  	c, err := statsd.NewBufferedClient(addr, prefix, s.flushInterval, s.flushBytes)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	s.client = c
    97  
    98  	return s, nil
    99  }
   100  
   101  // Inc increments a count by the value.
   102  func (s *BufferedStatsd) Inc(name string, value int64, rate float32, tags ...interface{}) error {
   103  	name += formatStatsdTags(tags)
   104  	return s.client.Inc(name, value, rate)
   105  }
   106  
   107  // Dec decrements a count by the value.
   108  func (s *BufferedStatsd) Dec(name string, value int64, rate float32, tags ...interface{}) error {
   109  	name += formatStatsdTags(tags)
   110  	return s.client.Dec(name, value, rate)
   111  }
   112  
   113  // Gauge measures the value of a metric.
   114  func (s *BufferedStatsd) Gauge(name string, value float64, rate float32, tags ...interface{}) error {
   115  	name += formatStatsdTags(tags)
   116  	return s.client.Gauge(name, int64(value), rate)
   117  }
   118  
   119  // Timing sends the value of a Duration.
   120  func (s *BufferedStatsd) Timing(name string, value time.Duration, rate float32, tags ...interface{}) error {
   121  	name += formatStatsdTags(tags)
   122  	return s.client.TimingDuration(name, value, rate)
   123  }
   124  
   125  // Close closes the client and flushes buffered stats, if applicable
   126  func (s *BufferedStatsd) Close() error {
   127  	return s.client.Close()
   128  }
   129  
   130  var statsdPool = bytes.NewPool(100)
   131  
   132  // formatStatsdTags formats into an InfluxDB style string
   133  func formatStatsdTags(tags []interface{}) string {
   134  	if len(tags) == 0 {
   135  		return ""
   136  	}
   137  
   138  	tags = deduplicateTags(normalizeTags(tags))
   139  
   140  	buf := statsdPool.Get()
   141  	for i := 0; i < len(tags); i += 2 {
   142  		buf.WriteByte(',')
   143  		formatStatsdValue(buf, tags[i])
   144  		buf.WriteByte('=')
   145  		formatStatsdValue(buf, tags[i+1])
   146  	}
   147  
   148  	s := string(buf.Bytes())
   149  	statsdPool.Put(buf)
   150  	return s
   151  }
   152  
   153  // formatStatsdValue formats a value, adding it to the Buffer.
   154  func formatStatsdValue(buf *bytes.Buffer, value interface{}) {
   155  	if value == nil {
   156  		buf.WriteString("nil")
   157  		return
   158  	}
   159  
   160  	switch v := value.(type) {
   161  	case bool:
   162  		buf.AppendBool(v)
   163  	case float32:
   164  		buf.AppendFloat(float64(v), 'g', -1, 64)
   165  	case float64:
   166  		buf.AppendFloat(v, 'g', -1, 64)
   167  	case int:
   168  		buf.AppendInt(int64(v))
   169  	case int8:
   170  		buf.AppendInt(int64(v))
   171  	case int16:
   172  		buf.AppendInt(int64(v))
   173  	case int32:
   174  		buf.AppendInt(int64(v))
   175  	case int64:
   176  		buf.AppendInt(v)
   177  	case uint:
   178  		buf.AppendUint(uint64(v))
   179  	case uint8:
   180  		buf.AppendUint(uint64(v))
   181  	case uint16:
   182  		buf.AppendUint(uint64(v))
   183  	case uint32:
   184  		buf.AppendUint(uint64(v))
   185  	case uint64:
   186  		buf.AppendUint(v)
   187  	case string:
   188  		buf.WriteString(v)
   189  	default:
   190  		buf.WriteString(fmt.Sprintf("%+v", value))
   191  	}
   192  }