AWS
CloudWatch
SNS
lambda

cloudwatchlogs -> lambda -> SNSを試してみた

More than 3 years have passed since last update.


はじめに

EC2でWebサイトのエラーログを受け取る時に、CloudWatch -> SNSだと、英語がよくわからなくて萎えるので、Lambdaで整形してからSNSでメール送信したい。

Cloudwatchlogs -> lambda -> SNSという構成でやる。

他にも、Cloudwatchlogs -> kinesis -> lambda -> SNSという方法があるが、kinesisを挟んでもあんまり旨みがないし(もちろんメリットが0ではない)、kinesis -> lambdaはポーリングなので、イベントドリブンにできない欠点がある。

参考

【新機能】Amazon CloudWatch LogsのログデータをAWS Lambdaでリアルタイムに処理する

CloudWatch Logs Subscriptionsを利用したZabbixへのログ転送


構成

logfilter1.png



  • EC2 -> CloudwatchLogs は、エージェントを経由して行う

  • データはloggroupでグループ化して管理する。(通知の際の切り分けがしやすいように)


  • CloudwatchLogs -> lambda はsubscriptionを使って、ERROR,FATALだけに絞る(INFO,WARNを送るといっぱいリクエスト増えてお金かかるので)

  • lambdaはpythonで書く(簡単なので)


  • CloudwachLogs -> SNSはメトリックスフィルターを使う

  • lambdaのエラー処理も行う(心配なので)

  • 今回SNSの整形は頑張らない(必要な情報がカスタマイズできる感じがわかればいい)


料金


cloudwatchlogs

項目
単位
料金(Month)

カスタムメトリックス

$0.5

アラーム

$0.10

取り込み
GB
$0.76

アーカイブ
GB
$0.033

EC2からの転送
GB
$0.140

EC2からの転送は最初の1GB無料、次の10Tまでがこの値段

エラーの頻度にもよるが、そんなにお金はかからない印象。

1時間に1回くらいの頻度でエラーが吐かれるくらいなら、2ドル/月もかからないと思う


lambda

リクエストのうち毎月最初の 1,000,000 件は無料

今回の構成では無料でいけると思う。


SNS

Emailは1000件無料。

その後は100,000 件あたり 2 ドル

今回は、エラーがいっぱい出たとしても2ドルで済むと思う。


合計

2ドル(cloudwatchlogs) + 無料(lambda) + 2ドル(SNS) = 4ドル

もちろん、cloudwatchlogsのデータ保持容量、エラーログ頻度によっていろいろ変わります。


コード


  • lambda


lambda

from __future__ import print_function

import base64
import json
import zlib
import datetime
import boto3

sns = boto3.client('sns')

print('Loading function')

def lambda_handler(event, context):
#print("Received event: " + json.dumps(event, indent=2))
data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS)
data_json = json.loads(data)
log_json = json.loads(json.dumps(data_json["logEvents"][0], ensure_ascii=False))
if data_json["logGroup"]:
date = datetime.datetime.fromtimestamp(int(str(log_json["timestamp"])[:10])) + datetime.timedelta(hours=9)
sns_body = {}
sns_body["default"] = ""
sns_body["default"] += "Owner : " + data_json["owner"] + "\n"
sns_body["default"] += "LogGroup : " + data_json["logGroup"] + "\n"
sns_body["default"] += "LogStream : " + data_json["logStream"] + "\n"
sns_body["default"] += "SubscriptionFilters : " + ''.join(data_json["subscriptionFilters"]) + "\n"
sns_body["default"] += "Time : " + date.strftime('%Y-%m-%d %H:%M:%S') + "\n"
sns_body["default"] += "Message : " + log_json['message'] + "\n"

topic = 'arn:aws:sns:ap-northeast-1:111111111111:***********'
subject = 'Your Email Subject!!'
region = 'ap-northeast-1'
response = sns.publish(
TopicArn=topic,
Message=json.dumps(sns_body, ensure_ascii=False),
Subject=subject,
MessageStructure='json'
)
return 'Successfully processed {} records.'.format(len(event['awslogs']))


これをlambdaにポチッと貼り付ければ大丈夫です。

SNSのTOPICだけは各自変更してください。


最後に

何か間違いあればご指摘ください。