AWS SNSから届くメールを読みやすくする

## はじめに
AWSでエラー検知をしてメールを飛ばすという仕組みを作るのは簡単ですが、最低限の設定だけでメールを送ると、なかなか解読が難しい文字列が送られてきます。
現場でも使う仕組みだったので、少しでも読みやすくする方法を調べてみました。

以下の2つの記事が大変参考になりました。
[CloudWatch アラームの通知メールを少しでも読みやすくしたい](https://dev.classmethod.jp/articles/human-readable-mail-from-cloudwatch/)
[EventBridgeの入力トランスフォーマーでSNSのメール通知内容を整形してみた](https://blog.serverworks.co.jp/eventbridge/)


## エラー通知メール（通常のすがた）を確認
### 構成
　今回は「testAPI」という名前のAPIを作成して、APIでエラーが発生した場合、メールで通知するようにします。
　構成図は以下のとおりです。
![スクリーンショット_20221202_213345.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/65638422-6b19-5dc8-f062-93b354ed3459.png)
　ざっくりと説明すると、CloudWatchで監視を行い、CloudWatchがエラーを検知したらSNSでメールを送るという流れです。
　testAPIを作成したという前提で、SNSトピックの作成とCloudWatch Alarmの設定を説明します。

### SNSトピックの作成
　トピックで、タイプを「スタンダード」、名前はAPI名と何を通知するかわかるように設定します。
![スクリーンショット_20221201_203202.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/a977f7f8-4ae6-e8a1-d2c6-b31f91ea69dd.png)

　サブスクリプションで、プロトコルを「Eメール」、エンドポイントを自分のメールアドレスに設定します。
![スクリーンショット_20221201_203323.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/7ff7f17e-b88d-1b1b-3f43-9aaecfc0f43e.png)

　これだけだとサブスクリプションが保留中になっています。
![スクリーンショット_20221201_201040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/50f4836a-bd27-9312-2143-c0f230918b98.png)

　登録したメールアドレスに認証メールが届いているので、「Confirm subscription」を押すと、以下の画面が出てきてSNSトピックの設定は完了です。
![スクリーンショット_20221201_203411.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/d9e980b5-da17-37c5-822b-e5b877940bd4.png)

　

### CloudWatch Alarmの設定

　メトリクスはtestAPIの「4XXError」を選択します。ここは実際に監視したい項目を選んでください。（「4XXError」の選出理由はエラーが出しやすいというだけなので…）
![スクリーンショット_20221201_204259.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/739bde7d-2050-4c71-5a80-1241063be767.png)
![スクリーンショット_20221201_204319.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/cfbbab44-b3eb-d61e-e9b7-a8cf2a3e4769.png)
![スクリーンショット_20221201_204334.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/ad4f13b1-bba9-da87-daba-0c89a260ef8c.png)
![スクリーンショット_20221201_204450.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/2a6e303a-b617-bb88-1eb7-94720d0f0493.png)
　
　統計「合計」、期間「5分」にします。
![スクリーンショット_20221201_204526.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/8a686139-30ba-74b0-69f4-b515856d62a9.png)

　条件は以下の画像のとおり、しきい値の種類「静的」、4XXErrorが次の時…「以上」、…よりも「1」で設定します。
　これで「5分間で、4XXErrorが1回以上発生したとき」アラーム状態になります。
![スクリーンショット_20221201_204556.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/102e0958-bc2b-419d-be7a-9e74af648a60.png)

　アクションの設定で、アラーム状態トリガーを「アラーム状態」、次のSNSトピックに通知を送信を「既存のトピックを選択」、通知の送信先を先ほど作ったSNSトピック名にします。
![スクリーンショット_20221201_204620.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/1f062bc1-b7e3-6ada-5498-423e7a457b9f.png)

　アラーム名を設定します。
![スクリーンショット_20221201_204647.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/790814d5-5602-a56e-4d1e-b7f325db1fab.png)

### エラー通知メールを確認
　適当にエラーを発生させて（APIの4XXエラーは存在しないパスにアクセスすれば出ます）、エラー通知メールを待ちます。
　来ました。
![スクリーンショット_20221201_205037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/8a589859-6da1-7382-036d-6f2abf48b59e.png)

　・・・・・・？？？？
　これはあくまで一部の抜粋で、本文はこの2倍くらい文字がずら～～～～と並んでいます。
　AWSを全く知らない人に見せたら「迷惑メール？」と言われました。たしかに、寝起きの頭だと迷惑メールとして処分してしまうかもしれません。私はまだまだひよこなので、しっかり目覚めていてエラー通知メールと認識できても、解読が大変です。
　そこで、SNSから発行されるメールの加工方法がないか調べてみました。


## エラー通知メールを読みやすくする
### 構成
　先ほどから構成を少し変えます。EventBridgeというサービスを新たに追加します。
　流れをざっくりと説明すると、CloudWatchで監視を行い、CloudWatchがエラーを検知したらEventBridgeにイベントソースを送り、EventBridgeはイベントソースをもとにメッセージを加工して、SNSでメールを送るという流れです。
![スクリーンショット_20221202_213339.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/b09453ff-1c56-b36d-e4f3-d9cd94f9b10c.png)
　エラー検知するAPIや、CloudWatch Alarm、SNSトピックは基本的にそのまま使いますが、CloudWatch AlarmとSNSトピックについては少し設定の変更をします。

### CloudWatch Alarmの設定変更
　先ほどは、CloudWatch Alarmがアラーム状態になったら(＝エラーを検知したら)、SNSトピックに通知を行うという設定にしていました。
　しかし、今回はCloudWatch Alarmがアラーム状態になったら、EventBridgeにイベントソースを送るという構成にします。そのため、CloudWatch Alarmのアクションの設定から通知を削除します。
![スクリーンショット_20221214_220359.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/866f2e46-9f61-6f77-29ff-11cfe47b3220.png)

### SNSトピックの設定変更
　実は通知メールの件名は、SNSトピックの表示名と同じです。
　SNSトピックの表示名は任意の項目ですが、画像のように入力して、よりエラーが来たことをわかりやすくしました。
![スクリーンショット_20221201_225955.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/77cc0780-4444-4007-83de-35bad66c8c82.png)

　CloudWatch AlarmとSNSトピックについて、設定変更が終わったので、新しく使うEventBridgeの設定を行っていきます！　



### EventBridgeの設定
　ルールの詳細を定義で、名前をわかりやすいものに(画像ではCloudWatchアラームと同じ名前にしています)、イベントを「default」に、ルールタイプを「イベントパターンを持つルール」にします。
![スクリーンショット_20221201_205221.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/570df5c2-e61a-7153-f5b4-bda658831bd5.png)

　イベントパターンを構築で、イベントソースを「AWSイベントまたはEventBridgeパートナーイベント」を選択します。
　さらに、イベントパターンで、イベントソースを「AWSのサービス」、AWSのサービスを「CloudWatch」、イベントタイプを「CloudWatch Alarm State Change」にします。イベントパターンは画像の通りにJSONコードを入力します。
![スクリーンショット_20221201_205302.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/2b67b234-fcac-5417-e233-588181584a27.png)
![スクリーンショット_20221201_205426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/3a86c2f9-b6a5-391a-7f28-d2adbd19f0b0.png)
![スクリーンショット_20221201_225932.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/b56b77c8-c5b7-edaa-5f02-777082e9ab29.png)


　ターゲットを選択で、ターゲットタイプを「AWSのサービス」、ターゲットを選択を「SNSトピック」、トピックを先ほど作ったトピックにします。
![スクリーンショット_20221201_205743.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/2d1e84bd-7706-811e-ab3e-9deaad78dc2e.png)

　ターゲットを選択の追加設定をクリックします。
　ターゲット入力を設定から、「入力トランスフォーマー」を選択して、「入力トランスフォーマーを設定」を選択します。
![スクリーンショット_20221201_205804.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/04bb0759-1f5d-377b-9458-2603e9de57b4.png)

　入力トランスフォーマーを設定します。
　サンプルイベントを選択し、EventBridgeに渡されるイベントソースを確認して、
![スクリーンショット_20221201_205855.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/869105e9-6c0f-2640-0b47-08753c0bc365.png)
　入力パスで、サンプルイベントから必要な項目を抽出して変数に代入して、
![スクリーンショット_20221201_210258.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/890b87c9-32cd-6de0-43cc-6d72cd3583ec.png)
　入力テンプレートで、入力パスで定義した変数を使いながらSNSトピックに渡すメッセージを作っていくという流れです。
　イベントソースは使わずに、入力テンプレートに必要なメッセージを入力するというような使い方も可能です！　ただし、改行を含む入力テンプレートは各行をダブルクォーテーションで囲むのが必須のようです。（[公式ドキュメント](https://aws.amazon.com/jp/premiumsupport/knowledge-center/eventbridge-human-readable-notifications/)）
![スクリーンショット_20221214_215338.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/4fa33e0f-585c-facb-693b-15e21c411346.png)


### エラー通知メール（加工後のすがた）
![スクリーンショット_20221201_225537.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735282/e7fe4f95-69d2-bfef-6fb9-1cf0abf5fd3f.png)

　だいぶ何言ってるかわかるようになったのではないでしょうか！
　入力テンプレートは記号等を含めて自由に記載できたので、メール受信者の事情（AWSの習熟度や、さっと読みたい/じっくり詳しくエラーの原因を把握したいといったニーズ）に合わせて内容を変えていけるのが良いですね。


## 感想
　
　AWSは基本英語のサービスだと理解はしていますが、やっぱり日本語の方がうれしい。
　今回Eventbridgeを触ってみて、AWSサービスを呼び出すときはJSON形式でイベントソースを渡していることを改めて認識できました（そういえば、API GatewayからLambda関数を起動するときにJSON形式でイベントを渡していたなぁと思い出したり）。このあたりの理解をもっと深めたら、サービスどうしを組み合わせていろんなことができて楽しそうです。