Supervisorのプロセス異常終了をメールで通知


[Supervisorで簡単にデーモン化](http://qiita.com/yushin/items/15f4f90c5663710dbd56)

上記の続き。

## 目的

* プロセスが落ちてautorestartが頻繁に使われるようなら、それを検知しておきたい。
* いくらautorestartを指定していても、異常終了後に即起動できない状態だと **デフォルト5回リトライで落ちてしまう。**
* supervisorでデーモン化したプロセスが終了してしまった場合に、 **メールで通知させたい。**

## supervisorのイベントリスナー

* **異常終了イベントを検知するイベントリスナーを実装して組み込めばいい。**
    * バージョン3.0からの機能。
* 公式のドキュメントとしては以下の機能の部分。

http://supervisord.org/events.html#event-listeners-and-event-notifications

* メールを送るだけのリスナーなら、 `superlance` パッケージがリスナーの実装の一つとして存在するので、今回はこれを使う。

## superlance

pythonのパッケージ。

記述時点でversion 0.11を使用。

インストールは `easy_install` や `pip` で。
（pythonのパッケージ管理ツール。なければyumなりapt-getなりでpython-setuptoolsをどうぞ）

```sh
pip install superlance
```

又は

```sh
easy_install superlance
```

## supervisorのイベント

リスンしたいイベントは２種類。

1. デーモンが予期せぬリターンコードで終了した。 ==> `PROCESS_STATE_EXITED`
2. デーモンが起動に何度も失敗する。 ==> `PROCESS_STATE_FATAL`

それぞれ、 `superlance` パッケージ内の `crashmailbatch` と `fatalmailbatch` を使う。

（これらのイベントを対象としたもの以外にも、superlanceにはリスナー実装が存在する）

## crashmailbatch

* `PROCESS_STATE_EXITED`イベントをリスンし、メール通知する。
* **これ自身をsupervisorの管理対象プロセスとして登録することで動作する。**

`/etc/supervisord.d/crashmailbatch.ini`として以下の様に作成。

```ini
[eventlistener:crashmailbatch]
command=crashmailbatch --subject="Supervisord EXITED STATE report" --toEmail="toname@example.com" --fromEmail="fromname@example.com"
events=PROCESS_STATE,TICK_60

autorestart=true
stderr_logfile=/var/log/supervisor/jobs/crashmailbatch.log
stderr_logfile_maxbytes=1MB
stderr_logfile_backups=5
stderr_capture_maxbytes=1MB
```

前の記事同様、/var/log/supervisor/jobs/ディレクトリにエラーログを吐くのでディレクトリは作成しておくこと。

#### crashmailbatchコマンド

`command`で指定している通り、これ自身はただのコマンド。

`crashmailbatch`を引数なしで打つとヘルプがでるので、
SMTPサーバ、認証ユーザ等を変更する場合には参照する。

#### SMTPサーバ

**デフォルトではlocalhost。**
適宜サービスを立てるか、上記の`crashmailbatch`コマンドオプション(-H)で指定する。

#### メール送信インターバル

デフォルトは **１分に１度。**

こちらも`crashmailbatch`のコマンドオプション(-I)で変更可能。


#### リスンするイベント

`events`でリスンするイベントを書く。
`PROCESS_STATE`としても`PROCESS_STATE_EXITED`としても結果は変わらない。
`PROCESS_STATE`をリスンすれば、その子イベントとなる`PROCESS_STATE_EXITED`もキャッチする。
しかし`crashmailbatch`が処理するイベントは`PROCESS_STATE_EXITED`のみである。（`crashmailbatch`のソースに記述…)

#### stdoutをキャプチャしないこと。

上記のコンフィグではstderrのキャプチャを行っているが、 **stdoutは取ってはいけない。**

どうもメールの送信時に標準出力を使っているらしく、stdoutをこの設定で取るとメールが送信されない。

## fatalmailbatch

`PROCESS_STATE_FATAL`イベントをリスンし、メール通知する。

これ自身をsupervisorの管理対象プロセスとして登録することで動作する。

`/etc/supervisord.d/crashmailbatch.ini`として以下の様に作成。

```ini
[eventlistener:fatalmailbatch]
toname@example.com" --fromEmail="fromname@example.com"
command=fatalmailbatch --subject="Supervisord FATAL STATE report" --toEmail="toname@example.com"　--fromEmail="fromname@example.com"
events=PROCESS_STATE,TICK_60

autorestart=true
stderr_logfile=/var/log/supervisor/jobs/fatalmailbatch.log
stderr_logfile_maxbytes=1MB
stderr_logfile_backups=5
stderr_capture_maxbytes=1MB
```

コンフィグの指定方法は`crashmailbatch`とほぼ同じ。

## リスナーの起動

他のsupervisor管理プロセスと方法は同じ。

上記のようにコンフィグを作成した後に、例えば下記の様に実行する。

```
% supervisorctl
supervisorctl > reread
supervisorctl > add crashmailbatch
supervisorctl > add fatalmailbatch
supervisorctl > status
supervisorctl > exit
```


## 確認方法

* supervisor管理のプロセスを、`kill`コマンドでTERMINATEさせてみる。
    * EXITEDのメール通知が`crashmailbatch`によって行われる。
* supervisord管理のプロセスを、コンフィグを編集して`command`のパスを存在しないものにし、FATAL終了させてみる。
    * FATALのメール通知が`fatalmailbatch`によって行われる。

## この設定の意味

* 結局supervisorの生成プロセスだけ監視しても、 **supervisord自身が落ちては意味がない。**
    * イベントリスナー自身もsupervisorのプロセスなので。
* **monitとか使って簡単にプロセス監視書いた方がよくないか。**
* ついでにその監視でsupervisordも監視させた方がよくないか。

......はい。あえて使う意味はというと。

* **設定が容易。**
* supervisor外部の監視を使わなくても、supervisordだけで完結する。
* supervisordにプロセスを増やしても、監視設定を増やさなくて良い。
    * 外部の監視はsupervisor自身のみでよい。
* supervisordでデーモン化するようなものはプロセス名が特定しにくい（ **ことが多い、かもしれない**）のでmonitとかで書きにくい。
    * ただのこじつけ。

真面目に監視したいならやはり外部の監視に頼った方が良いでしょう。