Amazon CloudWatchメトリクスのグラフをSlackで参照してみた

この記事ではデータをAmazon CloudWatchにカスタムメトリクスとして格納し、メトリクスのグラフをAWS ChatbotからSlackに送る方法を説明します。
2021.07.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、ジョン・ヒョンジェです。

前日、Slackに新型コロナウイルスの発生状況を告げるアプリを作ってみました。

今回はその続きとして、新型コロナウイルス発生状況のデータをAmazon CloudWatchにカスタムメトリクスとして格納し、AWS Chatbotを利用してメトリクスのグラフをSlackで参照してみます。

作業の流れは以下のようになります。

  • CloudWatchカスタムメトリクスにデータを格納するコードを前回作成したLambda関数に追加
  • AWS Chatbot作成
  • SlackでCloudWatchメトリクスのグラフを参照

早速作ってみよう

Lambdaにコード追加

Lambda関数の全体のコードです。

import boto3
import json
import requests
import xmltodict
import urllib.parse
import datetime

def alert(event, context):

    # 時間設定
    today_time = datetime.date.today()
    yesterday_time = today_time - datetime.timedelta(days = 1)

    ## parse_data関数を呼び出す
    result_today_datas = parse_data(today_time.strftime("%Y%m%d"))
    result_yesterday_datas = parse_data(yesterday_time.strftime("%Y%m%d"))

    # S3にファイルをアップロード。(省略してもOK。ただのデータバックアップのため)
    s3 = boto3.resource('s3')
    bucket_name = "corona-log"
    file_name = "%s.json" % (today_time.strftime("%Y%m%d"))    
    obj_name = s3.Object(bucket_name, file_name)    
    obj_name.put(Body=json.dumps(result_today_datas))

    message_text = ""   #Incoming Webhooksに送信するテキスト

    for i in range(0, len(result_today_datas)): #データの加工
        region = result_today_datas[i]["region"]
        today_confirmed = result_today_datas[i]["confirmed"]
        inc_confirmed = int(result_today_datas[i]["confirmed"]) - int(result_yesterday_datas[i]["confirmed"])

        add_message = "*%s : %s名* (前日と比べ%s" % (region, today_confirmed, abs(inc_confirmed)) + ("名増加)" if inc_confirmed >=0 else "名減少)")
        if region == "Total":
            line = "========================================="
            message_text = (line + "\n").join([message_text, add_message])
        else:
            message_text = "\n".join([message_text, add_message])

    # Incoming Webhooksの設定  
    url = "<Incoming WebhooksのURL>"
    payload = {
        "attachments": [{
            "pretext" : "私が韓国の新型コロナウイルス感染者発生状況を告げに来た!! (%s)" % str(today_time),
            "color" : "#0099A6",
            "text" : message_text
        }]
    }
    headers = {
        "Content-Type" : "application/json; charset=UTF-8"
    }

    # Incoming Webhooksにデータ送信
    response = requests.post(url, data=json.dumps(payload), headers = headers)

    return response


def parse_Data(time):

    # Open APIのリクエストURL作成
    api_url = "http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19SidoInfStateJson"
    queryParams = {
        "ServiceKey" :  "<Open APIの認証キー>",
        "startCreateDt" : time,
        "endCreateDt" : time
        }
    query_string = urllib.parse.urlencode(queryParams)
    url = api_url + "?" + query_string

    # 分析しやすくするため、JSON形式に変換
    raw_data_result = requests.get(url).text
    dict_data = xmltodict.parse(raw_data_result)
    json_datas = json.loads(json.dumps(dict_data))

    result_datas = []

    for json_data in json_datas["response"]["body"]["items"]["item"]:

        data = {}
        data["region"] = json_data["gubunEn"]   #地域
        data["confirmed"] = json_data["incDec"] #感染者数

        result_datas.append(data)

    store_as_Metric(result_datas)

    return result_datas

