Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8691

Serverless Framework でエラーを検知して Webhook で Slack に通知を飛ばす方法

$
0
0

はじめに

AppSync の Lambda リゾルバを書く際に Serverless Frameworkを使用したのですが、
デプロイ後のバグ調査の際、毎回ブラウザから AWS Console を開いて該当 Lambda の CloudWatch のログを見に行くのが面倒でした。。 :upside_down:

そのため、エラーレポートの仕組みが欲しくなり、Lambda のエラーを Slack に通知する仕組みを Serverless Framework で実装する方法について調査したので、備忘録も兼ねて記事にまとめました :writing_hand:

動作環境

1. Slack で Webhook URL を発行する

まずは 公式サイトの手順に従って Webhook URL を発行します :earth_americas:

無事発行できると、
https://hooks.slack.com/services/~~~~~/~~~~~/~~~~~~~~~~~のようなフォーマットの URL が取得出来るはずなのでメモっておきます :pencil:

2. 必要な npm パッケージをインストールする

Slack の Incoming Webhook の仕組みを使用し、
チャンネルにメッセージを送信するための npm パッケージをインストールします :arrow_down:

npm install @slack/webhook --save

3. Slack にエラーレポートを送信する Lambda 関数を作成する (TypeScript)

Serverless Framework の handler に Slack にエラーレポートを送信する関数を追加します :arrow_down:

handlers/Reporter.ts
import{gunzip}from"zlib";import{IncomingWebhook}from"@slack/webhook";/**
 * CloudWatch のログ情報
 */interfaceCloudWatchLogContent{messageType:string;owner:string;logGroup:string;logStream:string;subscriptionFilters:string[];logEvents:{id:string;timestamp:string;message:string;}[];}/**
 * Lambda リゾルバの型定義
 */typeLambdaResolver<TEvent=any>=(event:TEvent)=>Promise<any>|any;/**
 * CloudWatch のロググループに出現するエラーを通知する
 * @param event 該当するエラーログの内容
 * @return {object} event オブジェクトをそのまま返却する
 */exportconstNotifyError:LambdaResolver=async(event:any)=>{/**
{
  awslogs: {
    data: 'H4sIAAA...'
  }
}
CloudWatch から呼ばれた際の event には上記フォーマットでデータが入っている。
data 内には Base64 でエンコードされた gzip 形式で圧縮されたデータが入っているので、
gzip 形式のデータを解凍しつつ、Base64 デコードを行い JSON 文字列を取得するための関数
*/constgunzipAsync=async(base64Logs):Promise<string>=>{returnnewPromise(function(resolve,reject){gunzip(base64Logs,function(err,binary){err?reject(err):resolve(binary.toString("ascii"));});});};// 1. Base64 でエンコードされた gzip 形式で圧縮されたデータを Base64 でデコードし、gzip のバイナリとして取得する// gunzipAsync 関数で gzip 解凍して ascii 文字列として取得することで CloudWatch のログ内容を JSON 文字列で取得するconstbase64Logs=Buffer.from(event["awslogs"]["data"],"base64");constuncompressedLogs=awaitgunzipAsync(base64Logs);console.log(uncompressedLogs);// 2. 取得した JSON 文字列を CloudWatchLogContent に変換して取得するconstcontent=<CloudWatchLogContent>JSON.parse(uncompressedLogs);console.log(content);// 3. 発行した Slack の Webhook URL で IncomingWebhook クラスを生成し、// send 関数で Slack チャンネル名 (ex. #serverless-error-report) と、// CloudWatchLogContent の内容を元に作成したテキストを引数に指定して、// 該当する Slack チャンネルにテキストを投稿するconstwebhook=newIncomingWebhook("<1. で発行した Slack の Incoming Webhook URL>");awaitwebhook.send({channel:"<通知したいチャンネル名 (例: #serverless-error-report)>",icon_emoji:"hammer",// icon_emoji パラメタを指定すると Slack へのメッセージ通知の際のアイコンを変更することが可能text:`*Group*\n_${content.logGroup}_\n\n*Message*\n\`\`\`${content.logEvents[0].message}\`\`\``,});returnevent;};

4. 3. の関数をデプロイする関数として追加し、各種 Lambda 関数の CloudWatch のログを監視するイベントと紐付ける

serverless.yml手順 3.で作成した関数 NotifyErrorを記載すると共に、
監視したい関数の CloudWatch ロググループを eventscloudwatchLogに定義し、filterERRORを指定します :heavy_check_mark:

これで、
該当ロググループに ERRORが含まれていた場合、
都度 Lambda 関数が実行されるようになります :fire::arrow_down:

serverless.yml
#...# 3. で作成した Slack にエラーレポートを送信する関数 NotifyError を functions に追記し、# events を用いて、他 Lambda 関数のロググループに 'ERROR' が出力されていた場合、 NotifyError 関数が実行されるようにするfunctions:#...NotifyError:handler:CloudWatch.NotifyErrorevents:-cloudwatchLog:logGroup:/aws/lambda/${self:service.name}-${self:provider.stage}-TestFunction1filter:ERROR-cloudwatchLog:logGroup:/aws/lambda/${self:service.name}-${self:provider.stage}-TestFunction2filter:ERROR-cloudwatchLog:logGroup:/aws/lambda/${self:service.name}-${self:provider.stage}-TestFunction3filter:ERROR#...

:arrow_up:が完了したら sls deployNotifyError関数をデプロイします :keyboard:

最後に AWS CLI で CloudWatch にイベントログデータを送信してみて、
本当に Slack に通知が飛んでくるか動作確認を行いましょう :hammer_pick:

注意事項 (複数の cloudwatchLogを定義した場合)

eventsに複数の cloudwatchLogを定義した場合、
関数のデプロイ後、AWS Console で該当する Lambda 関数を見に行くと、
正しく CloudWatch のイベントが紐付けられていないように見えます :arrow_down:
492d4761e7fadb62612e539c17b3d05f.png

同様のケースが発生している方は他にもいらっしゃるようですが、
手順 5.で Slack への通知まで確認出来れば問題なく設定できています :thumbsup:

5. AWS CLI を利用してCloudWatch にイベントログデータを送信して Slack に通知が飛んでくるか検証する

CloudWatch にイベントログデータを送信するコマンドです :white_check_mark::arrow_down:

aws logs put-log-events \--log-group-name'<該当するロググループ名>(例: /aws/lambda/test-dev-TestFunction1)'\--log-stream-name'<ログストリーム名(例: test-stream)>'--log-events\timestamp=(node -e'console.log(Date.now())'),message="This is ERROR"

コマンド実行後、
AWS Console から CloudWatch の該当するロググループのログストリームを見に行くと、
This is ERRORという文字列が出力されている事が確認できるはずです :mag:

あとは Slack に通知が飛んできたことまで確認できれば動作確認完了です! :tada::arrow_down:
4a5d063485ed635c83e3ea1917043673.png

おわりに

Serverless Framework 内で完結する形で、
Lambda 関数のエラーを捕捉して Slack に通知を飛ばす方法についてまとめました :writing_hand:

eventsには cloudwatchLogの他にも eventBridgeというものも指定できます。
eventBridgeを使用すると CloudWatch 以外の様々な AWS サービスのイベント駆動で Lambda 関数を実行することが可能です :muscle:

eventsを有効活用することで効率よくイベント駆動の処理を書いていけるので、
是非とも有効活用していきましょう! :runner::dash:

参考リンク


Viewing all articles
Browse latest Browse all 8691

Trending Articles