経緯
CodeBuildのログを整形してメール通知する必要がありました。
構築
今回はCodeBuildの失敗ログがトリガーになるので、CloudWatch Eventsで
CodeBuildの失敗するイベントを作成します。
そこからSNS経由でロググループとログストリーム名をLambdaで受け取り、ログをなんやかんやします。
※AWSのアイコンがアップデートされてさらにおしゃれになってました
こういう細かなアップデートがあるのもAWSの魅力ですね。
ただ、最新版にEmailのアイコンが無くなったような・・・?
CloudWatch Events
項目 | 値 |
---|---|
イベントパターン | チェック |
サービス名 | CodeBuild |
イベントタイプ | CodeBuild Build State Change |
特定の状態 | FAILED |
ターゲット | SNS① |
SNS①
- トピック名:任意
- サブスクリプション: Lambdaのエンドポイント(プロトコル:Lambda)
Lambda
設定項目 | 値 |
---|---|
関数の作成 | 一から作成 |
名前 | 任意 |
ランタイム | Python3.6 |
ロール | 1つ以上のテンプレートから |
ロール名 | 任意 |
ポリシーテンプレート① | Amazon SNS 発行ポリシー |
ポリシーテンプレート② | CloudWatchLogsReadOnlyAccess |
トリガーの追加 | SNS① |
タイムアウト | 1分 |
環境変数 | SNSarn/SNS②のArn |
コード
import json
import boto3
import os
import time
TOPIC_ARN = os.environ['SNSarn']
def lambda_handler(event, context):
message_unicode = event['Records'][0]['Sns']['Message']
message_dist = json.loads(message_unicode)
group_name = message_dist['detail']['additional-information']['logs']['group-name']
stream_name = message_dist['detail']['additional-information']['logs']['stream-name']
time.sleep(90)
client = boto3.client('logs')
logs = client.get_log_events(
logGroupName=group_name,
logStreamName=stream_name,
startFromHead=True
)
body = logs['events']
message = ""
for line in body:
log = '{}'.format(line['message'])
message = message + log + '\n'
Msg = message
sub = '[Codebuild FAILED]'
client = boto3.client('sns')
response = client.publish(
TopicArn=TOPIC_ARN,
Message=Msg,
MessageStructure='context',
Subject=sub
)
SNS②
- トピック名:任意
- サブスクリプション: 通知したいメールアドレス
最後に
実際に検討を行ったCodeBuildのログは7000行あり、
メールが複数来たり、内容が不足していました。
原因は(環境差があると思いますが、)CodeBuildからCloudWatch Logsにログが出力されるまで約1分差がある事です。
Lambda起動時にはログがすべて出力され切らないまま動作し、またLambdaが3秒でtimeoutしてしまいます。
そこでPythonのコード上でスリープを入れ、Lambdaのtimeoutを3秒から増やしました。
するとSNSの本文に記載できる量をオーバーしてのエラーになった為、
一旦、S3へ保存し、通知したい内容を選別しSNS本文に記載する内容を絞りました。
苦戦しましたが、やりたい事は実現できました。
もっとスマートな方法がありましたら、ご教示頂けますと幸いです。