AWSの部屋

AWS学習者向けのブログです

CloudWatch のログで特定の文字列を検出した際に Lambda と SNS でメール送信を行う

はじめに

システム運用時にエラーはつきものかと思いますが、そのエラーをいかに早く検知し対処を行うかが安定したシステム運用につながります。本日は CloudWatch に蓄積されたログから特定の文字列(エラーログに出力されている内容等)を自動で検出し、それをメールで通知するということをやってみます。

使用するサービス

  • Amazon CloudWatch・・・AWS リソースと AWS で実行するアプリケーションのモニタリングサービス
  • AWS Lambda・・・サーバーをプロビジョニングしたり管理しなくてもコードを実行できるコンピューティングサービス
  • Amazon Simple Notification Service (Amazon SNS)・・・モバイルプッシュ通知やSMS送信など様々なメディアに対応した分散型フルマネージド通知サービス

アーキテクチャ

本エントリーではログ内の「error」という文字列を検出しようと思います。

手順

  1. メール通知用 SNS トピックの作成
  2. Lambda 関数に割り当てるロールを作成
  3. SNS でメール送信を行う Lambda 関数の作成
  4. CloudWatch でサブスクリプションフィルタを作成
  5. 動作確認

1. メール通知用 SNS トピックの作成

こちらのエントリーを参照してください。

aws-room.hatenablog.com

2. Lambda 関数に付与するロールを作成

Lambda に対して以下のポリシーを割り当てたロールを作成します。

・CloudWatchLogsFullAccess
・AmazonSNSFullAccess

このようにロールを作成しました。

3. SNS でメール送信を行う Lambda 関数の作成

このような関数を作成します。(前工程で作成したロールを割り当てます)

以下のコードをデプロイします。

import base64
import json
import zlib
import datetime
import os
import boto3
from botocore.exceptions import ClientError

print('Loading function')


def lambda_handler(event, context):
    data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS)
    data_json = json.loads(data)
    log_entire_json = json.loads(json.dumps(data_json["logEvents"], ensure_ascii=False))
    log_entire_len = len(log_entire_json)

    print(log_entire_json)

    for i in range(log_entire_len): 
        log_json = json.loads(json.dumps(data_json["logEvents"][i], ensure_ascii=False))

        try:
            sns = boto3.client('sns')
    
            #SNS Publish
            publishResponse = sns.publish(
                TopicArn = os.environ['SNS_TOPIC_ARN'],
                Message = log_json['message'],
                Subject = os.environ['NOTIFICATION_SUBJECT']
            )
    
        except Exception as e:
            print(e)

デプロイが完了したら環境変数を設定します。

キー
SNS_TOPIC_ARN SNSのトピックの ARN
NOTIFICATION_SUBJECT SNS で通知される際の件名

4. CloudWatch でサブスクリプションフィルタを作成

まず CloudWatch でこのようにロググループを作成します。

ログストリームも作成します。

Lambda サブスクリプションフィルターを作成します。

項目
Lambda 関数 前工程で作成したLambda 関数
ログの形式 JSON
ログの形式 検出する文字列・パターン

5. 動作確認

AWS CLI で CloudWatch にログを出力することができるので、以下のようにしてログを出力しました。

aws logs put-log-events --log-group-name Error --log-stream-name Error-log-stream --log-events timestamp=1653457849182,message="System error"

ログ出力後、このように SNS からメールが送信されることが確認できました。

さいごに

同じことを自分で実装しようと思ったら非常に大変な作業になると思いますが、AWS のようなクラウドのサービスを活用するとメールでのアラート機能を簡単に作ることができました。CloudWatch を初めてしっかりと使ってみたのですが、やはり自分で手を動かすことでサービスに対する理解が深まりますね。これからもどんどん色々なサービスを使っていこうと思います。