ElastAlert による Elasticsearch のインデックス監視・通知

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、藤本です。

Elasticsearch を利用していて、インデキシングされるドキュメントのデータを監視したいことはないでしょうか。例えば、よくユースケースの紹介に挙げられるアクセスログを Elasticsearch にインデキシングしているケースでは、500番台のステータスコードが5分間に10回以上記録があった時に、Slack で通知したい。ログファイルの集約に Elasticsearch にインデキシングしている場合、ERROR のメッセージを含むメッセージを検知した時に、メール通知したい。など、Elasticsearch のインデックスを監視・通知したいケースは多々あるかと思います。

先日、X-Pack の Watcher による Elasticsearch のインデックス監視・通知をご紹介しました。

Elastic StackのX-Packを試す(Watcher編)

今回はもっと手軽に利用できる OSS ツールをご紹介します。

ElastAlert

ElastAlert は Yelp が開発している Elasticsearch のインデックスにあるドキュメントを監視、通知する OSS ツールです。2016/11/14現在は Elasticsearch 1系、2系に対応しており、まだ5系は未対応です。ElastAlert は大きく監視ルール、通知の2つのコンポーネントから成り立ちます。監視ルールはどのくらいの間隔で、どういう Elasticsearchクエリを発行して、何を条件として通知するのか定義します。通知は監視ルールの条件に合致した時にどういう通知を行うのかを定義します。設定はグローバルコンフィグ、個別監視設定をYAML形式で記述します。

監視ルールタイプ

ElastAlert は現在9種類のルールタイプをサポートしています。

監視ルールタイプの説明は下記サイトが参考になります。
elastalertでアプリの異常を自動検知して通知したい

Any

常に通知します

Blacklist

指定したフィールドが指定した値にマッチした時に通知します。

Whitelist

指定したフィールドが指定した値にマッチしなかった時に通知します。

Change

指定したフィールドの値が変化した時に通知します。

Frequency

指定した期間内に指定したクエリのドキュメント件数が指定した値以上の時に通知します。システム異常を検知できます。

Flatline

指定した期間内に指定したクエリのドキュメント件数が指定した値より少ない時に通知します。システム異常を検知できます。

Spike

指定したクエリのドキュメント件数が前回取得のクエリ結果の指定した値の倍数以上の時に通知します。突発的なアクセス増加を発見できます。

New Term

指定したフィールドの値が指定した期間内に同じ値がない時に通知します。未知のログ出力を発見できます。

Cardinality

インデックスのフィールド数が増えた時に通知します。データソースのフォーマットの変化を発見できます。

設定可能な項目はソースコード内にある schema.yaml に定義されています。

通知方法

ElastAlert は現在11種類の通知方法をサポートしています。

Email

指定したメールアドレスへメール通知します。

JIRA

Atlassian の JIRA へチケットを起票します。

OpsGenie

OpsGenie を介して様々な通知を行えます。

Commands

ElastAlert が動作する OS 内で指定したコマンドを実行します。

HipChat

HipChat のチャットルームへ通知します。

Slack

Slack のチャットルームへ通知します。

Gitter

Gitter のチャットルームへ通知します。

Telegram

Telegram へ通知します。

AWS SNS

AWS の SNS Topic をパブリッシュします。

VictorOps

VictorOps を介して様々な通知を行えます。

PagerDuty

PagerDuty を介して様々な通知を行えます。

X-Pack と ElastAlert の比較

ザックリ表にまとめました。有償プロダクトの X-Pack は充実した機能、Elasticsearch のバージョンとの安定性、Elastic社からのサポートがあり、安心して利用できます。一方の ElastAlert は無償利用、シンプルなPython実装のOSSなのでフォークして拡張したり、動作が分からない時にソースコードから原因解析することができます。実際、検証していてちょっとハマった時もソースコード読めば原因を特定することができました。またAWS専業の弊社としては Amazon ES、Amazon SNS に対応しているのは嬉しいです。特に Amazon SNS と連携しているので、Amazon SNS から AWS Lambda をキックすれば、ユースケースはかなり広がるでしょう。

