Kibana の Visualize で利用しているクエリを使って Slack にアラート通知する

Kibana で Visualize している集計値が何かしらの条件に合致した場合に Slack にアラート通知を送りたい。
Alerting から実現できたので、その設定方法をメモ。

題材として Elasticsearch に溜め込まれた Web サーバのアクセスログについて、正常レスポンス（ステータスコード 5xx 以外）が 99.95% を下回った場合に Slack に通知するような Trigger を作成してみる。

![FireShot Capture 005 - 可用性 - Kibana - kibana-log.macloud.jp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179455/9010dac9-feb6-d192-124d-eaa4f85aa946.png)

## 環境

- Kibana 7.1.1

## クエリ作成

### クエリの表示

Vizualize の設定そのものを Alerting 側でそのままソースとして利用することはできないようなので、 Vizualize のクエリをコピーして利用する。

サイドメニューから "Visualize" を選択。
左上の "Inspect" を選択すると右上にドロップダウンメニューが現れるので、これを "View: Requests" に切り替える。
"Request" タブを選択するとクエリが表示されるので、これをコピーしておく。

![FireShot Capture 006 - 可用性 - Kibana - kibana-log.macloud.jp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179455/b850411f-90eb-06f0-1425-2f86e78c4e55.png)

### クエリの修正

後述する Monitor に設定するためにコピーしたクエリを修正する。

#### 集計期間

元々のクエリには静的な集計期間が設定されているため、これを動的な期間に修正する。
例えば過去30日間のように指定する場合は以下のようになる。

```json
{
    "query": {
        "bool": {
            "must": [
                {
                    "range": {
                        "date": {
                            "from": "{{period_end}}||-30d",
                            "to": "{{period_end}}",
                            "include_lower": true,
                            "include_upper": true,
                            "format": "epoch_millis",
                            "boost": 1
                        }
                    }
                }
            ],
        }
    },
}
```

#### 集計値のキー名

後述する Trigger condition でヒット数を参照するためにキーがあると便利なので、設定しておく。

```json
{
    "aggregations": {
        "aggregation_name": {
            "range": {
                "ranges": [
                    {
                        "key": "success",
                        "from": 200,
                        "to": 499
                    },
                    {
                        "key": "failure",
                        "from": 500,
                        "to": 599
                    }
                ]
            }
        }
    },
}
```

#### 合計カウント数の上限撤廃

[デフォルトでは合計ヒット数の上限が 10,000 に設定されている](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html#request-body-search-track-total-hits)ので、その制約を外す。

```json
{
    "track_total_hits": true
}
```

## Alerting の設定

サイドメニューの "Alerting" から設定を行う。

### Monitor の作成

"Monitors" タブを開き、右上の "Create monitor" を選択。
"How do you want to define the monitor?" で "Define using extraction query" を選択し、作成したクエリを貼り付ける。

"Run" からクエリを実行して、右側のパネルに集計値が出力されればオーケー。

### Destination の作成

"Destination" タブを開き、右上の "Create destination" を選択。
"Type" に "Slack" を選択し、 Incoming webhook を別途作成して URL を貼り付ける。

### Trigger の作成

再び "Monitors" タブを開き、先程作成した Monitor を選択する。
画面中部の "Triggers" の "Create" を選択する。

"Trigger condition" を以下のように設定する。
1.0 を掛けているのは実数として演算させるため（やっつけ仕事）だが、もっとスマートな方法がありそう。

```
ctx.results[0].aggregations.2.buckets.success.doc_count * 1.0 / ctx.results[0].hits.total.value * 1.0 < 0.9995
```

"Notification" の "Destination" には先程作成したものを選択する。

## 動作確認

次のように通知が来ればオーケー！

<img width="590" alt="Screen Shot 2020-03-13 at 10.02.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179455/c3ed9aad-58f6-06e6-f5fe-430a71866de8.png">

## 今後の課題

Visualize のクエリに変更が必要な場合は併せて Alerting のクエリも変更しなければならないので、何か上手い方法がないか検討中...。