📻

zabbixから最新値を取得するツールを作りました

2021/11/08に公開約2,700字

tl;dr

zabbix-senderの逆で最新の値を取得するツール、zabbix-getterを作りました。

https://github.com/yakumo-saki/zabbix-getter

背景

我が家のインフラでは各種のメトリクスをzabbixに蓄積しています。IoT的なセンサー類のデータもzabbixに蓄積されています。zabbixから値を取り出してよしなに表示するサイネージ的なものを作ろうとした時に困ってしまいました。

そう、zabbixから値を取得するツールはzabbixに含まれていません。[1]
そこで、zabbix_senderのようなお手軽さでzabbixのデータを取得するツールを開発しました。

実装

このツールはできるだけ多くのプラットフォームで動作してほしいというのと、デプロイが容易であることが重要なのでgolangで開発しました。
まだgolangには不慣れなのでできるだけシンプルに、依存性を減らして開発することを心がけました。
結果、デプロイはgithubからバイナリを取得して解凍して即実行できるようになりました。

インターフェイス

設定ファイルを用意してしまえば、zabbix_senderと同じ引数で動くような形にしました。
また、スクリプトから使うことも考慮した設計になっています。

  • 出力は stdout、ログはstderrに出力される
  • 異常終了時、リターンコードが非ゼロになる

実行例

例えば、 zabbix-getter -s hostname -k keyname で値が取得できます。
項目名等が必要であれば -o JSON とオプション[2]を追加することでもう少し詳細な情報が出力されます。 逆に、-o PLAIN の場合は値だけを出力します。

{
  "hostid": "10307",
  "itemid": "32337",
  "key_": "temperature",
  "lastclock": "1636348382",
  "lastclockString": "2021-11-08 14:13:02 +0900 JST",
  "lastvalue": "28.48",
  "name": "気温",
  "units": "℃"
}

今後の機能追加予定(と足りない機能)

最新の値がある程度以上古かったら無かったことにする

これは個人的なユースケースです。30分以上前のデータが最新だったらそれはデータ取得プロセスがコケているのでデータなし扱いしたい。というものです。うちだと消費電力を30秒ごとに取得しているのですが、たまにこのプロセスがコケることがあります。その際この機能がないと古いデータをサイネージに表示してしまって、混乱することがあります[3]

履歴が複数件欲しい

内部的には持っているので、出力することは可能なんですがユースケースがあるのかなぁ…という疑問があります。 追加するとしたら -l 10 のような感じで件数を指定すると-o PLAIN の場合は行区切りで値がどばっと出る感じ、-o JSON ならJSONの配列で返す形になると思います。

ユーザー名とパスワードをセットしないといけないのがイマイチ

設定ファイルに記述するか、環境変数で設定できるのですが、それ以前にこれはAPIキーみたいなものでどうにかできないものか… と調べては見たものの、zabbixにそういう機能がないようです。

実装の細かい話

以下は完全に蛇足です。読み物として読んでもらえれば。

コマンドラインパーサー

依存性を最小限にするとはいえ、さすがにコマンドラインオプションを一つずつ解釈していくのは骨が折れるのでここはなにかのライブラリに頼りたいところです。
あれ? golang標準のflagパッケージは? となるところですが、標準のflagパッケージはショートハンドなオプションに対応していません。[4]
無理やり対応することもできそうですがアレなので早々にほかを探すことにしました。[5]

この項目、 https://sourjp.github.io/posts/go-cmd/ の記事を見たほうがより詳しいと思うのでこちらも参考になさってください。

要件としては、サブコマンドは作る気がないのでできるだけシンプルなものが欲しい。です。
結論としては、https://github.com/spf13/pflag を使用しました。標準のflagパッケージの不満点だけを解消してくれていて、使い心地はそのまま。さすが drop-in replacement なだけあります。

ロガー

これも標準のロガーがありますが、なんとログレベルの概念が一切ない。ちょっとこれはつらいです。では他のロガーを探そうとなるのですが… 多機能すぎて複雑そう。
fmt.Println に毛が生えたようなので良いので[6] 作ってみることにしました。まだライブラリとしては公開されていませんがそのうち公開しようと思っています。[7]

ちなみに、このロガーを他のgolangのコードで使いまわした際にJSON出力やコンテキストロギングのような機能が追加されて程々感が出てきたのはまた別のタイミングで…[8]

zabbixのitem.get API

初期のころは、zabbixのitem.get APIに含まれるlastvalueという項目の値を結果として出力していたのですが、項目によってこの値が常に "" となることに気が付きました。
テスト用に作った項目ではそういう動作をしないのですが… 諦めて真面目に項目の履歴を取得してそちらから値を出力するように変更しました。[9]

脚注
  1. zabbixに送信する方はzabbix_senderというお手軽ツールが同梱されています ↩︎

  2. これはkubectl -oを真似しました。 ↩︎

  3. 電子レンジ使ってるのに消費電力が低いとか。実際にあった話です ↩︎

  4. -o と --output は同じ。というようなの ↩︎

  5. ヘルプの出力で -o --output が同じであるような出力にならないのが致命的でした ↩︎

  6. それはgolang標準ロガーでは?という気がします ↩︎

  7. ソース中には含まれているのでファイルをコピーすれば使えます ↩︎

  8. しかし、ファイルにログを出力する機能さえ未だに実装されていない。今どきは標準出力と標準エラー出力だけにしておいた方が色々と都合が良いので… ↩︎

  9. v0.9.2くらいの変更です ↩︎

Discussion

ログインするとコメントできます