概要
CloudWatchのログを監視し、特定のログが出力された場合に、
その特定のログの内容をSlackに通知する方法を紹介します。
利用するサービス
- AWS
- CludWatch
- Lambda
- Amazon Systems Manager
- Slack(Incoming Webhook)
手順
以下の順序で作業を行っていきます。
- SlackのWorkspaceにIncoming Webhookを登録
- AWS Systems ManagerにSlackにPOSTするためのURLを登録
- Lambdaでログ内容をSlackにPOSTするプログラムを作成
- CloudWatchのロググループのサブスクリプションフィルターにLambdaを設定する
- 連携確認テスト
1. SlackのWorkspaceにIncoming Webhookを登録
まず、ログを通知したいチャンネルをSlackで作成。
次に、slack app directoryでIncoming Webhookを検索し、Slackに追加をクリック。
チャンネルへの投稿で作成したSlackチャンネルを選択し、Incoming Webhook インテグレーションの追加をクリック。
Webhook URLの内容をコピーして控えておく。
2. AWS Systems ManagerにSlackにPOSTするためのURLを登録
Lambdaのコードに直接URLを記入して、Slackに通知することはできるのですが、
セキュリティの面で心配なので、Systems Managerを利用することにします。
まず、AWS Systems Managerのコンソールを開く。
パラメーターストア>>パラメータの作成をクリック。
以下のようにIncoming WebhookのURLを設定しパラメータを作成する。

3. Lambdaでログ内容をSlackにPOSTするプログラムを作成
まず、Lambdaのコンソールを開く。
関数>>関数の作成をクリック。
関数名にlog_to_slackと指定し、ランタイムにRubyを選択して関数を作成する。
作成した関数に対応するロールを編集してAmazonSSMFullAccessを追加。
コードソースに以下を指定。
require 'json'
require 'base64'
require 'zlib'
require 'net/http'
require 'uri'
require 'aws-sdk-ssm'
def lambda_handler(event:, context:)
# Base64変換+zip解凍+JSON変換
json_log_data = JSON.parse(Zlib::GzipReader.new(StringIO.new(Base64.decode64(event["awslogs"]["data"]))).read)
log_events = json_log_data["logEvents"]
output = ''
log_events.each do |log_event|
output += log_event["message"]
output += "\n"
end
# slackに通知
slack_post(output)
end
def slack_post(message)
uri = URI.parse(get_slack_url)
ssm_client = Aws::SSM::Client.new
request = {
name: 'test-slack-url', # パラメータ名
with_decryption: true # 暗号化されている場合は復号し、暗号化されていない場合は何もしない
}
response = ssm_client.get_parameter(request)
slack_url = response.parameter.value
params = { text: '```' + message + '```' }
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.start do
request = Net::HTTP::Post.new(uri.path)
request.set_form_data(payload: params.to_json)
http.request(request)
end
end
def get_slack_url
# このソースにURLをベタ打ちするのはセキュリティの問題があるため、
# aws systems managerにwebhookのスラックURLを登録した。
# aws systems managerに登録したurlを取得
ssm_client = Aws::SSM::Client.new
request = {
name: 'test-slack-url',
with_decryption: true
}
response = ssm_client.get_parameter(request)
response.parameter.value
end
Deployボタンを押してデプロイしておく。
4. CloudWatchのロググループのサブスクリプションフィルターにLambdaを設定する
CloudWatchにログを出力するためテストLambdaを作成
まず、Lambdaのコンソールを開く。
関数>>関数の作成をクリック。
関数名にlambda_testと指定し、ランタイムにRubyを選択して関数を作成する。
コードソースに以下を指定。
require 'json'
def lambda_handler(event:, context:)
# TODO implement
{ statusCode: 200, body: JSON.generate('Hello from Lambda!') }
pp "INFO:AAAAA"
pp "DEBUG:BBBB"
pp "ERROR:CCCC"
end
このlambda_testをテスト実行することでCloudWatchの
lambda_testに対応したロググループに意図的に
「INFO:AAAA」
「DEBUG:BBBB」
「ERROR:CCCC」
といったログを出力できるようになる。
Deployボタンを押してデプロイし、
TestボタンをおしてCloudWatchのコンソールからロググループをクリックし、
lambda_testのロググループが作成されていることを確認する。
lambda_testのロググループのサブスクリプションフィルターを設定する
lambda_testのロググループを開き、サブスクリプションフィルタータブをクリック。
作成>>Lambda サブスクリプションフィルターを作成を選択。
Lambda関数でlog_to_slackを選択。
ログの形式でその他を選択。
サブスクリプションフィルターのパターンでERRORと入力。
※lambda_testのERROR:CCCCを検知したタイミングでlog_to_slackが動作するように設定。
サブスクリプションフィルター名でerror_filterと入力。
ストリーミングを開始をクリック。
5. 連携確認テスト
lambda_testのコードを開き、Testをクリックし、
Slackの今回作成したチャンネルにERROR:CCCCが通知されていることを確認する。
お疲れさまでした。最後までお付き合いいただき、ありがとうございます。
参考記事
AWS Lambdaで作るSlack bot (Incoming Webhook)
Ruby でWebhook にPOST する方法
【Ruby】AWS SSMパラメータストアの値を取得する