Zabbixでエラーログ監視。「特定文字列が1時間に5回以上出たらメール通知」する。

# 概要

Zabbixでエラーログを監視したいという要件はよくありますが、今回はちょっとトリッキーな設定をしてみます。
やりたいことは以下。

* ログに「WARNING」という文字列が1時間に5回以上出たらメール通知
* 障害期間中は1分ごとに繰り返し通知をする
* 障害発生後、10分間エラーが出なかったら復旧と判断する

では設定をしてみます。

# 前提条件

Zabbixはインストール済みのものとします。
また、UIは英語ではなく日本語の画面を使って説明していきます。

* バージョン：Zabbix 2.4
* Zabbixサーバ：Ubuntu14.04.2(ローカルVM)

# 設定

### ホストの設定

今回はお試しなので監視対象は「Zabbix server（自分自身）」にします。
「設定」->「ホスト」でホスト一覧を表示します。
「Zabbix server」はZabbixインストール時にデフォルトで入っているので、「ステータス」を有効にしてあげるだけで良いです。
ちなみに、サーバにZabbix agentが入っていないと怒られるのでインストールしておきましょう。

![Zabbixログ監視 - ホストの設定.png](https://qiita-image-store.s3.amazonaws.com/0/27159/5e77fb26-1d96-fa0d-7022-7e5f80ee758e.png)

### アイテムの設定

続いて上記ホストに対してアイテムを設定します。
本当はテンプレートにアイテムを追加するほうがいいのですが、今回はとりあえずホストに対して直接追加することにします。
「設定」->「ホスト」でホスト一覧を表示し、「Zabbix server」の欄の「アイテム」をクリックします。
するとホストに紐付いているアイテム一覧が表示されるので、右上の「アイテムの作成」をクリックします。
設定画面が表示されるので、以下のように入力しました。

![Zabbixログ監視 - アイテムの設定.png](https://qiita-image-store.s3.amazonaws.com/0/27159/118fb30d-f22b-bd6c-c503-6933779a253e.png)

それぞれの項目の説明です。

* 名前：お好みで。
* タイプ：「Zabbixエージェント(アクティブ)」を選択します。
 * 「アクティブ」を選択するとZabbixサーバからログをチェックしにいくのではなく、監視対象のホスト側からZabbixサーバに対してログを送信するようになります。
* キー： `log[ログファイル名,,,,skip]` と入力します。今回はお試しなので適当なパスにしました。
 * ログローテートの設定をしている場合は `logrt` を使うほうが厳密なチェックが出来ますが、シビアな判定が必要でない限りはどちらでも良いと思います。
 * 第2引数は正規表現での絞り込みをします。例えば `log[/var/log/message,"error"]` と入力すると「error」という文字列を含む行しか送信されません。ログの量が多すぎない限りはここで絞り込む必要はないと思います。
 * 最後の引数はmodeというパラメータで、ログの送信方法を指定します。「all(デフォルト)」と「skip」を選択できます。どちらもログファイルの前回送った分からの差分を送信するのですが、「skip」を選択するとZabbixエージェントが停止していた間のログ送信はされません。これは運用方法に合わせて変えてみてください。
* データ型：「ログ」を選択します。
* 更新間隔(秒)：お好みで。
* ヒストリ保存期間(日)：お好みで。
* ログの時間形式：今回ログには `[2016-03-09 15:20:00] error: ～` の形式で出すことにするので `[yyyy-MM-dd hh:mm:ss]` と入力しました。「yMdhms」以外の文字は考慮されないので書式に合わせて自由に入力します。
* アプリケーションの作成：省略
* アプリケーション：「-なし-」を選択
* 説明：お好みで。
* 有効：チェック

ちなみに、タイプ「Zabbixエージェント(アクティブ)」使う場合はZabbix agent側のconfに設定が必要です。Zabbixサーバ自身を監視対象にしている場合は最初から設定されていたので気にすることはないです。
詳細はこの辺りを参考にすると良いと思います。
https://www.zabbix.com/documentation/2.2/jp/manual/appendix/items/activepassive


### トリガーの設定

続いて上記で作成したアイテムに対してトリガーを設定します。
「設定」->「ホスト」でホスト一覧を表示し、「Zabbix server」の欄の「トリガー」をクリックします。
するとホストに紐付いているトリガー一覧が表示されるので、右上の「トリガーの作成」をクリックします。
以下のように入力しました。

![Zabbixログ監視 - トリガーの設定2.png](https://qiita-image-store.s3.amazonaws.com/0/27159/10ec82ee-07a5-d45e-f9ca-cf0c4736d4cd.png)

各項目についての説明です。

* 名前：お好みで。
* 条件式：あとで説明します。
* 障害イベントを継続して生成：チェックしない
 * これをチェックするとトリガーされるたびにイベントが生成されます。僕はうっとおしいのでチェックを外しています。
* 説明：お好みで。
* URL：お好みで。
 * 設定すると障害時にこのURLが表示されます。
* 深刻度：お好みで。
 * 深刻度によって障害時の色が変わったりします。また、深刻度によって通知設定を変えることも出来ます。
* 有効：チェックします。

さて、肝心の条件式について説明します。

```
{Zabbix server:log[/home/vagrant/zabbix_error_log.log,,,,skip].str("WARNING")}=1
and
{Zabbix server:log[/home/vagrant/zabbix_error_log.log,,,,skip].count(1h,"WARNING")}>4
and
{Zabbix server:log[/home/vagrant/zabbix_error_log.log,,,,skip].nodata(10m)}=0
```

3つの式をand条件にしている記述です。
1行目はちょっと置いておき、3行目から説明します。
これは「1時間以内にWARNINGという文字列が5回以上でたら」という条件式になります。
count関数の第1引数は期間を指定します。「1h(1時間)」という指定や秒数で「3600(1時間)」という指定ができます。
第2引数はパターンを指定します。今回は「WARNING」のみカウントしたいのでそのまま入力します。
第3引数は演算子を指定します。 `eq(等しい)` `ne(等しくない)` `gt(より大きい)` `lt(未満)` `like(部分一致)` などがあります。デフォルトは `like(部分一致)` なので今回は省略しました。
第4引数はタイムシフトというものですが、ここでは割愛します。

3行目は「10分間データがなかったら偽」という条件です。
他の記述だけでは1度トリガーされたら障害状態がずっと続いてしまいます。そのため、10分間データがなかったら障害状態を解除する記述です。

最後に1行目の説明です。
この記述がないと障害発生->復旧後に「WARNING」と関係ないログが出た場合でも再びトリガーされてしまいます。
それを防ぐためにstr関数で「WARNING」が含まれているもののみに限定しています。
冗長な記述に感じますがやむを得ないものです。

### アクションの設定

最後にアクションの設定です。
「設定」->「アクション」->「アクションの作成」をクリックします。
タブが3つあるのでそれぞれ設定していきます。まず1つ目は以下のように入力しました。

![Zabbixログ監視 - アクションの設定 - 1.png](https://qiita-image-store.s3.amazonaws.com/0/27159/1a7bbff7-0429-de90-b78a-e0c76a9ddefd.png)

メッセージのマクロはいろいろあるので詳しくはこちらをご覧ください。
https://www.zabbix.com/documentation/2.2/jp/manual/config/notifications/action/operation/macros
今回のポイントは「直近のログ」と書いたところです。実際のエラー内容を表示するときは

```
1. {ITEM.NAME1} ({HOST.NAME1}:{ITEM.KEY1}): {ITEM.VALUE1}
2. {ITEM.NAME2} ({HOST.NAME2}:{ITEM.KEY2}): {ITEM.VALUE2}
3. {ITEM.NAME3} ({HOST.NAME3}:{ITEM.KEY3}): {ITEM.VALUE3}
...
```

のように書くことが多いですが、ログの場合は誤って違う行が検知されることが多いです。
なので単純にログの直近何件かを表示する以下の記述にしました。

```
{{HOSTNAME}:{TRIGGER.KEY}.last(#1)}
{{HOSTNAME}:{TRIGGER.KEY}.last(#2)}
{{HOSTNAME}:{TRIGGER.KEY}.last(#3)}
...
```

続いて「アクションの実行条件」というタブの設定です。
以下のように入力しました。

![Zabbixログ監視 - アクションの設定2.png](https://qiita-image-store.s3.amazonaws.com/0/27159/fd459824-d1da-5918-1d2f-9f94cece89cd.png)

2つの条件を設定しています。

* トリガーの値が「障害」だったら
* 先ほど設定した「Error log alert」がトリガーされたら

続いて「アクションの実行内容」タブの設定を見てみましょう。

![Zabbixログ監視 - アクションの設定3.png](https://qiita-image-store.s3.amazonaws.com/0/27159/4373c7d3-392e-4b69-4ee6-dc25365edf6e.png)

まず「デフォルトのアクション実行ステップの間隔」についてです。今回は「障害期間中は1分ごとに繰り返し通知」をしたいので「60秒」に設定しておきます。
今回はステップを1つしか作らないのであまりありがたみがありませんが、例えばステップを複数作って「10分」と設定すると「担当者Aに通知 -> 10分後に担当者Bに通知 -> 10分後に担当者リーダーに通知」なんていうエスカレーションも可能です。

続いてポイントとなるのがステップの「終了」を「0(無限)」にしているところです。ここを「1」にしてしまうと障害発生時の1回しか通知が来ませんが、こうすることで障害期間中は60秒ごとに繰り返し通知されます。
ただ、これは設定を間違うと障害が復旧しても永遠と通知が来てしまうので注意が必要です。これを防ぐために先ほどの「アクションの実行条件」に「トリガーが障害だったら」を設定しています。つまり、「復旧したらトリガーしない」ということになります。

これで一連の設定は完了です。

# 実際に障害を起こしてみる

設定完了したので実際に障害を起こしてみましょう。
手動でエラーログに書き込みします。

```bash
echo "[2016-03-09 03:30:00] WARNING: DB接続に失敗しました。" >> zabbix_error_log.log
echo "[2016-03-09 03:31:00] WARNING: DB接続に失敗しました。" >> zabbix_error_log.log
echo "[2016-03-09 03:32:00] WARNING: DB接続に失敗しました。" >> zabbix_error_log.log
echo "[2016-03-09 03:33:00] WARNING: DB接続に失敗しました。" >> zabbix_error_log.log
echo "[2016-03-09 03:34:00] WARNING: DB接続に失敗しました。" >> zabbix_error_log.log
```

そしてZabbixの「監視データ」->「ダッシュボード」を見てみると

![Zabbixログ監視 - ダッシュボード.png](https://qiita-image-store.s3.amazonaws.com/0/27159/62df3ea4-6f83-5399-572b-ce44cadd574f.png)

出ましたね。（下の警告は気にしないでください）
日付をクリックしてページを進んで行くと詳細が見れます。
以下のメッセージが送られてきました。

```
ログにエラーが継続的に発生しました。

▼ Zabbixトリガー内容

ホスト名: Zabbix server
エラーログのパス: log[/home/vagrant/zabbix_error_log.log,,,,skip]
直近1時間のエラー件数：6

Event ID: 592
Trigger: Error log alert
Trigger status: PROBLEM
Trigger severity: Average
Trigger URL: 

▼ 直近のログ
[2016-03-09 03:34:00] WARNING: DB接続に失敗しました。
[2016-03-09 03:33:00] WARNING: DB接続に失敗しました。
[2016-03-09 03:32:00] WARNING: DB接続に失敗しました。
[2016-03-09 03:31:00] WARNING: DB接続に失敗しました。
[2016-03-09 03:30:00] WARNING: DB接続に失敗しました。
```

この後10分間同様のエラーメールが届いたのち、復旧のメールが届きました。
これで完了です。