LoginSignup
1
0

More than 1 year has passed since last update.

AWS CloudWatchのログを監視し、Slackに通知する(CloudWatch+Lambda+Ruby+Slack)

Posted at

概要

CloudWatchのログを監視し、特定のログが出力された場合に、
その特定のログの内容をSlackに通知する方法を紹介します。

利用するサービス

  • AWS
    • CludWatch
    • Lambda
    • Amazon Systems Manager
  • Slack(Incoming Webhook)

手順

以下の順序で作業を行っていきます。

  1. SlackのWorkspaceにIncoming Webhookを登録
  2. AWS Systems ManagerにSlackにPOSTするためのURLを登録
  3. Lambdaでログ内容をSlackにPOSTするプログラムを作成
  4. CloudWatchのロググループのサブスクリプションフィルターにLambdaを設定する
  5. 連携確認テスト

1. SlackのWorkspaceにIncoming Webhookを登録

まず、ログを通知したいチャンネルをSlackで作成。
次に、slack app directoryIncoming 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を設定しパラメータを作成する。
image.png

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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0