目次
はじめに
前編では、Winstonを使って自前のCloudWatchにログを出力する方法を紹介しました。後編では、CloudWatchに出力されたログからエラーログを検出し、その結果をEメールで開発者に通知する方法を紹介します。
本記事は下記の記事を参考に書かれています。
How to get notified on specific Lambda function error patterns using CloudWatch
全体構成
構築するソリューションの全体構成を下記に示します。前編では自前のCloudWatchのMyLogGroup
に書き込むとろこまでを構築しました。後編ではMyLogGroup
へのエラーログの書き込みを検出し、Eメールで通知をするところまでを構築します。
処理の流れ
後編で扱う処理の流れは大まかには以下のようになります。
スキルからログストリームのMyLogGroup
にエラーログが書き込まれると、それをトリガーにしてLambda関数のmyErrorNotifier
を起動します。
myErrorNotifier
では、渡されたエラーログの内容をデコードして、Simple Notification Service (SNS)のMyErrorTopic
に書き込みます。
MyErrorTopic
には、トピックの配信先としてEメールアドレスが登録されており、そのEメールアドレスにエラーログの内容を含むEメールが送信されます。
システムの構築
構築手順
構築は前述の構成を下流から上流に向けて行います。(これは依存関係の順になります)
- SNSトピックの作成
- IAMロールの作成
- Lambda関数の作成
- トリガーの設定
SNSトピックの作成
Simple Notification Service (SNS) にトピックを作成し、トピックの出力先 (サブスクリプション) にEメールアドレスを指定します。これにより、このトピックに書き込みがあると、Eメールで通知されます。
トピックの作成
AWSコンソールからSNSサービスのコンソールを表示します。
- 左メニューから①
トピック
を選択します - ②
トピックの作成
をクリックします
- タイプ①
スタンダード
を選択します - ②
名前 (MyErrorTopic)
を入力します - ③
トピックの作成
をクリックします
サブスクリプションの作成
トピックが作成されたら引き続きサブスクリプションを作成します。
- ①
ARN
は後でLambda関数の定義で使用します - ②
サブスクリプション
の作成をクリックします
- プロトコルに①
Eメール
を選択します - エンドポイントに通知メールを受け取る②
メールアドレス
を入力します - ③
サブスクリプションの作成
をクリックします
MyErrorTopic
へのサブスクリプションが作成されます。
Eメールアドレスの確認のために、サブスクリプションの送信先に指定したメールアドレに、下記のようなメールが送られていきます。Confirm subscription
リンクをクリックして、サブスクリプションを確認します。
IAMロールの作成
Lambda関数myErrorNotifier
に付与するロールをIndentiy and Access Management (IAM) で定義します。このロールには下記の権限がポリシーとして含まれます。
- CloudWatchへのアクセス
myErrorNotifier
自身のログを出力するためのものです。 - SNSへのアクセス
MyErrorTopic
にメッセージを書き込むためのものです。
以下ではまず最初にポリシーを定義し、次にロールを定義してそこに先に作成したポリシーをアタッチします。
ポリシーの作成
AWSコンソールからIAMサービスのコンソールを表示します。
- 左メニューから①
ポリシー
を選択します - ②
ポリシーを作成
をクリックします
- ①
JSON
タブを選択します - ②
ポリシーの定義
を入力します (詳細は後述) - ③
次のステップ: タグ
をクリックします
ポリシー定義の詳細
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:<partition>:sns:<region>:<AWS account number>:MyErrorTopic"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:<partition>:logs:<region>:<AWS account number>:log-group:/aws/lambda/MyErrorNotifier:*"
}
]
}
sns ARNには、先程定義したSNSトピックMyErrorTopic
のARNを指定します。
log ARNには、下記を指定します。
- <partition>は”aws”
- <region>は、この後作成するLambda関数用のCloudWatchが作成されるリージョン (Lambda関数と同じ場所)
- <AWS account number>は、sns ARNと同じもの
タグは設定してもしなくても構いません。次のステップ: 確認
をクリックします。
- 名前に①
MyErrorNotifierPolicy
を入力します - ②
ポリシーの作成
をクリックします
MyErrorNotifierPolicy
が作成されます。
ロールの作成
ロールを作成し、先程作成したポリシーをアタッチします。
- 左メニューから①
ロール
を選択します - ②
ロールを作成
をクリックします
- ①
AWSサービス
を選択します - 一般的なユースケースから②
Lambda
を選択します - ③
次のステップ: アクセス権限
をクリックします
- ポリシーのフィルタに①
'My'
と入力します - 先程作成した②
MyErrorNotifierPolicy
を選択します - ③
次のステップ: タグ
をクリックします
タグは設定してもしなくても構いません。次のステップ: 確認
をクリックします。
- ロール名に①
MyErrorNotifierRole
を入力します - ②
ロールの作成
をクリックします
MyErrorNotifierRole
が作成されます。
Lambda関数の作成
エラーログを受け取り、SNSに書き込むLambda関数myErrorNotifier
を作成します。
AWSコンソールからLambdaサービスのコンソールを表示します。
- 左メニューから①
関数
を選択します - ②
関数の作成
をクリックします
- ①
一から作成
を選択します - 関数名②
myErrorNotifier
を入力します - 実行ロールに③
既存のロールを使用する
を選択します - ④
MyErrorNotifierRole
を選択します - ⑤
関数の作成
をクリックします
- ①
コード
タブを選択します - ②
ソースコード
を入力します (詳細は後述) - ③
Deploy
をクリックします
ソースコード
下記のコードを入力してください。
const zlib = require('zlib');
const AWS = require('aws-sdk');
AWS.config.update({region: '...'});
const TopicArn = '...';
exports.handler = (event, context) => {
const base64Log = Buffer.from(event.awslogs.data, 'base64');
zlib.gunzip(base64Log, (err, unzipedLog) => {
if (err) {
console.error('Error occurred:', err);
throw err;
}
const stringifiedLog = unzipedLog.toString('utf8');
const log = JSON.parse(stringifiedLog);
var params = {
Message: JSON.stringify(log, null, 2),
TopicArn: TopicArn
};
let publishPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
publishPromise.then(function(data) {
console.log(`Message ${params.Message} sent to the topic ${params.TopicArn}`);
}).catch(function(err) {
console.error(err, err.stack);
});
});
};
region: このLambda関数を作成しているリージョンを指定します。
TopicArn: 先に作成したトピックMyErrorTopic
のARNを指定します。
トリガーからはエラーログがevent.awslogs.data
に入れられて送られてきます。このdata
はzipされ、更にbase64でエンコードされています。これをデコード、unzipしてエラーログの内容を復号しています。
復号されたエラーログの内容は、SNSトピックMyErrorTopic
にパブリッシュされます。MyErrorTopic
のサブスクリプションの定義によりEメールとして発信されます。
トリガーの設定
Lambda関数myErrorNotifier
を起動するトリガーとして、MyLogGroup
へのエラーログ書き込みを指定します。
- ①
設定
タブを選択します - 左メニューから②
トリガー
を選択します - ③
トリガーを追加
をクリックします
トリガーのソースとして、CloudWatch Logs
を選択します。
- ロググループに①
MyLogGroup
を選択します - フィルターの名前に②
myErrorTrigger
を入力します - フィルターパターンに③
error
を入力します - ④
追加
をクリックします
Lambda関数myErrorNotifier
に、トリガーが設定されて定義が完了します。
スキルの実行
前編と同じく、下記の会話を実行します。
U: Alexa, open hello world
A: Welcome, you can say Hello or Help. Which would you like to try?
U: Hello
A: Hello World!
U: ユーザー、A: アレクサ
メールボックスに下記の内容のメールが届けば動作確認完了です。
記載されているlogGroup, logStreamから、該当するエラーログを含むログストリームを探すことができます。
おわりに
前編と合わせて、Alexa-Hostedスキルを監視し、エラーの発生をEメールで受け取れるシステムを構築しました。
これでログを確認する手間が省け、またエラーを見落としたり、対応が遅れたりする心配も無くなります。もっとも、エラーの通知なんて来ないにこしたことはありません。筆者もメールの来ないことを祈りつつ使っています。
変更履歴
日付 | 内容 |
2021/08/15 | 初版リリース |