Monitoring Agent を使って Zabbix で Fluentd を監視する


## はじめに
この記事の内容は、[fluentdの効果的な活用例と安定運用のポイント (3/3)](http://www.atmarkit.co.jp/ait/articles/1404/04/news004_3.html)を参考にしています。ありがとうございます。

## Fluentd で Monitoring Agent 機能を利用する
Fluentd には、現在のバッファサイズ、キュー長、リトライ回数を取得するための[Monitoring Agent](http://docs.fluentd.org/articles/monitoring)機能があります。これは、バッファサイズなどの情報を取得したい Fluentd プロセスの設定ファイルに下記の設定を追加した上で、`http://host:24220/api/plugins` にアクセスすることで情報を取得できるようになる機能です。

```MonitoringAgent機能の設定
<source>
  type monitor_agent
  bind 0.0.0.0
  port 24220
</source>
```
```MonitoringAgent機能から得られる情報
plugin_id:object:ff44c0	plugin_category:input	type:monitor_agent	output_plugin:false	retry_count:
...
plugin_id:object:f9ec64	plugin_category:output	type:	output_plugin:true	buffer_queue_length:0	buffer_total_queued_size:0	retry_count:0
plugin_id:object:10883f0	plugin_category:output	type:	output_plugin:true	buffer_queue_length:0	buffer_total_queued_size:0	retry_count:0
```

Monitoring Agent 機能は、URI の拡張子を json にする (`http://host:24220/api/plugins.json`) ことで json 形式でも情報を取得できるため、この json を処理するスクリプトを書けば、機械的にバッファサイズやリトライ回数を監視することが可能になります。

## Zabbix で Monitoring Agent 機能を利用する
Zabbix には、Zabbixサーバにスクリプトまたはバイナリを実行してチェックさせる[外部チェック](https://www.zabbix.com/documentation/2.2/jp/manual/config/items/itemtypes/external)という方法があります。これは、`/usr/local/share/zabbix/externalscripts` (デフォルト値) にスクリプトを設置した上で、Zabbix のアイテム作成時、タイプを `外部チェック`、キーを `script_file_name[<parameter1>,<parameter2>,...]` にすることでスクリプトを定期実行させ、その結果を格納させる方法です。

つまり、Monitoring Agent 機能から Zabbix に情報を渡すスクリプトを作成し、外部チェックで格納させれば、キュー長やリトライ回数を視覚化し、異常を検知し、通知することができるようになります。

```python:MonitoringAgent機能からZabbixに情報を渡すスクリプト
#!/usr/bin/env python
# coding=utf-8

import json
import sys
import urllib2

host, port, plugin_id, metric = sys.argv[1:]
response = urllib2.urlopen("http://%s:%s/api/plugins.json" % (host, port))
body = json.loads(response.read())
for plugin in body['plugins']:
    if plugin['plugin_id'] == plugin_id:
        print plugin[metric]
        break
```

ただ、 **注意すべきことがあります**。Monitoring Agent 機能で返されるプラグインの ID はデフォルトで Ruby のオブジェクトの ID である (`plugin_id:object:fad6ec`) ため、プラグイン毎のバッファサイズを得ることが困難です。

この問題を解決するために、Fluentd の [Common Plugin Parameter](http://docs.fluentd.org/articles/config-file#common-plugin-parameter) の `@id` パラメータを使用します。これを使用するとプラグインの ID は `@id hoge` で指定した `hoge` になるため、Fluentd プロセスを再起動させたとしても継続して監視を続けることが可能になります。人間が読めるという意味でも非常に便利です。

しかし、それでも [fluent-plugin-forest](https://github.com/tagomoris/fluent-plugin-forest) といったマルチスレッディングさせるプラグインを使用した場合は対応することができません。この場合は、全てのプラグインの最大値を取得し、その最大値で監視するなどすれば、ある程度上手くいくでしょう。

```python:MonitoringAgent機能からZabbixに情報を渡すスクリプト(最大値を渡す場合)
#!/usr/bin/env python
# coding=utf-8

import json
import sys
import urllib2

host, port, metric = sys.argv[1:]
response = urllib2.urlopen("http://%s:%s/api/plugins.json" % (host, port))
body = json.loads(response.read())
maximum_value = 0
for plugin in body['plugins']:
    if plugin.get(metric, 0) > maximum_value:
        maximum_value = plugin.get(metric)
print maximum_value
```

## まとめ
この記事は、[fluentdの効果的な活用例と安定運用のポイント (3/3)](http://www.atmarkit.co.jp/ait/articles/1404/04/news004_3.html)の内容に、外部チェックと Common Plugin Parameter まわりの内容を加えて説明していきました。また、スクリプトも Python に書き換え、Zabbix だけをインストールした環境でも動作するように意識しました。

この記事だけでなくリンク先も参考にして頂き、より安心して Fluentd を運用して頂ければ幸いです。