CloudWatch Alarm からの通知
SNS
次の通り、SNS トピックを用意しておきます。
CloudWatch アラーム
CloudWatch アラームで先程作成した SNS を通知の送信先としておきます。
通知内容
ECS のタスクを意図的に 3 回連続で 1 にして、通知してみます。
CloudWatch アラーム → SNS → Email に通知した場合
CloudWatch アラーム → SNS → Chatbot → Slack に通知した場合
CloudWatch Alarm → Lambda → SNS に通知した場合
ちなみにここでは補足ですが、CloudWatch Alarm のアクションとして直接 Lambda を指定することができるようになりました。
そのため、CloudWatch Alarm → Lambda → SNS のようにし、Lambda で簡易的にカスタマイズして通知しています。
CloudWatch Alarm からは次のようなイベントログです。
{
"source": "aws.cloudwatch",
"alarmArn": "arn:aws:cloudwatch:ap-northeast-1:123456789012:alarm:Error_ServiceA_Alarm",
"accountId": "123456789012",
"time": "2024-02-19T15:19:28.025+0000",
"region": "ap-northeast-1",
"alarmData": {
"alarmName": "Error_ServiceA_Alarm",
"state": {
"value": "ALARM",
"reason": "Threshold Crossed: 1 out of the last 1 datapoints [1.0 (19/02/24 15:17:00)] was less than or equal to the threshold (1.0) (minimum 1 datapoint for OK -> ALARM transition).",
"reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2024-02-19T15:19:28.022+0000\",\"startDate\":\"2024-02-19T15:17:00.000+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[1.0],\"threshold\":1.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2024-02-19T15:17:00.000+0000\",\"sampleCount\":1.0,\"value\":1.0}]}",
"timestamp": "2024-02-19T15:19:28.025+0000"
},
"previousState": {
"value": "OK",
"reason": "Threshold Crossed: 1 out of the last 1 datapoints [2.0 (19/02/24 15:00:00)] was not less than or equal to the threshold (1.0) (minimum 1 datapoint for ALARM -> OK transition).",
"reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2024-02-19T15:02:32.938+0000\",\"startDate\":\"2024-02-19T15:00:00.000+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[2.0],\"threshold\":1.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2024-02-19T15:00:00.000+0000\",\"sampleCount\":1.0,\"value\":2.0}]}",
"timestamp": "2024-02-19T15:02:32.939+0000"
},
"configuration": {
"description": "ECSのタスクが3回連続で1以下になりました。",
"metrics": [
{
"id": "92c6e0f3-9271-49e7-c4d9-93f5170897f5",
"metricStat": {
"metric": {
"namespace": "ECS/ContainerInsights",
"name": "RunningTaskCount",
"dimensions": {
"ServiceName": "ecs-svc",
"ClusterName": "ecs-cluster"
}
},
"period": 60,
"stat": "Sum"
},
"returnData": true
}
]
}
}
}
CloudWatch Alarm からのイベントログを元に、Lambda は次の通り作成しています。
import os
import json
import boto3
from datetime import datetime, timezone, timedelta
def lambda_handler(event, context):
# SNS トピックの ARN
sns_topic_arn = os.environ['SNS_TOPIC_ARN']
# CloudWatch アラームイベントから関連情報を抽出
alarm_name = event['alarmData']['alarmName']
alarm_reason = event['alarmData']['state']['reason']
region = event['region']
timestamp_utc = event['alarmData']['state']['timestamp']
description = event['alarmData']['configuration']['description']
# UTC のタイムスタンプを日本時間に変換
timestamp_utc = datetime.strptime(timestamp_utc, '%Y-%m-%dT%H:%M:%S.%f+0000')
timestamp_jst = timestamp_utc + timedelta(hours=9) # JST (UTC + 9 hours)
# SNS へ送信するメッセージを作成
message = f"アラーム名: {alarm_name}\n"\
f"理由: {alarm_reason}\n"\
f"リージョン: {region}\n"\
f"タイムスタンプ: {timestamp_jst.strftime('%Y-%m-%d %H:%M:%S')} (JST)\n"\
f"説明: {description}"
# SNS へ送信する Subject を設定
subject = alarm_name
# SNS にメッセージを送信
sns_client = boto3.client('sns')
sns_client.publish(
TopicArn=sns_topic_arn,
Message=message,
Subject=subject
)
EventBridge からの通知
EventBridge
イベントパターンは次の通り、alarmName が Error_ServiceA から始まる CloudWatch アラームのみに限定して通知することとします。
{
"source": ["aws.cloudwatch"],
"detail-type": ["CloudWatch Alarm State Change"],
"detail": {
"alarmName": [{
"prefix": "Error_ServiceA"
}],
"state": {
"value": ["ALARM"]
}
}
}
通知内容
EventBridge → SNS → Email に通知した場合
今回は、Lambda ではなく EventBridge の入力トランスフォーマーを使ってメッセージの内容を変換しています。
ただし、EventBridge のターゲット入力トランスフォーマーからは Subject が変換できるわけではないので、Subject も変更したい場合や、時刻を日本時間にしたい場合などは、Lambda をかます必要がありそうです。
EventBridge → SNS → Chatbot → Slack に通知した場合
ここでも、EventBridge の入力トランスフォーマーを使っています。
詳しくは以下の方の記事とドキュメントを参考にしてみて下さい。
なお、入力トランスフォーマーを利用しなかった場合は、Slack に通知が飛びませんでした。
Chatbot のメトリクスを確認してみると、UnsupportedEvents が上がっています。
これは、サポートされていないイベントまたはメッセージが試行された数のようです。
ちなみに、サポートされている GuardDuty イベントを通知した場合は、入力トランスフォーマー無しに通知することができました。