X-Pack ElastAlert
コスト 要サブスクリプション OSS(Python実装)
トリガー お互いスケジューリング
監視方法 Elasticsearchクエリ
Webリクエスト
固定値
上記の組み合わせ
Elasticsearchクエリ
条件 柔軟な条件 特定の条件(前述)
通知方法 Email
Webhook
Index
Logging
HipChat
Slack
PagerDuty
Email
JIRA
OpsGenie
Commands
HipChat
Slack
Telegram
AWS SNS
VictorOps
PagerDuty
Gitter
設定管理 インデックス YAMLファイル
バージョン対応 基本的に最新バージョンに追従 1.X、2.X対応(2016/11/06時点)
サポート サブスクリプションによる
Elastic社からのサポート
なし
OSSなのでGithubのIssueなどで
AWS対応 Amazon ES対応
通知にAmazon SNS利用可

試してみた

今回は最初に記載したユースケースのアクセスログの500番のステータスコードが5分間に10回以上記録があった時に、Slack で通知したい、を実装します。Webサーバのアクセスログを Logstash を利用して、準リアルタイムで Elasticsearch に取り込んでいます。監視したいステータスコードはresponseというフィールド名でデータを保持します。

環境

  • Elasticsearch Node
    • OS : CentOS 7.2
    • Elasticsearch : 2.4.1
  • ElastAlert動作環境
    • OS : MacOS
    • Python : 2.7.12
    • ElastAlert : 0.1.3

インストール

ElastAlert は pip でインストールできます。現在サポートされている ElastAlert のPythonバージョンは 2.6系、2.7系となります。ElastAlert は ElasticsearchとのインタフェースにElasticsearch-py を利用します。なので、基本的には Elasticsearch のメジャーバージョンに合わせたバージョンの Elasticsearch-py を利用してください。現在、pip にてインストールすると Elasticsearch-py の5系がインストールされます。今回は Elasticsearch 2.4.1 を利用したので、Elasticseach-py の2系の最新バージョンをインストールしています。

# pip install "elasticsearch>2.0.0,<3.0.0" elastalert
Collecting elasticsearch<3.0.0,>2.0.0
  Using cached elasticsearch-2.4.0-py2.py3-none-any.whl
Collecting elastalert
:
Installing collected packages: urllib3, elasticsearch, simplejson, six, python-dateutil, requests, oauthlib, requests-oauthlib, tlslite, jira, boto, blist, functools32, jsonschema, croniter, aws-requests-auth, texttable, jmespath, docutils, botocore, funcsigs, pbr, mock, configparser, argparse, pyyaml, PyStaticConfiguration, elastalert
Successfully installed PyStaticConfiguration-0.10.2 argparse-1.4.0 aws-requests-auth-0.3.0 blist-1.3.6 boto-2.43.0 botocore-1.4.70 configparser-3.5.0 croniter-0.3.13 docutils-0.12 elastalert-0.1.3 elasticsearch-2.4.0 funcsigs-1.0.2 functools32-3.2.3.post2 jira-0.32 jmespath-0.9.0 jsonschema-2.5.1 mock-2.0.0 oauthlib-2.0.0 pbr-1.10.0 python-dateutil-2.5.3 pyyaml-3.12 requests-2.11.1 requests-oauthlib-0.7.0 simplejson-3.10.0 six-1.10.0 texttable-0.8.6 tlslite-0.4.9 urllib3-1.19

インストールはこれだけです。

初期設定

ElastAlert は Elasticsearch のインデックスで ElastAlert の実行履歴、差分情報を管理します。まずは管理用のインデックスを生成します。コマンドで対話形式で設定します。

# elastalert-create-index
New index name? (Default elastalert_status) ⇐ デフォルトの場合はそのままEnter
Name of existing index to copy? (Default None) ⇐ デフォルトの場合はそのままEnter
New index elastalert_status created
Done!

