tl;dr
alerty という cron の失敗の結果を各種通知先にアラートを飛ばすツールを sonots さんが作られた。
このツールのイイなあと思うところの一つはプラグインによって通知先を増やせる点。また、README にも書かれているが、プラグインの実装がとても簡単に出来るようになっている点も自分のような Ruby HelloWorld 検定准一級(初心者)には嬉しい配慮だと思う。
ということで、 alerty の公開に便乗して 勉強を兼ねてエイヤで三種のプラグインを作ったので、作成の過程で得た知見等を雑にメモる。 尚、alerty の詳細については上記の Blog 記事や以下の Github リポジトリをご一読あれ。
プラグイン三種盛り
三種のプラグインについてリンクと図で。
alerty-plugin-datadog_event
以下、ざっくり処理の流れ。Datadog の Monitor からさらに担当者への通知も定義することが出来る。(そこまでやるかは置いといて)
以下、スクショ。
alerty-plugin-amazon_cloudwatch_logs
以下、ざっくり処理の流れ。CloudWatch Logs から Metric Filter → Alert という流れで更に担当者への通知も定義することが出来る。(同じくそこまでやるかは置いといて)
以下、スクショ。
alerty-plugin-post_im_kayac
以下、ざっくりと処理の流れ。Cron の実行結果は S3 に放り込んでおいて Presigned URL を発行、発行してみて気付いたが URL が長すぎたので bitly で短縮して im.kayac の handler に含めて通知、URL を踏んで詳細のログは S3 で確認するという流れ。尚、せっかくの Presigned URL なので bitly 上で短縮した URL は非公開設定しておく。
おや、アラートだ。
どれどれ。
赤丸で囲まれたリンクをクリックすると既定のブラウザで開く。
詳細のログが記録された S3 バケットにアクセスしてログを確認することが出来る。
いくつかの知見
Datadog Events API の Source Type について
知見というわけではないが、alerty-plugin-datadog_event を作るにあたっての調査報告。
Datadog Events API において Event を Put する際に source_type_name
というオプションがあるので、これを指定して Event を put することでダッシュボードの Events において sources: foo,bar
等のようにイベントを絞り込むことが出来る。
ところが…以下の実験にて source_type_name
以下では source
に該当は任意の値を指定しても My Apps
として登録させてしまうのではないか疑惑。
# # Event を put する # % curl -X POST -H "Content-type: application/json" -d '{ "title": "foo", "text": "bar", "priority": "normal", "tags": ["environment:test"], "alert_type": "info", "source": "baz" }' 'https://app.datadoghq.com/api/v1/events?api_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' {"status": "ok", "event": {"priority": "normal", "date_happened": 1441719048, "handle": null, "title": "foo", "url": "https://app.datadoghq.com/event/event?id=2977220706502185346", "text": "bar", "tags": ["environment:test"], "related_event_id": null, "id": 2977220706502185346}} # # put した Event を確認 # % ruby test.rb ["200", {"events"=>[{"date_happened"=>1441719048, "alert_type"=>"info", "is_aggregate"=>false, "title"=>"foo", "url"=>"/event/event?event_id=2977220706502185346", "text"=>"bar", "tags"=>["environment:test"], "comments"=>[], "device_name"=>nil, "priority"=>"normal", "source"=>"My Apps", "host"=>nil, "resource"=>"/api/v1/events/2977220706502185346", "id"=>2977220706502185346}]}]
Event を put する際には "source": "baz"
で put しているにも関わらず Event を get してみると "source"=>"My Apps"
でレスポンスが返ってきている。これは、そもそも source
には任意を自由に定義出来るのではなく、決められた値のみ指定することが可能でそれ以外を指定した場合には My Apps
と返ってくるのか、それとも source
への任意の値を指定することはまだ未対応なのか個人的な七不思議の一つとして引き続き調査を進めたい。
CloudWatch Logs の Timestamp
alerty-plugin-amazon_cloudwatch_logs を作る際に得た知見という程ではないがドキュメントをちゃんと読みませう的な内容。AWS SDK for Ruby V2 を利用して、以下のように put_log_events
メソッドでメッセージを送信する
resp = @client.put_log_events({ log_group_name: @log_group_name, log_stream_name: @log_stream_name, log_events: [ { timestamp: timestamp, message: event_message.to_json, }, ] })
この際の timestamp
については Time.now.to_i
で得られる Epoch Time ではなくて Epoch Time のミリ秒までが必要となる為、こちらの記事を参考にさせて頂いて以下のようにミリ秒までを取得した。
timestamp = Time.now.instance_eval { self.to_i * 1000 + (usec/1000) }
以下、API ドキュメント。
A point in time expressed as the number of milliseconds since Jan 1, 1970 00:00:00 UTC.
上記の記述の通りミリ秒での指定が必要となる。
CloudWatch Logs にログを放り込む場合には token 必須
こちらもログを放り込む際のネタ。
ロググループ、ログストリーム作りたての一発目は以下のように put_log_event
でログを放り込むことが出来る。
resp = @client.put_log_events({ log_group_name: @log_group_name, log_stream_name: @log_stream_name, log_events: [ { timestamp: timestamp, message: event_message.to_json, }, ] })
一発目にログを放り込んだ際のレスポンスに以下のような nextSequenceToken
が含まれる(以下は AWS CLI でのレスポンス例で AWS SDK for Ruby の場合にはレスポンスオブジェクトから next_sequence_token
というメソッドで取得可能)ので、次にログを放り込む際にはこの nextSequenceToken
の値を sequence_token:
キーの値として定義した上で put_log_events
する。
{ "nextSequenceToken": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
以下は二回目以降の put_log_events
のパラメータ。
resp = @client.put_log_events({ log_group_name: @log_group_name, log_stream_name: @log_stream_name, log_events: [ { timestamp: timestamp, message: event_message.to_json, }, ], sequence_token: next_token })
今回のプラグインではログを放り込む際に取得した next_sequence_token
をローカルのファイルに書き込んで、次のタイミングで放り込む際に書き込んだトークンを取得して利用するという方法を取ってみた。
AWS SDK for Ruby V2 で S3 Presigned URL を使って…
alerty-plugin-post_im_kayac を作る際に cron の実行結果を im.kayac の message に載せると見辛かったので message の中身を S3 にアップロードしておいて URL だけメッセージに載っけて飛ばそうと思ったけど、出来るだけセキュアにやりたかったので署名付き URL を発行することにした。AWS SDK for Ruby V2 では以下の手順で署名付き URL を発行することが出来る。
def put_log_to_s3(message) obj = @s3.bucket(@s3_bucket).object('KeyName') url = URI.parse(obj.presigned_url(:put)) Net::HTTP.start(url.host) do |http| http.send_request("PUT", url.request_uri, message, { "content-type" => "", }) end obj.presigned_url(:get, expires_in: 600) end
-
Aws::S3::Resource
クラスのインスタンスを作成 -
Aws::S3::Resource
クラスインスタンスの bucket メソッドと object メソッドを呼び出して、バケット名とオブジェクトキーを指定する -
URI
クラスのインスタンスを作成し、これを使用してAws::S3::Resource
クラスインスタンスの.presigned_url
メソッドを利用して署名付き URL を生成する(:put
と:get
で取得出来る URL が異なるようだ→未検証、また:expires_in
でオブジェクトの期限を設定することが出来る)
こちらも以下のドキュメントに記載されている。
余談だが、AWS のドキュメントが読みやすくなっているのはとても嬉しい。
Ruby で im.kayac.com にメッセージを送る
以下の Gem を利用すると簡単だった。
今回のプラグインはパスワード認証のみ対応しているが、上記の Gem は秘密鍵認証にも対応している。
bitly で短縮 URL を生成する
署名付き URL が長すぎたので短縮した方が見栄えがイイと思ったので bitly で 署名付き URL を短縮することにした。こちらは以下の Gem を利用した。
以下のように書くだけで簡単に短縮 URL を取得出来た。
Bitly.use_api_version_3 bitly = Bitly.new(config.bitly_user_name, config.bitly_api_key) bitly.shorten("http://xxxx.xxx.com").short_url
事前に bitly の User Name と API キーを取得しておく。
また、bitly ではデフォルトで短縮した URL は公開されてしまうので公開されないよう上記のように非公開設定にしておくことをお忘れなく…。
todo
todo こそモチベーション。
alerty-plugin-datadog_event
-
source_type_name
を使えるようにする
alerty-plugin-amazon_cloudwatch_logs
-
log_group_name
とlog_stream_name
が存在しない場合には自動で追加するようにする - Windows 環境で token を書き込むファイルへの書き込みが上手く動作しないことがあったので調べる
alerty-plugin-post_im_kayac
- 秘密鍵認証の対応
- cron の実行ログを保存する S3 キーの名前を日付、ホスト名を合わせたキー名にする
- Presigned URL の expire を設定ファイルで指定出来るようにする
全般的に
- 各種エラー処理
以上。
もし、よろしければプラグインを使って頂いてフィードバック等頂けるとありがたや、ありがたや。