CloudWatch Alarm もしくは EventBridge から SNS に通知した時の内容を整理してみた

# CloudWatch Alarm からの通知

## SNS

次の通り、SNS トピックを用意しておきます。

![スクリーンショット 2024-02-19 11.22.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/7372ab0d-5178-963c-5f0a-a7700b0548bf.png)

## CloudWatch アラーム

CloudWatch アラームで先程作成した SNS を通知の送信先としておきます。

![スクリーンショット 2024-02-19 15.46.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/dd61c57c-afef-5c1c-f7ea-d20cea60684d.png)

![スクリーンショット 2024-02-19 15.46.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/97e7c961-58ca-feb2-992a-6aa28af533ef.png)

## 通知内容

ECS のタスクを意図的に 3 回連続で 1 にして、通知してみます。

### CloudWatch アラーム → SNS → Email に通知した場合

![スクリーンショット 2024-02-19 16.19.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/33d77155-c796-790d-a73d-7756ba9e5228.png)

### CloudWatch アラーム → SNS → Chatbot → Slack に通知した場合

![スクリーンショット 2024-02-19 18.33.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/5ddd8ba5-954e-fec0-0483-72a3593a2d84.png)

### CloudWatch Alarm → Lambda → SNS に通知した場合

![スクリーンショット 2024-02-20 2.10.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/99ca7901-a2cc-b684-01e2-0ded23a0fd91.png)

ちなみにここでは補足ですが、CloudWatch Alarm のアクションとして直接 Lambda を指定することができるようになりました。

そのため、CloudWatch Alarm → Lambda → SNS のようにし、Lambda で簡易的にカスタマイズして通知しています。

https://aws.amazon.com/jp/about-aws/whats-new/2023/12/amazon-cloudwatch-alarms-lambda-change-action/

CloudWatch Alarm からは次のようなイベントログです。

```json
{
	"source": "aws.cloudwatch",
	"alarmArn": "arn:aws:cloudwatch:ap-northeast-1:１２３４５６７８９０１２:alarm:Error_ServiceA_Alarm",
	"accountId": "１２３４５６７８９０１２",
	"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 は次の通り作成しています。

```python
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 アラームのみに限定して通知することとします。

```json:イベントパターン
{
  "source": ["aws.cloudwatch"],
  "detail-type": ["CloudWatch Alarm State Change"],
  "detail": {
    "alarmName": [{
      "prefix": "Error_ServiceA"
    }],
    "state": {
      "value": ["ALARM"]
    }
  }
}
```

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-event-patterns.html

## 通知内容

### EventBridge → SNS → Email に通知した場合

![スクリーンショット 2024-02-22 15.03.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/e8ed3ae0-eb9a-6554-fbf0-ec5fb338a415.png)

今回は、Lambda ではなく EventBridge の入力トランスフォーマーを使ってメッセージの内容を変換しています。
ただし、EventBridge のターゲット入力トランスフォーマーからは Subject が変換できるわけではないので、Subject も変更したい場合や、時刻を日本時間にしたい場合などは、Lambda をかます必要がありそうです。
![スクリーンショット 2024-02-22 14.22.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/3c946a4c-4d6a-2998-7d22-e9418d2eb17f.png)

![スクリーンショット 2024-02-22 14.45.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/04708d83-acb8-ea8a-7c3c-f89b65572e26.png)

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-transform-target-input.html


### EventBridge → SNS → Chatbot → Slack に通知した場合

![スクリーンショット 2024-02-22 21.39.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/1b694365-2538-6989-7a23-0e1d167bb621.png)

ここでも、EventBridge の入力トランスフォーマーを使っています。

![スクリーンショット 2024-02-22 14.22.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/a39cdc3b-ccb0-2fcc-54d9-40858f0eed19.png)

![スクリーンショット 2024-02-22 21.37.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/33722e78-8853-89bf-ec2c-296c39339935.png)

詳しくは以下の方の記事とドキュメントを参考にしてみて下さい。

https://blog.mmmcorp.co.jp/2023/11/27/statuscheck-alarm-notification/

https://docs.aws.amazon.com/ja_jp/chatbot/latest/adminguide/custom-notifs.html

なお、入力トランスフォーマーを利用しなかった場合は、Slack に通知が飛びませんでした。
Chatbot のメトリクスを確認してみると、**UnsupportedEvents** が上がっています。
これは、サポートされていないイベントまたはメッセージが試行された数のようです。

![スクリーンショット 2024-02-22 17.05.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/24a9eaea-6e7a-bfa6-55a0-1850be2b0857.png)

https://docs.aws.amazon.com/ja_jp/chatbot/latest/adminguide/related-services.html

ちなみに、サポートされている GuardDuty イベントを通知した場合は、入力トランスフォーマー無しに通知することができました。

![スクリーンショット 2024-02-22 17.00.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/504f6fc2-b450-edc3-8cdd-b4114b665a6a.png)