Datadog Monitor から Webhook で Lambda 起動

前回 Datadog から SNS 経由で Lambda Function を起動を行いました。
別の方法を探してみた所、Webhook Integration が使えそうだったので試してみました。
1) API Gateway と Lambda Function を作成
API Gateway を trigger として Lambda Function を作成します。APIへは AccessKey認証 とします。

今回使用した Lambda Function は、受け取った内容をそのまま Slack へポストするだけの物です。
2) CloudFront Distribution 作成
API Gateway の Endpoint をそのまま叩けば良いかと考えたのですが、Datadog の Webhook が SSLv3 を使用しているようで以下のようなエラーが発生します。

Datadog 側での設定変更は無いようだったので、CloudFront を挟む事で回避させます。
Origin Domain Name へ API Gateway の Invoke URL を入力します。 (Origin Path、Origin ID は自動的に入力されます。)

また、AccessKey認証のため WhiteList Headers に x-api-key を設定します。

3) Datadog Webhook Integration 設定
Integration → Webhooks → Configuration に CloudFrontのエンドポイントと API Gateway の API Key を設定します。

正常に登録できていれば、Monitor の Nortify 設定で Webhook: 〜 が選択できるようになります。

実行例
Datadogのアラート発行をトリガーに、Lambda Function が起動した事を確認できます。
- Lambda Function Log

- Slack

CloudFront を介す必要がありますが、 メッセージのカスタマイズもある程度可能なため、 SNSでの通知より柔軟に処理設定できるのではないでしょうか。
Datadog MonitorからSNS経由でLambda起動
Datadog から SNS(Amazon Simple Notification Service) への通知ができるということで、 Datadog → SNS → Lambda → Slack で通知情報に+αで情報付与をしてみます。

題材
Lambda で実行可能な物でしたら何でも良いのですが、常々不便を感じていた CloudFront のエラー通知で試してみました。
CloudFront で ErrorRate 上昇時に Datadog から Slack へ通知します。 これは Datadog の通常の機能(Metric Monitor)で実現できます。ですが、CloudFront の Tag は取得していないようで通知メッセージには DistributionId しか出力されません。

DistributionId で判別するのは中々敷居が高いので CNAME と OriginName を後追いで付与します。
1) Monitor 通知先の作成
通知先として使用する Slack と SNS の設定です。
Datadog の Integration ページの Configuration 記載内容に沿って各種設定を行います。
1-1) Slack
Incoming WebHook を作成します。
Datadog 側への設定に Webhook URL が必要になりますので、Slack の Configure Apps に追加します。

1-2) SNS
使用する SNS Topic を作成します。
例では dd-alert という名前で作成しました。

通知先設定の確認
正常に登録できていれば Datadog の Monitor 作成画面で選択可能になります。

2) Datadog Monitor の作成
Lambdaの関数を起動するトリガーとする Monitor を作成します。
例では 5xx Error Rate のメトリクスを使用しました。
尚、5xx Error Rate 等の未発生のメトリクスは Edit で選択できないので、初回は直接 Source に書く必要があるかもしれません。
通知先として作成した Slack Incoming WebHook と SNS topic の2つを指定します。