def store_as_Metric(result_datas):

    cloudwatch = boto3.client('cloudwatch')

    # CloudWatchにカスタムメトリクスとしてデータを格納
    for data in result_datas:
        response = cloudwatch.put_metric_data(
            Namespace='corona_alert',
            MetricData = [
                {
                    'MetricName' : "confirmed_cases",
                    'Dimensions' : [
                        {
                            'Name' : 'region',
                            'Value' : data["region"]
                        },
                    ],
                    'Value' : int(data["confirmed"]),
                    'Unit' : 'None'
                },
            ]
        )

前回作成したコードで追加した部分は以下です。

def store_as_Metric(result_datas):

    cloudwatch = boto3.client('cloudwatch')

    # CloudWatchにカスタムメトリクスとしてデータを格納
    for data in result_datas:
        response = cloudwatch.put_metric_data(
            Namespace='corona_alert',
            MetricData = [
                {
                    'MetricName' : "confirmed_cases",
                    'Dimensions' : [
                        {
                            'Name' : 'region',
                            'Value' : data["region"]
                        },
                    ],
                    'Value' : int(data["confirmed"]),
                    'Unit' : 'None'
                },
            ]
        )

CloudWatchにデータを格納するためにはput_metric_dataメソッドを使います。パラメーターとしてNamespace, MetricDataを定義します。

  • Namespace
    • ネームスペースを定義
    • 「AWS/」に始まるネームスペースはNG(AWSサービスのネームスペースと重なる恐れがある)
  • MetricData
    • メトリクスのデータを定義
    • メトリクス名、ディメンション、Value、Unitなどのプロパティを指定

この場合ではディメンションに各地域を指定し、Valueに各地域で発生した感染者数を指定しました。

put_metric_dataメソッドの詳しいところは以下のリンクを参考してください

では、CloudWatchコンソールで確認してみましょう!

このようにカスタムメトリクスにちゃんとデータが格納されているのを確認することができます。矢印が差している部分がデータポイントになります。(前回、毎日12時にLambdaを実行するように設定しました)

ま、今は7月14日からのデータしかありませんが、1週間後には綺麗なグラフになるでしょう。

AWS Chatbot作成

AWS ChatbotはSlackチャンネルでAWSのリソースを簡単にモニタリング、および操作できるようにしてくれるサービスです。

まず、AWS ChatbotコンソールでSlackワークスペースを設定した後、そのワークスペースでChatbotを利用したいチャンネルを設定します。

ChatbotのIAMロールの設定では「通知のアクセス許可」だけ付与することで十分です。

設定が終わったら、設定したSlackのチャンネルで/invite @awsを入力し、Chatbotを招待します。

CloudWatchメトリクスグラフの参照

では、最後に先のカスタムメトリクスのグラフをSlackで参照してみましょう!

実行するコマンドは以下です。

@aws cloudwatch get-metric-widget-image --region <region> --metric-widget <string>

get-metric-widget-imageはCloudWatchメトリクスのスナップショットグラフをビットマップ画像として取得することができるコマンドです。

metric-widgetオプションには検索するグラフを定義するJSONの情報を入力します。このJSON情報は以下のように、CloudWatchコンソールですぐ取得することができます。

では、コマンドを実行してみます。全てのディメンションを参照するのはちょっと多いので、私が住んでいるDaegu、首都のSeoul, そして、韓国全体の感染者数のグラフを参照します。

正常にCloudWatchからカスタムメトリクスのスナップショットを取得することができました!

最後に

前回のブログの続きとして、新型コロナウイルスの発生状況のデータをCloudWatchのカスタムメトリクスとして格納し、Slackでそのメトリクスのグラフを参照する内容を追加してみました。

「SlackでCloudWatchのメトリクスグラフが参照できる」のは場合によってはとても便利な機能です。例えば、マネジメントコンソールが使えない場合でもEC2のCPU使用率のグラフをSlackで気軽に参照できたらとても嬉しいでしょう。

では、以上です。このブログがどなたかの参考になったら幸いです!