elasticsearch5系 alerting機能を使いコードを書かずに簡単にslack通知を実装する



ealsticsearchにログデータを溜めている場合、そのデータを集計してしきい値超えたらslack通知したいというのは、よくあるユースケースかと思う。

[elastalert](https://elastalert.readthedocs.io/en/latest/index.html)というツールが流行っていたりすることからも明らかで、自前でツールを作って運用されている方も多いと思う。

自分も、pythonで作ったツールでその機能を実現していたが、elasticsearchの[alerting](https://www.elastic.co/jp/products/x-pack/alerting)を使って、これまでの処理を置き換えたので、そのメモを残しておく。

## Alerting機能とは

elasticsearchに登録するcronのようなもので、indexされているデータに対して、定期的にクエリを実行して通知というような機能を実装する事が出来る

何がうれしいかというと

- cronを実行する為のサーバが不要(サーバレス)
- 簡単なjsonを書くだけで、自前でコードを書きメンテナンスしていく必要がない

※elasticcloudの32GBプラン以下だと無償で使える
※通常は、x-packというelasticsearchの有償プラグインにバンドルされている機能

## Alertingを書くにあたり理解すべき構成要素

elasticsearchのalerting機能は下記の4要素を組み合わせて作られる。比較的わかりやすい構造になっている。

###input:

elasticsearchに投げるクエリを定義する

###triggers:

スケジューラの機能

###conditions

inputの出力からactionsを動かす条件を定義

###actions

conditionsにマッチした場合のアクション
※slack通知とか何かのクエリを発行するとか


##サンプルを動かしてみる

テーマ: 適当に作ったテストINDEXに対してクエリを発行して閾値を超えたらslack通知する

####サンプルデータ

id,level,datetimeの3フィールドを持つシンプルなインデックスを作った。

```
    "hits": [
      {
        "_index": "test_nagai1",
        "_type": "test1",
        "_id": "AVuKaxAdGdCIUEfpcX22",
        "_score": 1,
        "_source": {
          "id": "nagais",
          "level": "INFO",
          "datetime": "2017-04-20T16:11:02+09:00"
        }
      },
      {
        "_index": "test_nagai1",
        "_type": "test1",
        "_id": "AVuKaty4GdCIUEfpcX2x",
        "_score": 1,
        "_source": {
          "id": "nagais",
          "level": "ERROR",
          "datetime": "2017-04-20T17:11:01+09:00"
        }
      },
      {
        "_index": "test_nagai1",
        "_type": "test1",
        "_id": "AVuKaud8GdCIUEfpcX2y",
        "_score": 1,
        "_source": {
          "id": "nagais",
          "level": "ERROR",
          "datetime": "2017-04-20T17:11:02+09:00"
        }
      }。。。


```

####サンプルジョブ

#####仕組み
- `_xpack/watcher/watch/`にJSON形式でジョブを登録する形
- deleteするとジョブは止まる。 `DELETE _xpack/watcher/watch/errorlog_notify`

```
PUT _xpack/watcher/watch/errorlog_notify
{
  "trigger": { #30秒間隔
    "schedule": {
      "interval": "30s"
    }
  },
  "input": { #1分以内でlevelフィールドがERRORかFATALのもの
    "search": {
      "request": {
        "indices": [
          "test_nagai1"
        ],
        "body": {
          "query": {
            "bool": {
              "must": [
                {
                  "range": {
                    "datetime": {
                      "gte": "now-1m",
                      "lte": "now"
                    }
                  }
                },
                {
                  "regexp": {
                    "level": "(ERROR|FATAL)"
                  }
                }
              ]
            }
          }
        }
      }
    }
  },
  "condition": { # 検索結果が1件以上のもの
    "compare": {
      "ctx.payload.hits.total": {
        "gte": 1
      }
    }
  },
  "actions": { #slack通知のプロファイル(icon_emojiはサポートされてなかった様子💧)
    "notify-slack": {
      "slack": {
        "message": {
          "from": "ESwatcher",
          "to": [ #ここでチャンネルを指定
            "#elastic_alerting_test"  
          ],
          "text": "EScloud error log watcher",
          "attachments": [
            {
              "title": "Loglevel Error",
              "text": "loglevel error too many\nerror_count: {{ctx.payload.hits.total}}",
              "color": "danger"
            }
          ]
        }
      }
    }
  }
}
```

####結果

こんな感じで通知が来ます。

![Slack_-_ikyu.jpg](https://ikyu.qiita.com/files/4cb1aa7a-50b5-5b42-7115-0c8015e14a47.jpeg "Slack_-_ikyu.jpg")


####ジョブ履歴を確認

過去1分以内のジョブを確認するみたいなのはこんな感じで！

```
GET .watcher-history*/_search
{
  "query" : {
    "bool" : {
      "must" : [
        { "range" : { "result.execution_time" : { "from" : "now-1m" }}}
      ]
    }
  }
}
```

## 参照

https://www.elastic.co/guide/en/x-pack/5.1/xpack-alerting.html

##所感

動かす環境準備して、pythonでelasticsearchのクライアント使ってデータ引いてきて、加工して、slackクライアントで通知してみたいな処理
↓
JSON書いてelasticsearchに登録して完了

かなり省力化出来るので、使える環境にある人は積極的に使っていった方がいいと思った。