【AWS】CloudWatch Logsからシステムログをメール通知する。
はじめに
CloudWatch Logsから対象のシステムログをメール通知する方法をアウトプットします。
今回はCloudWatch Logsのサブスクリプションフィルターを使用します。
※参考記事にあるクラスメソッドさんの記事を参考にしております。
構成
ログ送信の流れは以下の通りです。
①EC2から CloudWatch Logs へログファイル出力
②サブスクリプションフィルターで特定文字列をマッチさせて Lambda 関数を起動
③Lambda 関数で該当メッセージを抽出、SNS 用に整形
④該当文字列が含まれた行を SNS で通知(今回はメール)
前提
- 作業用IAMユーザーにて作業を実施
- 今回は、AmazonLinuxの
/var/log/messages
からのログ抽出とします。 - CloudWatch logs上に既にOS上のログが出力されている状態になります。(OS上のCloudWatchエージェント設定については割愛とさせて頂きます。)
- CloudWatch Logsのロググループ名とログストリーム名は、事前に以下のように設定しております。
項目 | 内容 | 備考 |
---|---|---|
ロググループ名 | amalinux01 | EC2のホスト名 |
ログストリーム名 | /var/log/messages | 監視したいログファイル名 |
- 監視したいEC2には、事前に
CloudWatchAgentAdminPolicy
をアタッチしたIAMロールを設定済み
今回のゴール
以下のような形でメール通知させる。
全体の流れ
①メール通知用SNSトピック作成
②Lambda関数の作成
③サブスクリプションフィルタの作成
④アラート発報試験
作業手順
①メール通知用SNSトピック作成
1.マネジメントコンソールよりSNSを開く。
2.Amazon SNSの画面より「トピック」を開く。
3.トピック一覧より「トピックの作成」を開く。
4.トピックの作成にて以下のように入力し、「トピックの作成」をクリック。
項目 | 内容 | 備考 |
---|---|---|
タイプ | スタンダード | |
名前 | Alarm_Test | 任意の名前でOK |
表示名 | 空欄 | 入力は任意 |
5.トピックが作成されたことを確認。
6.作成したトピックの画面にて「サブスクリプションの作成」をクリック。
7.以下のように選択&入力し、「サブスクリプションの作成」をクリック。
項目 | 内容 | 備考 |
---|---|---|
トピックARN | 該当トピックのARN | そのままでOK |
プロトコル | Eメール | Eメールで通知するため |
エンドポイント | 通知したいEメールアドレス |
8.サブスクリプションが正常に作成できたことを確認。
9.登録したメールアドレスに、以下件名でメールが届くので、メールの認証を実施する。
AWS Notification - Subscription Confirmation
10.再度、作成したトピック内のサブスクリプションを確認し、ステータスが「確認済み」になっていることを確認。
②Lambda関数の作成
1.マネジメントコンソールよりLambdaを開く。
2.Lambdaダッシュボードより「関数の作成」をクリック。
3.関数の作成の画面にて、「一から作成」にチェックを入れる。
4.基本的な情報の項目にて、以下のように選択し、「関数の作成」をクリック。
項目 | 設定内容 | 備考 |
---|---|---|
関数名 | AlertCode | 任意の名前を入力 |
ランタイム | Python3.7 | |
実行ロール | 以下ポリシーがアタッチされているIAMロール ・CloudWatchLogsFullAccess ・AmazonSNSFullAccess |
大きい権限を与えているため、実務で使用する場合はさらに制限が必要 |
5.関数が作成されることを確認。
6.下にスクロールし、「コード→lambda_function.py」と選択。以下コードをコピー&ペーストし、「Deploy」をクリック。
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):
# ホスト名取得
hostname = data_json['logGroup']
# ログファイル名取得
logname = data_json['logStream']
# LogEvents取得
log_json = json.loads(json.dumps(data_json["logEvents"][i], ensure_ascii=False))
#UNIX時間→時刻/JST変換
datetime_utc = log_json['timestamp'] / 1000.0
datetime_utc = datetime.datetime.fromtimestamp(datetime_utc).strftime('%Y/%m/%d %H:%M:%S')
datetime_utc = datetime.datetime.strptime(datetime_utc, '%Y/%m/%d %H:%M:%S')
datetime_jst = datetime_utc + datetime.timedelta(hours = 9)
# 件名整形
subjectmsg = "【Alert】" + hostname + "_" + logname
# 本文整形
hostmsg = "■ホスト名:" + "\n" + hostname
lognamemsg = "■ログファイル名:" + "\n" + logname
timemsg = "■発生時刻:" + "\n" + str(datetime_jst)
logmsg = "■ログ内容:" + "\n" + log_json['message']
msg = hostmsg + "\n\n" + timemsg + "\n\n" + lognamemsg + "\n\n" + logmsg
try:
sns = boto3.client('sns')
#SNS Publish
publishResponse = sns.publish(
TopicArn = os.environ['SNS_TOPIC_ARN'],
Message = msg,
Subject = subjectmsg
)
except Exception as e:
print(e)
7.コードのDeployが成功したことを確認。
8.「設定→一般設定→編集」と選択。
9.タイムアウトを1分に設定し、「保存」をクリック。
10.一般設定にてタイムアウトの値が「1分0秒」になっていることを確認。
11.「環境変数→編集」と選択する。
12.以下の環境変数を追加し、「保存」をクリック。
項目 | 設定内容 | 備考 |
---|---|---|
キー | SNS_TOPIC_ARN | SNSのarnを格納する変数 |
値 | arn:aws:sns:ap-northeast-1:+++++++++++++:Alerm_Test | 「①メール通知用SNSトピック作成」にて作成したトピックのarn |
13.環境変数が追加できたことを確認。
③サブスクリプションフィルタの作成
1.マネジメントコンソールより「CloudWatch」を起動する。
2.CloudWatch画面より「ロググループ」をクリックする。
3.今回の監視対象であるロググループをクリックする。
4.ロググループの画面より、「サブスクリプションフィルター」をクリックする。
5.サブスクリプションフィルター一覧の右側にある「作成」から「Lambdaサブスクリプションフィルターを作成」をクリックする。
6.「②Lambda関数の作成」にて作成したLambda関数を選択する。
7.下にスクロールし、以下のように入力する。
項目 | 設定内容 | 備考 |
---|---|---|
ログの形式 | JSON | |
サブスクリプションフィルターのパターン | error | フィルタリングしたい値を入力 |
サブスクリプションフィルター名 | 【ERROR】amalinux01(/var/log/messges) | 任意の名前を入力 |
8.パターンのテストを実施し問題ないことを確認後、「ストリーミングを開始」をクリックする。
9.サブスクリプションフィルターが作成できたことを確認。
※Lambdaの「設定→トリガー」の部分でも、サブスクリプションフィルターが追加されたことを確認可能
④アラート発報試験
1.監視対象のEC2へログインし、以下コマンドを実行する。
※今回は、AmazonLinux2を使用しています。
logger -p user.err -t ERROR "プログラムでエラーが発生しました"
2./var/log/messages
にログが追記されていることを確認。
sudo tail -1 /var/log/messages
[ec2-user@ip-10-0-0-204 ~]$ sudo tail -1 /var/log/messages
Aug 1 15:42:41 ip-10-0-0-204 ERROR: プログラムでエラーが発生しました
[ec2-user@ip-10-0-0-204 ~]$
3.少々待つと以下内容のメールが受信される。
※Lambdaの対象関数内の「モニタリング」を確認すると、実行ログを確認することが可能。
Discussion