Mackerelでバッチの成否監視

https://qiita.com/saoyagi2/items/1be430ecd3b4d962da56

こちらの記事で書いたアイデアですが、3年も経ってようやく実際に試すことが出来ました。3年も何やってたんだよと自分でも思いますが、まあそれだけ自分自身が運用監視から離れたことで興味がなくなってしまったんですよね。

やりたいことはリンク先に書いたのですが、こちらで改めて簡単にまとめておきます。

* 仕込んだバッチ処理の成否を監視したい。
* 成功をメールやチャットツールに報告した場合、「成功していない」ことを自分で見つけ出さないといけない。
    - 対象のバッチ処理が多数あると、とてもチェックしきれない。
* バッチ処理に失敗した場合にメールやチャットツールに報告したいがいくつか難点がある。
    - バッチ処理の失敗報告機能に不具合があると報告されない(バッチ機構側で異常検知することは出来る)。
    - バッチ機構(cron など)の設定にミスがあってバッチ処理がそもそも起動されていなかったら報告されない。
* バッチ処理の成功を監視ツールにステータスとして送信し、ステータスが正常でなくなった場合に監視ツールからアラートをあげてはどうか。
    - 原発などの重要施設では通常時に警報が常に鳴っていて、異常時には警報が止まることで警報装置自体が故障していても異常を感知できるそうで、それに近しい考え方。フェイルセーフ的というか。

監視ツールとしては Mackerel を使用しました。

## やりかた

Mackerel にはチェック監視という機能があります。監視対象はステータスで「OK」「CRITICAL」「WARNING」「UNKNOWN」の値を取れますので、バッチ処理の成否監視としてはピッタリです。

しかし、チェック監視は Mackerel エージェントのプラグインからしか送信できないため、バッチ処理自体からステータス送信ができません。バッチ処理からはログを吐いて、プラグインからログを解析してステータスを送信すれば出来ますが、実装がその分複雑になってしまいます。

また、チェック監視は致命的なことに監視ルールで途切れ監視が設定できません。これではバッチ機構自体に障害があった場合に検知できなくなってしまいます。バッチ機構自体も別で監視するにしても、バッチ処理が実行できなかったアラートも上げて欲しいですよね。

ということで今回はサービスメトリック監視を使うことにしました。サービスメトリック監視では数値が送信できますので、今回は成功時は 1 を、失敗時は 0 を送信することにします。

サービスメトリックの投稿は API で簡単に行えます。ドキュメントはこちら。

https://mackerel.io/ja/api-docs/entry/service-metrics#post

実際に作ったバッチ処理はこんな感じです。

```bash
#!/usr/local/bin/bash

API_KEY="xxx"
STATUS=1

curl https://api.mackerelio.com/api/v0/services/all/tsdb \
  -H "X-Api-Key: ${API_KEY}" \
  -H "Content-Type: application/json" \
  -X POST \
  -d '[{"name": "Batch.test", "time": '$(date +%s)', "value": '${STATUS}'}]'
```

こちらを crontab で1分に1回起動するように設定しました。

```:crontab
* * * * * $BINDIR/mackerel-test-batch.sh > /dev/null 2>&1
```

## 実際の動作の様子

Mackerel のサービスメトリックのグラフはこちら。値は 1.0 に張り付いています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/30454a95-14b5-7803-54d2-9338fc6aab45.png)

次に監視ルールを作成します。Critical条件として「1未満になった場合」を、途切れ監視の Critical条件として10分を設定します(途切れ監視は10分未満は設定できないようです)。

途切れ監視の発動時間はバッチ処理実行間隔プラスアルファに設定します。1時間おきに実行するバッチ処理なら1時間10分とかですね。2時間でもいいかもしれません。バッチ処理間隔そのままですと、バッチ処理が前回よりも実行時間が長くなっただけで発報してしまいますので。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/641c10a2-43d6-7cdd-3ae5-6cb30d839342.png)

さて、実際に発報させてみます。まず送信値を 0 にしてみます。

```bash
STATUS=0
```

Mackerel のグラフが 0 に落ちました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/5a5081e0-d3f3-6a47-f665-5f1e7acc2c38.png)

そしてアラートも発報されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/9444d038-201e-cf1e-9b9b-56074526bbb0.png)

送信値を 1 にもどしてみます。

```bash
STATUS=1
```

Mackerel のグラフが 1 に戻りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/bdcea10a-d913-1410-cf8f-421c911b13d7.png)

アラートもクローズされています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/07859646-6637-c6b6-aa43-4969bc01431b.png)

次に、バッチ処理の実行そのものを止めてみます。

```:crontab
# * * * * * $BINDIR/mackerel-test-batch.sh > /dev/null 2>&1
```

グラフが途切れました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/ce1e388c-945c-2cd2-67be-7d95dbd324b3.png)

グラフが途切れて10分後、アラートきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/13935e9f-a937-3dad-e320-31be5b45cf2e.png)

再びバッチ処理を実行するようにします。

```:crontab
* * * * * $BINDIR/mackerel-test-batch.sh > /dev/null 2>&1
```

クローズされました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/11732db9-3301-624a-d5a0-0232508b1a75.png)