forked from cactus/go-statsd-client
/
main.go
152 lines (134 loc) · 3.67 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package statsd
import (
"bufio"
"errors"
"fmt"
"math/rand"
"net"
"sync"
"time"
)
type Client struct {
// connection buffer
buf *bufio.ReadWriter
// underlying connection
conn *net.Conn
// prefix for statsd name
prefix string
// write mutex
mutex sync.Mutex
}
// Close closes the connection and cleans up.
func (s *Client) Close() error {
// flush any outstanding data
s.buf.Flush()
s.buf = nil
err := (*s.conn).Close()
return err
}
// Increments a statsd count type.
// stat is a string name for the metric.
// value is the integer value
// rate is the sample rate (0.0 to 1.0)
func (s *Client) Inc(stat string, value int64, rate float32) error {
dap := fmt.Sprintf("%d|c", value)
return s.submit(stat, dap, rate)
}
// Decrements a statsd count type.
// stat is a string name for the metric.
// value is the integer value.
// rate is the sample rate (0.0 to 1.0).
func (s *Client) Dec(stat string, value int64, rate float32) error {
return s.Inc(stat, -value, rate)
}
// Submits/Updates a statsd gauge type.
// stat is a string name for the metric.
// value is the integer value.
// rate is the sample rate (0.0 to 1.0).
func (s *Client) Gauge(stat string, value int64, rate float32) error {
dap := fmt.Sprintf("%d|g", value)
return s.submit(stat, dap, rate)
}
// Submits a statsd timing type.
// stat is a string name for the metric.
// value is the integer value.
// rate is the sample rate (0.0 to 1.0).
func (s *Client) Timing(stat string, delta int64, rate float32) error {
dap := fmt.Sprintf("%d|ms", delta)
return s.submit(stat, dap, rate)
}
// Sets/Updates the statsd client prefix
func (s *Client) SetPrefix(prefix string) {
s.prefix = prefix
}
// submit formats the statsd event data, handles sampling, and prepares it,
// and sends it to the server.
func (s *Client) submit(stat string, value string, rate float32) error {
if rate < 1 {
if rand.Float32() < rate {
value = fmt.Sprintf("%s|@%f", value, rate)
} else {
return nil
}
}
if s.prefix != "" {
stat = fmt.Sprintf("%s.%s", s.prefix, stat)
}
data := fmt.Sprintf("%s:%s", stat, value)
_, err := s.send([]byte(data))
if err != nil {
return err
}
return nil
}
// sends the data to the server endpoint over the net.Conn
func (s *Client) send(data []byte) (int, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
n, err := s.buf.Write([]byte(data))
if err != nil {
return 0, err
}
if n == 0 {
return n, errors.New("Wrote no bytes")
}
err = s.buf.Flush()
if err != nil {
return n, err
}
return n, nil
}
func newClient(conn *net.Conn, prefix string) *Client {
buf := bufio.NewReadWriter(bufio.NewReader(*conn), bufio.NewWriter(*conn))
client := &Client{
buf: buf,
conn: conn,
prefix: prefix}
return client
}
// Returns a pointer to a new Client.
// addr is a string of the format "hostname:port", and must be parsable by
// net.ResolveUDPAddr.
// prefix is the statsd client prefix. Can be "" if no prefix is desired.
func Dial(addr string, prefix string) (*Client, error) {
conn, err := net.Dial("udp", addr)
if err != nil {
return nil, err
}
client := newClient(&conn, prefix)
return client, nil
}
// Returns a pointer to a new Client.
// addr is a string of the format "hostname:port", and must be parsable by
// net.ResolveUDPAddr.
// timeout is the connection timeout. Since statsd is UDP, there is no
// connection, but the timeout applies to name resolution (if relevant).
// prefix is the statsd client prefix. Can be "" if no prefix is desired.
func DialTimeout(addr string, timeout time.Duration, prefix string) (*Client, error) {
conn, err := net.DialTimeout("udp", addr, timeout)
if err != nil {
return nil, err
}
client := newClient(&conn, prefix)
return client, nil
}