設定ファイル作成

ElastAlert の設定ファイルはグローバルコンフィグ、個別監視設定の2つのYAMLファイルから成り立ちます。

グローバルコンフィグ作成

個別監視設定を横断した共通設定のコンフィグファイルを作成します。設定値は個別監視設定が優先され、個別監視設定になければ、グローバルコンフィグから参照する関係性となります。例えば、各監視ルールの通知先 Slack チャンネルが共通であれば、Incoming Webhook URL をグローバルコンフィグに指定することが可能です。

グローバルコンフィグでは以下の設定項目が必須となります。

設定キー 説明
es_host 接続する Elasticsearch のホスト名・IPアドレス
es_port 接続する Elasticsearch のポート番号
rules_folder 個別監視設定のYAMLファイルが配置されたディレクトリパス
buffer_time データ取得期間
run_every 監視する間隔
writeback_index 実行履歴を管理するインデックス名
config.yaml
es_host: 10.255.0.100
es_port: 9200
rules_folder: rules
buffer_time:
  hours: 1
run_every:
  minutes: 1
writeback_index: elastalert_status

個別監視設定

個別監視設定では監視ルール、通知方法を定義します。

監視ルール設定

今回はある期間内にしきい値を超えるドキュメント数があった時にアラートを上げたいので、監視ルールタイプに Frequency を利用します。Frequency ルールでは以下の設定が必要となります。

設定キー 説明
type frequency
name 監視ルールの名前
index 監視対象のインデックス名(ワイルドカード(*)を利用可)
num_events しきい値。期間内にしきい値を超えたらアラート
timeframe 監視期間
アラート設定

今回は Slack チャンネルに通知したいので、通知方法は Slack を利用します。また Slack 通知する場合、通知を受け取りたいチャンネルで Incoming Webhook を有効化してください。Slack 通知では以下の設定が可能です。

設定キー 説明
alert slack
slack_webhook_url 通知を受け取りたいチャンネルの Incoming Webhook URL
slack_username_override 通知ユーザー名
デフォルト値は elastalert
slack_emoji_override 通知ユーザーアイコン
デフォルト値はゴーストアイコン
slack_icon_url_override 通知ユーザーアイコン
slack_msg_color 通知メッセージの引用ラインの色
slack_parse_override 通知メッセージのエスケープの有無
slack_text_string 付加したい通知メッセージ
rules/status500-moniroting.yaml

今回は最低限の設定としています。

監視したい Elasticsearch のインデックスは logstash- から始まる全てとします。5分間に10回という条件はnum_eventstimeframeで指定します。今回は response フィールドが 500 の値だけをカウントしたいので term クエリでフィルターします。

アラート設定のslack_webhook_urlは利用するチャンネルのURLに置き換えてください。

name: status500-moniroting
type: frequency
index: logstash-*
num_events: 10
timeframe:
    minutes: 5
filter:
  - term:
      response: 500
alert:
  - slack
slack_webhook_url: "https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxx/xxxxxxxxxxxxxxxxxxx"

動作確認

ElastAlert を起動します。

# elastalert

config.yaml のbuffer_timeで指定した期間内に監視ルールの条件にマッチしなければ、特に何も起きません。今回の設定では過去1時間の中で5分間にステータスコード500のリクエストが10回発生していなければ、通知されません。

次に監視条件にマッチするようにステータスコード500が発生するリクエストを10回以上送信します。

config.yaml のrun_everyの次のクエリで検知します。

Slack 通知が発生します。

screenshot 2016-11-13 12.22.31

通知メッセージは監視ルールに応じたメッセージと検知した最新のドキュメントを受信します。

Slack_-_cm-fujimoto_shinji

まとめ

いかがでしたでしょうか?

インストールはpipで、設定はYAMLファイルだけですので、非常に簡単に利用することができました。機能も豊富で、公開されて1年半ぐらい経過していますが、現在も定期的にコミットされていてメンテナンスされているようですので安心して使えそうです。