This repository has been archived by the owner on Jun 16, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 45
/
graphite.go
191 lines (165 loc) · 5.12 KB
/
graphite.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package graphite
import (
"bytes"
"fmt"
"log"
"net"
"time"
)
// Graphite is a struct that defines the relevant properties of a graphite
// connection
type Graphite struct {
Host string
Port int
Protocol string
Timeout time.Duration
Prefix string
conn net.Conn
nop bool
DisableLog bool
}
// defaultTimeout is the default number of seconds that we're willing to wait
// before forcing the connection establishment to fail
const defaultTimeout = 5
// IsNop is a getter for *graphite.Graphite.nop
func (graphite *Graphite) IsNop() bool {
if graphite.nop {
return true
}
return false
}
// Given a Graphite struct, Connect populates the Graphite.conn field with an
// appropriate TCP connection
func (graphite *Graphite) Connect() error {
if !graphite.IsNop() {
if graphite.conn != nil {
graphite.conn.Close()
}
address := fmt.Sprintf("%s:%d", graphite.Host, graphite.Port)
if graphite.Timeout == 0 {
graphite.Timeout = defaultTimeout * time.Second
}
var err error
var conn net.Conn
if graphite.Protocol == "udp" {
udpAddr, err := net.ResolveUDPAddr("udp", address)
if err != nil {
return err
}
conn, err = net.DialUDP(graphite.Protocol, nil, udpAddr)
} else {
conn, err = net.DialTimeout(graphite.Protocol, address, graphite.Timeout)
}
if err != nil {
return err
}
graphite.conn = conn
}
return nil
}
// Given a Graphite struct, Disconnect closes the Graphite.conn field
func (graphite *Graphite) Disconnect() error {
err := graphite.conn.Close()
graphite.conn = nil
return err
}
// Given a Metric struct, the SendMetric method sends the supplied metric to the
// Graphite connection that the method is called upon
func (graphite *Graphite) SendMetric(metric Metric) error {
metrics := make([]Metric, 1)
metrics[0] = metric
return graphite.sendMetrics(metrics)
}
// Given a slice of Metrics, the SendMetrics method sends the metrics, as a
// batch, to the Graphite connection that the method is called upon
func (graphite *Graphite) SendMetrics(metrics []Metric) error {
return graphite.sendMetrics(metrics)
}
// sendMetrics is an internal function that is used to write to the TCP
// connection in order to communicate metrics to the remote Graphite host
func (graphite *Graphite) sendMetrics(metrics []Metric) error {
if graphite.IsNop() {
if !graphite.DisableLog {
for _, metric := range metrics {
log.Printf("Graphite: %s\n", metric)
}
}
return nil
}
zeroed_metric := Metric{} // ignore unintialized metrics
buf := bytes.NewBufferString("")
for _, metric := range metrics {
if metric == zeroed_metric {
continue // ignore unintialized metrics
}
if metric.Timestamp == 0 {
metric.Timestamp = time.Now().Unix()
}
metric_name := ""
if graphite.Prefix != "" {
metric_name = fmt.Sprintf("%s.%s", graphite.Prefix, metric.Name)
} else {
metric_name = metric.Name
}
if graphite.Protocol == "udp" {
fmt.Fprintf(graphite.conn, "%s %s %d\n", metric_name, metric.Value, metric.Timestamp)
continue
}
buf.WriteString(fmt.Sprintf("%s %s %d\n", metric_name, metric.Value, metric.Timestamp))
}
if graphite.Protocol == "tcp" {
_, err := graphite.conn.Write(buf.Bytes())
//fmt.Print("Sent msg:", buf.String(), "'")
if err != nil {
return err
}
}
return nil
}
// The SimpleSend method can be used to just pass a metric name and value and
// have it be sent to the Graphite host with the current timestamp
func (graphite *Graphite) SimpleSend(stat string, value string) error {
metrics := make([]Metric, 1)
metrics[0] = NewMetric(stat, value, time.Now().Unix())
err := graphite.sendMetrics(metrics)
if err != nil {
return err
}
return nil
}
// NewGraphite is a factory method that's used to create a new Graphite
func NewGraphite(host string, port int) (*Graphite, error) {
return GraphiteFactory("tcp", host, port, "")
}
// NewGraphiteWithMetricPrefix is a factory method that's used to create a new Graphite with a metric prefix
func NewGraphiteWithMetricPrefix(host string, port int, prefix string) (*Graphite, error) {
return GraphiteFactory("tcp", host, port, prefix)
}
// When a UDP connection to Graphite is required
func NewGraphiteUDP(host string, port int) (*Graphite, error) {
return GraphiteFactory("udp", host, port, "")
}
// NewGraphiteNop is a factory method that returns a Graphite struct but will
// not actually try to send any packets to a remote host and, instead, will just
// log. This is useful if you want to use Graphite in a project but don't want
// to make Graphite a requirement for the project.
func NewGraphiteNop(host string, port int) *Graphite {
graphiteNop, _ := GraphiteFactory("nop", host, port, "")
return graphiteNop
}
func GraphiteFactory(protocol string, host string, port int, prefix string) (*Graphite, error) {
var graphite *Graphite
switch protocol {
case "tcp":
graphite = &Graphite{Host: host, Port: port, Protocol: "tcp", Prefix: prefix}
case "udp":
graphite = &Graphite{Host: host, Port: port, Protocol: "udp", Prefix: prefix}
case "nop":
graphite = &Graphite{Host: host, Port: port, nop: true}
}
err := graphite.Connect()
if err != nil {
return nil, err
}
return graphite, nil
}