avg(last_15m):max:aws.cloudfront.5xx_error_rate{*} by {distributionid} > 10
5xx Error Rate over {{#is_alert}}{{threshold}}%{{/is_alert}}{{#is_warning}}{{warn_threshold}}%{{/is_warning}}
{{^is_recovery}} @slack-notice @sns-dd-alert {{/is_recovery}}
3) Lamdba Function の作成
アラート通知が発生した際に実行したい関数を作成します。 Slack通知がメインとなるため cloudwatch-alarm-to-slack-python をベースに作成しました。 IAM role へは CloudFrontReadOnlyAccess を付与しています。

Environment variables に作成した Slack Incoming WebHook と SNS topic を設定します。

例ではSNSを受け取り、通知された DistributionId を基に CNAME と OriginDomainName を取得します。
実行例
アラート発生した場合に通知される内容の例です。 タイミングにより通知される順序は前後します。
- 先にSNS

- 後にSNS

今回題材にした CloudFront の名称取得はその内 Datadog 側で対応してくれそうですが、
アラート受けてから別に確認していた情報を付与、実行していた処理を自動実行させる等、
色々と応用が効きそうです。
Datadog Monitorで復旧通知を行わない方法
DatadogのMonitorでの通知設定で復旧(Recovery)通知を行わない方法です。

template variables 内に通知先を設定する

通知先を含めて {{#is_alert}}{{/is_alert}} もしくは {{^is_recovery}}{{/is_recovery}} 内に記載 します。
言われてみればなるほどなのですが、しばらくこの発想に至らず、復旧通知は必須なのかと誤解していました。
以下誤解していた理由(言い訳)です。
例文を見ただけではわからなかった

初期表示状態の例文を見て、 {{#is_alert}}|{{#is_recovery}}を使って、異常時と復旧時の通知メッセージを変える物と認識しました。 (そのような使い方ももちろん可能です)
通知先指定時に末尾に設定される

このような感じで(3)のアラート文面を書いた後に(4)の通知先を設定すると、アラート文面の末尾に通知先が追記されます。

そのため、変数({{#is_alert}}{{/is_alert}}など)の中に通知先を入れられると考えませんでした。
尚、ドキュメント内にも通知先をtemplate variables内に設定する例はありませんでした。
■い頭は●くしないといけないと思いました。
AWS RDSイベント通知を受け取る
追記
よく質問されるので追記。
DatadogにはAWSで発生したイベントを拾ってくれる機能がありますが、RDSのイベントは含まれていません。
投稿時点の話で、現在はRDSイベントもDatadog上で取得できます。

RDSのイベント通知機能としてEvent Subscriptionがあり、イベント発生時に任意のメールアドレスに通知ができます。

メールのアラート受信は埋もれやすいので、DatadogとSlackへ通知します。
基本的にはメール送信による投稿が可能なサービスへの連携が可能と思います。
目次
RDSイベント通知
設定すると以下の様なFailover等のイベント発生時に設定したメールアドレス宛に通知してくれます。

RDSイベント通知設定

AWSマネジメントコンソールのRDSダッシュボードから EventSubscription -> CreateEventSubscription

"create topic"リンククリックで、メールアドレスを入力できるようになるので、通知したい宛先を入力します。
Datadog、Slackへの通知に使用するメールアドレス取得方法は後述します。

Datadogへ通知
DatadogにはAWSで発生したイベントを拾ってくれる機能がありますが、 RDSのイベントは含まれていません。

Datadogにメールによる投稿を行うことで、Eventsへ出力させます。
Datadogメールアドレス払い出し
Integrations -> APIs

Create API Email

メールアドレス(event-XXXXX@dtdg.co)が払い出されます。
Datadog上でConfirm
RDSイベント通知設定にメールアドレスを登録するとConfirmationのメールが届きます。
Datadogの場合はEvents画面上で参照できます。

Confirm subscriptionのリンクをクリックし、認証を完了します。

イベント発生時には以下の様なメッセージが通知されます。

Slackへ通知
Slackメールアドレス払い出し
Integrations -> Email

Create an Email Integration

メールアドレス(xxxxx@XXXXX.slack.com)が払い出されます。
投稿したいチャンネル、アイコン等を設定します。

Slack上でConfirm
RDSイベント通知設定にメールアドレスを登録するとConfirmationのメールが届きます。
Slackの場合は以下のようなメッセージが届きます。

Confirm subscriptionのリンクをクリックし、認証を完了すると、以下の様なメッセージが通知されます。

まとめ
クリティカルなイベントは標準でアカウント宛に通知してくれても良いのではと思いました。
まだまだ根強いですが、Eメールでアラート受信の運用は止めたいです。
以下、余談です。
DatadogにEventをトリガーにアラート通知する機能があります。が、
フィルタが正常に起動しなかったり、1分単位で発生したイベントを掴めなかったりと、現時点では少々挙動が怪しいです。
サポートさんへissueを挙げてますので修正されることを期待します。
Datadog からデータ出力を試してみる
モニタリングクラウドサービス Datadog からメトリクス(データ)を取得して、テキスト出力をしてみます。 値の一覧を見る画面は用意されていませんのでAPIを使用します。
シェルスクリプト(sh)での例文が出ているのでそちらを使用します。その他にPython,Rubyのリファレンスが記載されています。
Application/API Key の取得
メニューからAPIsをクリック→API発行画面でApplicationKeyを発行できます。

クエリストリングの取得
データ取得用のqueryが必要になるので、既存グラフから拝借します。 今回はDatadogAgentで取得できるnginxのrequest_per_sの値を取得します。

グラフのJSONの"q"部分をパラメータとして使用します。
"q": "max:nginx.net.request_per_s{example} by {name}",
データ値一覧の取得
Referenceページの QUERY TIME SERIES POINTS を使用します。
- from/to はUNIXTIMEで指定
- queryにJSONから取得した"q"の内容(半角スペースを除外)を指定
#!/bin/sh
api_key=取得したAPIキー
app_key=取得したアプリケーションキー
to_time=$(date +%s) # UNIXTIME指定
from_time=$(date -v -20M +%s) # UNIXTIME指定
curl -G \
"https://app.datadoghq.com/api/v1/query" \
-d "api_key=${api_key}" \
-d "application_key=${app_key}" \
-d "from=${from_time}" \
-d "to=${to_time}" \
-d "query=max:nginx.net.request_per_s{example}by{name}"
- 出力例
日時と値がタイムスタンプ(UNIXTIME)順に出力されます。
{"status": "ok", "res_type": "time_series", "series": [{"metric": "nginx.net.request_per_s", "attributes": {}, "display_name": "nginx.net.request_per_s", "unit": [null, null], "pointlist": [[1442528400000.0, 0.21052631735801697], [1442528410000.0, 0.21052631735801697],
・・・略・・・
[1442529580000.0, 23.615476608276367], [1442529590000.0, 22.850000381469727]], "end": 1442529599000, "interval": 10, "start": 1442528400000, "length": 120, "aggr": "max", "scope": "name:sververXX,example", "expression": "max:nginx.net.request_per_s{name:sververXX, example}"}], "from_date": 1442528400000, "group_by": ["name"], "to_date": 1442529600000, "query": "max:nginx.net.request_per_s{example}by{name}", "message": ""}
データ値一覧の取得(csv変換)
jqでcsv形式に変換し、時系列に並べます。上記の結果をoutput.jsonへ出力した前提です。
jq -r '.series[] | { scope: .scope ,pointlist: .pointlist[] } | [.scope ,.pointlist[0] ,.pointlist[1]] | @csv' output.json | sort -t ',' -k 1,3
うーん・・・美しくない・・・。
- 出力例
"name:sververXX,example",1442528400000,0.21052631735801697 "name:sververXX,example",1442528410000,0.21052631735801697 "name:sververXX,example",1442528420000,0.21052631735801697 "name:sververXX,example",1442528430000,0.1875 ・・・略・・・ "name:sververXX,example",1442529570000,24.380952835083008 "name:sververXX,example",1442529580000,23.615476608276367
きっと便利なツールなどが既に公開されていたりするのでしょうが、 環境を選ばないのでシェルスクリプトでの出力をとりあえず試してみました。
Datadog nginx Integration を試す
※画像と内容は一切関係ありません

Datadogのnginxインテグレーション設定を試してみます。
と言っても下記ページ通りで簡単に取得できます。
取得できるメトリクスは以下になります。
nginx.net.connections nginx.net.reading nginx.net.request_per_s nginx.net.waiting nginx.net.writing
nginx stub status 有効化
今回の環境は CentOS 6.7 に公式サイトから nginx をインストールしています。
# nginxインストール $ sudo rpm -Uvh "http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm" $ sudo yum install nginx # stub_statusモジュールの導入確認 $ nginx -V |& grep http_stub_status_module configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_spdy_module --with-cc-opt='-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic'
設定ファイルを変更します。ローカルホストからのみアクセスを受け付けるよう設定しています。(設定箇所はお好みで)
$ sudo vi /etc/nginx/conf.d/default.conf
・・・略・・・
# nginx_status有効化(許可IPの設定)
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
・・・略・・・
# nginx再起動
$ sudo service nginx restart
# nginx_status確認
$ curl http://localhost/nginx_status
Active connections: 1
server accepts handled requests
23296 23296 23432
Reading: 0 Writing: 1 Waiting: 0
DatadogAgent nginxインテグレーション有効化
DatadogAgentは既に導入済みの前提です。exampleファイルをコピーしてnginx.yamlを作成します。(タグ付け等はお好みで)
# exampleファイルコピー
$ sudo cp -p /etc/dd-agent/conf.d/nginx.yaml.example /etc/dd-agent/conf.d/nginx.yaml
$ sudo vi /etc/dd-agent/conf.d/apache.yaml
init_config:
instances:
- nginx_status_url: http://localhost/nginx_status/
tags:
- env:production
# DatadogAgent再起動
$ sudo service datadog-agent restart
DatadogAgent再起動後にinfoで確認し、以下の様な出力があれば有効化されています。
# nginx Integration有効化確認
$ sudo service datadog-agent info
・・・略・・・
nginx
-----
- instance #0 [OK]
- Collected 7 metrics, 0 events & 2 service checks
・・・略・・・
Datadogメトリクス確認
Datadog上でメトリクスが取得できていることが確認できます。
- Add Graph

Integration Dashboard

NGINX-Metrics

NGINX-Openview

Datadog Apache Integration を試す
※画像と内容は一切関係ありません

DatadogのApacheインテグレーション設定を試してみます。
と言っても下記ページ通りで簡単に取得できます。留意点としてはExtendedStatusの有効化をすること位かと思います。
取得できるメトリクスは以下になります。
apache.net.bytes apache.net.bytes_per_s apache.net.hits apache.net.request_per_s apache.performance.busy_workers apache.performance.cpu_load apache.performance.idle_workers apache.performance.uptime
Apache mod_status 有効化
CentOS 6.7 でrpmからインストールした場合、モジュールは既に導入済みとなっています。
$ apachectl -V Server version: Apache/2.2.15 (Unix) $ apachectl -M ・・・略・・・ status_module (shared) ・・・略・・・
設定ファイルを変更します。ローカルホストからのみアクセスを受け付けるよう設定しています。
$ sudo vi /etc/httpd/conf/httpd.conf
・・・略・・・
# mod_statusモジュール読み込み
LoadModule status_module modules/mod_status.so
・・・略・・・
# ExtendedStatus有効化(コメントアウトを外す)
ExtendedStatus On
・・・略・・・
# server-status有効化(コメントアウトを外し、許可IPの設定)
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>
・・・略・・・
# Apache再起動
$ sudo service httpd restart
# server-status確認
$ curl http://localhost/server-status
<html><head>
<title>Apache Status</title>
</head><body>
<h1>Apache Server Status for localhost</h1>
<dl><dt>Server Version: Apache/2.2.15 (Unix) DAV/2 PHP/5.6.13</dt>
<dt>Server Built: Aug 24 2015 17:52:49
・・・略・・・
DatadogAgent Apacheインテグレーション有効化
DatadogAgentは既に導入済みの前提です。exampleファイルそのままの内容を使用します。(タグ付け等はお好みで)
# exampleファイルコピー
$ sudo cp -p /etc/dd-agent/conf.d/apache.yaml.example /etc/dd-agent/conf.d/apache.yaml
$ sudo cat /etc/dd-agent/conf.d/apache.yaml
init_config:
instances:
- apache_status_url: http://localhost/server-status?auto
# apache_user: example_user
# apache_password: example_password
# tags:
# - optional_tag
# DatadogAgent再起動
$ sudo service datadog-agent restart
DatadogAgent再起動後にinfoで確認し、以下の様な出力があれば有効化されています。
# ApacheIntegration有効化確認
$ sudo service datadog-agent info
・・・略・・・
apache
------
- instance #0 [OK]
- Collected 8 metrics, 0 events & 2 service checks
・・・略・・・
Datadogメトリクス確認
Datadog上でメトリクスが取得できていることが確認できます。
- Add Graph

Integration Dashboard Apache-Openview

