GoでZabbixと通信する、もしくはオレオレZabbix Server/AgentをGoで実装する方法

全国一千万Zabbixユーザの皆様こんにちは。

複数のZabbix Agentから取得した値を集約する zabbix-aggregate-agent や zabbix_get コマンドの Go 実装版 go-zabbix-get を書いて遊んでいるうちに、Go で Zabbix と通信するライブラリが育ってきてしまったので一通りまとめておきます。

"github.com/fujiwara/go-zabbix-get/zabbix" を import して使います。

import "github.com/fujiwara/go-zabbix-get/zabbix"

Zabbix Agentから値を取得する

アイテムでいうところの「Zabbixエージェント」型、ServerやProxyからAgentに対してTCP接続をして値を取得するタイプです。

value, err := zabbix.Get("example.com:10050", "keyname", 5*time.Second)

通信相手のAegentのアドレス、取得したいアイテムのkey名、タイムアウト時間を渡すだけです。簡単ですね。value は string です。

Zabbix Server/Proxy に値を送信する

アイテムでいうところの「Zabbixトラッパー」型、ServerやProxyに対して(Agent以外の何者かが)値を送信するタイプです。Fluentdのプラグインfluent-plugin-zabbix もこの形式ですね。

resp, err := zabbix.Send(
	"example.com:10051",
	zabbix.TrapperData{Host: "localhost", Key: "foo", Value: "bar"},
	5 * time.Second,       
)

送信データを zabbix.TrapperData 型として作成して渡してあげるだけです。これも簡単ですね。

これは何が嬉しいのかというと、自作の daemon 類に何か異常があった場合に Zabbix Serever に直接 trap を送りつけるような機能が実装できます。アラートの即応性が上がりますね。

複数データをまとめて送りつける SendBulk() もあります。

res, err := zabbix.SendBulk(
	"example.com:10051",
	zabbix.TrapperRequest{
		Data: []zabbix.TrapperData{
			zabbix.TrapperData{Host: "localhost", Key: "foo", Value: "bar"},
			zabbix.TrapperData{Host: "localhost", Key: "xxx", Value: "yyy"},
		},
	},
	timeout,
)

オレオレZabbix Agentを実装する

ここまでは既存の Agent や Server に対する通信ですが、自分自身で Agent や Server(Trapper) を実装することも可能です。

err := zabbix.RunAgent("0.0.0.0:10050", func(key string) (string, error) {
	switch key {
	case "agent.ping":
		return "1", nil
	// ...
	default:
		return "", fmt.Errorf("not supported")
	}
})

RunAgent() に func(key string) (string, error) な関数を callback として渡してやることで、TCPサーバとなり Server や zabbix_get コマンドに値を返す daemon を実装できます。

自作の daemon が持っている情報を、直接 Zabbix Server から通信して取得するような機能が実装できます。値の取得のために、別途 zabbix-agent から UserParameter で外部コマンドを起動するような必要がなくなります。

オレオレZabbix Server(Trapper)を実装する

zabbix_sender (zabbix.Send()) により送信された値を受信するサーバも簡単に実装可能です。

err := zabbix.RunTrapper("0.0.0.0:10051", func(req zabbix.TrapperRequest) (res zabbix.TrapperResponse, err error) {
	for _, data := range req.Data {
		log.Println(data)
	}
	res.Proceeded = len(req.Data)
	return res, nil
})

これは使いどころがいまいち難しいのですが、fluent-plugin-zabbixのテスト には便利に使っています。

ここまで道具が揃ったら、Go で Zabbix Server 互換実装を作り上げることも夢ではないですね!(やりませんけど…)

全く誰得プロダクトだと思いますが、お楽しみください。