Add zabbix.go

This commit is contained in:
Alexey Dubkov 2015-02-26 01:47:00 -08:00
parent 20c5dd26d5
commit 5827377550

184
zabbix.go Normal file

@ -0,0 +1,184 @@
/*
Zabbix sender protocol defenition:
HEADER: ZBXD\x01, 5 byte
DATALEN: 8 byte, little-endian
DATA: JSON data
Request packet to zabbix host:
<HEADER><DATALEN>{
"request": "sender data",
"data": [
{
"host": "Host name 1",
"key": "item_key",
"value": "33",
"clock": 1381482894
},
{
"host": "Host name 2",
"key": "item_key",
"value": "55",
"clock": 1381482894
}
],
"clock": 1381482905
}
Response packet:
<HEADER><DATALEN>{
"response":"success",
"info":"Processed 2 Failed 0 Total 2 Seconds spent 0.002070"
}
*/
package zabbix
import (
"encoding/binary"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
"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 := new(Metric)
m.Host = host
m.Key = key
m.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 := new(Packet)
p.Request = `sender data`
p.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 := new(Sender)
s.Host = host
s.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() *net.TCPAddr {
// 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 {
fmt.Printf("Connection failed: %s", err.Error())
os.Exit(1)
}
return iaddr
}
// Method Sender class, make connection to uri
func (s Sender) connect() *net.TCPConn {
iaddr := s.getTCPAddr()
// Open connection to zabbix host
conn, err := net.DialTCP("tcp", nil, iaddr)
if err != nil {
fmt.Printf("Connection failed: %s", err.Error())
os.Exit(1)
}
return conn
}
// Method Sender class, read data from connection
func (s Sender) read(conn *net.TCPConn) []byte {
res := make([]byte, 1024)
res, err := ioutil.ReadAll(conn)
if err != nil {
fmt.Printf("Error whule receiving the data: %s", err.Error())
os.Exit(1)
}
return res
}
// Method Sender class, send packet to zabbix
func (s Sender) Send(packet *Packet) {
conn := s.connect()
defer conn.Close()
dataPacket, _ := json.Marshal(packet)
// Make zabbix header
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 {
fmt.Printf("Error while sending the data: %s", err.Error())
os.Exit(1)
}
res := s.read(conn)
fmt.Printf("RESPONSE: %s\n", string(res))
}