Rubyを用いたAWS LambdaからSlackに通知する仕組みを作った話
本記事では、Rubyを用いたLambda関数におけるSlack通知の実装例と実装の際に工夫した点を紹介します。
従来は、Lambda関数の処理中にエラーが発生した場合に、エラークラスやトラブルシュート用の情報をAmazon SNSを用いてアラート通知用のメールアドレス宛に通知していました。今回Slackに通知先を移行するにあたり、下記のサンプルコードのように実装しました。
通知例
Lambda関数のサンプルコード
# ランタイム: Ruby3.2
# 必要な環境変数: SLACK_CHANNEL, SLACK_WEBHOOK_URL
require 'net/http'
require 'uri'
def lambda_handler(event: nil, context: nil)
@context = context
dummy_method
rescue StandardError => e
message = "追加情報だよ"
notify_error_to_slack(e.class, e.message, message)
end
def dummy_method
raise StandardError.new("エラーメッセージだよ")
end
def notify_error_to_slack(err_class, err_message, message)
subject = '[ERROR] Error occurred'
notify_to_slack(
generate_message(:alert, subject, err_class, err_message, message)
)
end
# 通知内容に応じて絵文字を変更
def emoji_for(severity)
case severity
when :info
":mega:" # 📣
when :alert
":rotating_light:" # 🚨
end
end
# メッセージの生成
def generate_message(severity, subject, err_class, err_message, message)
{
"channel": "#{ENV['SLACK_CHANNEL']}",
"username": "Lambda Bot",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "#{emoji_for(severity)} #{subject}",
"emoji": true
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*lambda_function_name:*\n#{@context.function_name}"
},
{
"type": "mrkdwn",
"text": "*lambda_request_id*\n#{@context.aws_request_id}"
},
{
"type": "mrkdwn",
"text": "*lambda_log_stream_name:*\n#{@context.log_stream_name}"
},
{
"type": "mrkdwn",
"text": "*ErrorClass:*\n#{err_class}"
},
{
"type": "mrkdwn",
"text": "*ErrorMessage:*\n#{err_message}"
},
{
"type": "mrkdwn",
"text": "*Info:*\n#{message}"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<#{cloud_watch_log_stream_url}|Please check CloudWatch log from here...>"
}
}
]
}
end
# 関数のログストリームのURLの生成
def cloud_watch_log_stream_url
encoded_function_name = URI.encode_www_form_component(URI.encode_www_form_component("/aws/lambda/#{@context.function_name}"))
encoded_log_stream_name = URI.encode_www_form_component(URI.encode_www_form_component(@context.log_stream_name))
url_prefix = "https://ap-northeast-1.console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#logsV2:log-groups/log-group/"
url_interfix = "/log-events/"
url_prefix + encoded_function_name + url_interfix + encoded_log_stream_name
end
# Slack APIのリクエスト
def notify_to_slack(message)
Net::HTTP.post(URI(ENV['SLACK_WEBHOOK_URL']), message.to_json)
end
Block Kitを使用したSlackメッセージ
Block Kit builderを用いたメッセージ作成の効率化
Slack APIでは、Block Kitと呼ばれるUIフレームワークを用いてリッチなUIのメッセージを送ることができます。メッセージのUIを検討するにあたり、Block Kit builderを用いたことで下図のように簡単のUIを作ることができます。今回は、このBlock Kitを使用してメッセージを作成し、メッセージ作成の効率化を図りました。
メッセージ作成にはblocksとattachmentsのどちらを使うべきか
メッセージの書き方を調べてみるとattchments
とblocks
の2種類が存在しますが、公式ドキュメントによるとblocks
を使うことが推奨されています。
{
"channel": "CHANNEL_NAME",
"attachments": []
}
👇 こちらが推奨されている
{
"channel": "CHANNEL_NAME"
"blocks": []
}
CloudWatch LogsのログストリームのURL
従来の運用では、Lambda関数のログを調べる際に、ログストリーム名を確認して該当のログストリーム名を検索するという流れがとても手間だと感じていました。そこで、Slackのチャットに該当のログストリームのリンクを付けるようにしました。CloudWatch LogsのログストリームのURLは少し特徴的で、下記のような文字列の組み合わせになっています。下記の組み合わせで生成したリンクをSlackの通知内容に含めることで、リンクを押下するとすぐに該当のログストリームを確認することができ、トラブルシュートの時間を削減することができました。
"https://#{region}.console.aws.amazon.com/cloudwatch/home?region=#{region}#logsV2:log-groups/log-group/"
+
関数名を2回エンコードした文字列
+
"/log-events/"
+
ログストリーム名を2回エンコードした文字列
まとめ
以上がRubyを用いたLambda関数からのSlack通知の実装例と工夫した点になります。
似たようなユースケースの通知の実装を検討されている方の参考になると嬉しいです。😊
Discussion