CloudWatch LogsからS3バケットにエクスポートするシェルスクリプト

はじめに

先日先人が作り上げた、偉大なログエクスポートを実行するStepFunctionsがコケていました。
先人ほどのスキルもないので、CloudShellを利用してCloudWatchLogsからS3へエクスポートするシェルスクリプトを作成したので記事として残します。
StepFunctionsの根本対応が必要ですが、まずは一時的な対応としてシェルスクリプトを作成。
マネジメントコンソールからGUI操作も可能ですが、対象となるCloudWatchLogsの量が多いことや、アクセスキーが払い出されていないことから、本番環境のCloudShellで作業実施を決めました。

参考:
AWS ドキュメント「AWS CLI を使用してログデータを Amazon S3 にエクスポートする」

構成図


構築

1.S3バケットの準備

実機ではStepFunctionsから毎晩ログが対象のS3バケットにエクスポートされているため設定は不要。
ただし検証するために新規作成しているため、新たに作成したS3バケットに、以下バケットポリシーを追記する。
※東京リージョンを想定
arn:aws:s3:::[YOUR-BUCKET-NAME]部分は、ログが転送されるS3バケット名を入力する

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::[YOUR-BUCKET-NAME]"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::[YOUR-BUCKET-NAME]/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}

2.CloudWatch LogsからS3バケットにエクスポートするシェルスクリプト

2.1.転送するCloudWatchLogsのリストファイルを作成

S3へ転送したい CloudWatchLogsのロググループをテキストファイル形式で作成して保存
※下記log.txtの内容にS3に転送したいロググループ名を記載する

【例】log.txt

/aws/lambda/cfn-sf-inamura-LambdaHumanApprovalSendEmailFunctio-wPwtEbDmKEg3
/aws/lambda/cfn-stepfunctions-inamura-LambdaHumanApprovalSendE-3j0qFdWkOpat
/aws/lambda/cfn-stepfunctions-inamura-LambdaHumanApprovalSendE-D92dYTTBLAmy
/aws/lambda/cfn-stepfunctions-inamura-LambdaHumanApprovalSendE-IbgVOxScNeUI
/aws/lambda/cfn-stepfunctions-inamura-LambdaHumanApprovalSendE-UTH7yskJ5b79

2.2.CloudWatch LogsからS3バケットにエクスポートするシェルスクリプトを作成

【シェルスクリプト】bash export_log_groups_to_s3.sh

#!/bin/bash
#エラーが発生した場合停止する
set -e

#引数$1:ログリストパス
#引数$2:保存先S3バケット名の記載がない場合はエラー表示
if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Please provide both a log group name file and a bucket name as arguments."
  exit 1
fi

log_group_name_file=$1
s3_bucket_name=$2

#検索開始・終了時間
start_time=$(($(date -d "2020/01/01" +%s)*1000)) 
end_time=$(($(date -d "2023/05/01" +%s)*1000))

#ログリストを一行ずつ実行
while IFS= read -r log_group_name
do
  #空行になるまで繰り返す
  if [ -z "$log_group_name" ]; then
    continue
  fi

  #タスクネーム作成
  task_name="ExportTask-$(date +%Y%m%d%H%M%S)"

  #ロググループ名の一文字めの"/"を削除するr
  prefix=${log_group_name#/}

  #エクスポートタスクを作成しタスクIDを取得
  task_id=$(aws logs create-export-task --task-name "${task_name}" --log-group-name "${log_group_name}" --from ${start_time} --to ${end_time} --destination "${s3_bucket_name}" --destination-prefix "${prefix}" --query 'taskId' --output text)

  #エクスポートタスク作成が失敗した場合、どのロググループで失敗したか表示
  if [ $? -ne 0 ]; then
    echo "Failed to create export task for log group ${log_group_name}"
    exit 1
  fi

  #エクスポートタスクのステータスを取得
  while true; do
    status=$(aws logs describe-export-tasks --task-id "${task_id}" --query 'exportTasks[0].status.code' --output text)

    #エクスポートステータスが”COMPLETED”なら、次のタスクを実行するためループ終了
    if [[ "${status}" == "COMPLETED" ]]; then
      echo "Export task for log group ${log_group_name} completed successfully."
      break
    fi

    #エクスポートタスクが”FAILED”なら、どのロググループで失敗したか表示して終了
    if [[ "${status}" == "FAILED" ]]; then
      echo "Export task for log group ${log_group_name} failed."
      exit 1
    fi

    #エクスポートタスクが"RUNNING","PENDING"なら30秒sleep後、再実行
    if [[ "${status}" == "RUNNING" ]] || [[ "${status}" == "PENDING" ]]; then
      echo "Export task for log group ${log_group_name} wait please."
      sleep 30
    fi
  done
done < "$log_group_name_file"

挙動の確認

1.CloudShellで実行

$1引数:S3へ出力したいログリストのテキストファイル
$2引数:出力先とするS3バケット

$ bash export_log_groups_to_s3.sh "log.txt" "20220214-inamura"

2.実行結果の確認

2.1.CloudShell画面での実行結果確認

何度かS3バケットに送れないということで「wait please」が出ましたが、30秒待機して再トライして送信ができてることがターミナル画面からわかる


2.2.実行後のS3バケット画面での確認

S3にも出力されていることを確認できる

2.3.CloudWatchLogsの画面での確認

2.3.1.「Amazon S3へのすべてのエクスポートを表示」画面へ遷移

CloudWatch > ロググループ > アクション > Amazon S3へのすべてのエクスポートを表示 を押下

2.3.2.エクスポートタスクでの確認

エクスポートタスクが完了しており、ステータスが「Completed successfully」となっていることを確認

さいごに

ログ転送中は同時に2つの処理を実行できないことは新たな学びでした。
さて一時対応が済んだので、StepFuncitonsの根本解決に着手していこうと思います。
※利用したS3バケットは検証終了したため削除されています。

Last modified: 2023-05-28

Author