LoginSignup
9
9

More than 3 years have passed since last update.

CloudWatch Logs Insights の分析結果をLambdaで監視する

Last updated at Posted at 2019-08-11

はじめに

CloudWatch Insightsの分析結果を監視するLambdaを作成しました。

CloudWatch Logs Insightsとは

CloudWatch Logs Insightsとは、2018年のre:Inventで発表されたサービスです。
詳細に関しては、以下のサイトをご覧いただければと思いますが、一言で説明すればCloudWatch Logs内のログデータを簡単に集計・分析できるサービスです。
ロググループに対する専用のクエリ言語がサポートされており、そのクエリを投げることで簡単にログの集計・分析が行え、さらにグラフを作成して結果を可視化することもできます。これらの分析結果をCloudWatchダッシュボードに追加することもできます。
新機能 – Amazon CloudWatch Logs Insights – 高速でインタラクティブなログ分析
CloudWatch Logs Insights を使用したログデータの分析

やったこと

今回、CloudWatch Insightsで得られた分析結果を監視するLambdaを作成しました。
具体的には、APIGatwayのアクセスログのステータスコードに400以上のものがある場合にSlackに通知する
ということを行いました。
注:「LambdaでInsightsの分析結果を使う」ことをしたかったため、そのままCloudWatchのメトリクスを使えばもっと簡単にできます。

以下、構成図です。
APIGatewayのアクセスログをCloudWatch Logsに吐き出し、
LambdaでCloudWatch Logs Insightsのクエリを実行し分析結果を取得、
その分析結果の内容にしたがってSlackに通知するということを行います。
なお、2019年8月現在、Insightsの分析結果をCloudWatch Alermのメトリクスに指定することはできなかったため、LambdaはCloudwatch Eventsによって5分ごとに動かすようにしました。
スクリーンショット 2019-08-10 14.49.46.png

事前準備

Lambdaを作成する前に、いくつかの事前準備を行います。

SlackWebhookのURLを取得する。

Slack通知を行う場合、SlackWebhookのURLを取得しておいてください。

IAMロールの作成

今回使用するIAMロールは以下の2つあるので、それらを作成します。
1.APIGateway用IAMロール
後述しますが、APIGatewayはデフォルト状態ではアクセスログをCloudWatch Logsに書き出す仕様ではないためその設定を行う必要があります。その際、APIGatewayがCloudWatch Logsにログを書き込む権限が必要となるためそのIAMロールを作成します。
デフォルトで存在するポリシー「AmazonAPIGatewayPushToCloudWatchLogs」をアタッチしたロールを作成し、ARNをコピーしておいてください。

2.Lambda用IAMロール
Lambdaに割り当てるロールを作成します。今回、CloudWatchLogsへのアクセス権限が必要なため、以下のIAMポリシーをアタッチしたロールを作成しました。

IAMポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

ロググループの作成

APIGatewayのアクセスログを書き出すためのCloudWatch Logsのロググループを作成しておきます。

APIGatewayの設定

APIGatewayの対象APIのアクセスログの設定を行います。デフォルト状態では、アクセスログは取得しない設定になっているためアクセスログをCloudWatch Logsに吐き出す設定を行います。
サービス > APIGateway > 設定
でARNにAPIGatway用に作成したIAMロールのARNを設定します。

アクセスログを取得するAPIを選択 > ステージを選択 > ログのトレース
CloudWatch ログを有効化し、アクセスログを有効化、ログの形式を設定 (今回は、JSONにしました)。

これでAPIGatwayの設定は完了です。

Lambdaの設定

環境変数

今回、以下の環境変数を設定しました。
CHANNEL_LIST   :通知するSlackのチャンネル名をカンマ区切りで設定。
LOGGROUP_NAMES : 監視するCloudWatchLogsのロググループをカンマ区切りで設定。

Insightsの結果をLambdaで監視する
import os
import datetime
import time
import ast
import slackweb
import boto3

at_color = "danger"
client = boto3.client('logs')
channel_list = os.environ.get('CHANNEL_LIST').split(',')
logGroupNames = os.environ.get('LOGGROUP_NAMES').split(',')
slack_api = "Slack WebhookのURLを記載"

def lambda_handler(event, context):
    five_minutes_ago = datetime.datetime.now() - datetime.timedelta(minutes = 5)
    startTime = five_minutes_ago.replace(second = 0, microsecond = 0)
    endTime = startTime + datetime.timedelta(minutes = 5) - datetime.timedelta(milliseconds = 1)
    queryString = 'fields @timestamp, @message | sort @timestamp desc | filter (status >= 400)'

    for logGroupName in logGroupNames:
        error_logs = results(logGroupName, startTime, endTime, queryString)
        if len(error_logs) > 0:
            for error_log in error_logs:
                dict_message = ast.literal_eval(error_log[1]['value'])
                text = str(logGroupName) + '\n' + str(dict_message)
            for channel in channel_list:
                try:
                    post_slack(channel,text)
                except Exception as e:
                    post_slack(channel,text)

def results(logGroupName, startTime, endTime, queryString):
    start_query_res = client.start_query(
        logGroupName=logGroupName,
        startTime=int(startTime.timestamp()),
        endTime=int(endTime.timestamp()),
        queryString=queryString
    )
    queryId = start_query_res['queryId']

    get_results_res = client.get_query_results(
        queryId=queryId
    )

    while get_results_res['status'] == 'Running':
        time.sleep(5)
        get_results_res = client.get_query_results(
           queryId=queryId
        )
    return get_results_res['results']

def post_slack(channel,text):
    slack = slackweb.Slack(url=slack_api)
    slack.notify(
        username="API-accesslog",
        channel=channel,
        attachments = [{
            "color" : at_color,
            "text" : text
        }]
    )


参考サイト

Boto3 Docs 1.9.205 dociumentation

9
9
1

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
9
9