概要
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パラメータストアの値を取得する