forked from adubkov/go-zabbix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzabbix.go
170 lines (141 loc) · 3.6 KB
/
zabbix.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
// Package implement zabbix sender protocol for send metrics to zabbix.
package zabbix
import (
"encoding/binary"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"time"
)
// Metric class.
type Metric struct {
Host string `json:"host"`
Key string `json:"key"`
Value string `json:"value"`
Clock int64 `json:"clock"`
}
// Metric class constructor.
func NewMetric(host, key, value string, clock ...int64) *Metric {
m := &Metric{Host: host, Key: key, Value: value}
// use current time, if `clock` is not specified
if m.Clock = time.Now().Unix(); len(clock) > 0 {
m.Clock = int64(clock[0])
}
return m
}
// Packet class.
type Packet struct {
Request string `json:"request"`
Data []*Metric `json:"data"`
Clock int64 `json:"clock"`
}
// Packet class cunstructor.
func NewPacket(data []*Metric, clock ...int64) *Packet {
p := &Packet{Request: `sender data`, Data: data}
// use current time, if `clock` is not specified
if p.Clock = time.Now().Unix(); len(clock) > 0 {
p.Clock = int64(clock[0])
}
return p
}
// DataLen Packet class method, return 8 bytes with packet length in little endian order.
func (p *Packet) DataLen() []byte {
dataLen := make([]byte, 8)
JSONData, _ := json.Marshal(p)
binary.LittleEndian.PutUint32(dataLen, uint32(len(JSONData)))
return dataLen
}
// Sender class.
type Sender struct {
Host string
Port int
}
// Sender class constructor.
func NewSender(host string, port int) *Sender {
s := &Sender{Host: host, Port: port}
return s
}
// Method Sender class, return zabbix header.
func (s *Sender) getHeader() []byte {
return []byte("ZBXD\x01")
}
// Method Sender class, resolve uri by name:port.
func (s *Sender) getTCPAddr() (iaddr *net.TCPAddr, err error) {
// format: hostname:port
addr := fmt.Sprintf("%s:%d", s.Host, s.Port)
// Resolve hostname:port to ip:port
iaddr, err = net.ResolveTCPAddr("tcp", addr)
if err != nil {
err = fmt.Errorf("Connection failed: %s", err.Error())
return
}
return
}
// Method Sender class, make connection to uri.
func (s *Sender) connect() (conn *net.TCPConn, err error) {
type DialResp struct {
Conn *net.TCPConn
Error error
}
// Open connection to zabbix host
iaddr, err := s.getTCPAddr()
if err != nil {
return
}
// dial tcp and handle timeouts
ch := make(chan DialResp)
go func() {
conn, err = net.DialTCP("tcp", nil, iaddr)
ch <- DialResp{Conn: conn, Error: err}
}()
select {
case <-time.After(5 * time.Second):
err = fmt.Errorf("Connection Timeout")
case resp := <-ch:
if resp.Error != nil {
err = resp.Error
break
}
conn = resp.Conn
}
return
}
// Method Sender class, read data from connection.
func (s *Sender) read(conn *net.TCPConn) (res []byte, err error) {
res = make([]byte, 1024)
res, err = ioutil.ReadAll(conn)
if err != nil {
err = fmt.Errorf("Error whule receiving the data: %s", err.Error())
return
}
return
}
// Method Sender class, send packet to zabbix.
func (s *Sender) Send(packet *Packet) (res []byte, err error) {
conn, err := s.connect()
if err != nil {
return
}
defer conn.Close()
dataPacket, _ := json.Marshal(packet)
/*
fmt.Printf("HEADER: % x (%s)\n", s.getHeader(), s.getHeader())
fmt.Printf("DATALEN: % x, %d byte\n", packet.DataLen(), len(packet.DataLen()))
fmt.Printf("BODY: %s\n", string(dataPacket))
*/
// Fill buffer
buffer := append(s.getHeader(), packet.DataLen()...)
buffer = append(buffer, dataPacket...)
// Sent packet to zabbix
_, err = conn.Write(buffer)
if err != nil {
err = fmt.Errorf("Error while sending the data: %s", err.Error())
return
}
res, err = s.read(conn)
/*
fmt.Printf("RESPONSE: %s\n", string(res))
*/
return
}