CloudWatch LogsのログをS3にエクスポートするPowerShellスクリプト

お久しぶりです。

 
 
今回は、半年ほど前に業務で担当した PowerShell でのスクリプト作成に苦戦したので、記事として残したいと思います。
 
 

スクリプト作成の経緯

本来はスクリプト作成担当はチーム内のメンバーでしたが、体調不良で案件から外れてしまい急遽、本番環境で使用予定の 「CloudWatch LogsのログをS3にエクスポートするスクリプト」 の作成担当になりました。スクリプトの作成経験がなかったので、当時は自分でもどうなっていくのか分からない状況でした。
 
 

スクリプト条件

作成したスクリプトの条件です。
※この他にも細かい条件がいくつかありました。
 

  • Windows Server 2019 で動かす
  • AWS CLI "create-export-task" コマンドを使用
  • 毎月特定の日時に、前月1ヵ月分のログが保存されているロググループ約30個分のログを特定のS3へエクスポート
  • スクリプト開始、終了をイベントログに出力
  • スクリプト実行時に、"create-export-task" コマンドで作成する、エクスポートタスクのステタースをイベントログに出力
  • エクスポートタスクのステータスが "RUNNING"の場合は1分待機し、再度タスクのステータスを取得
     
     

 

スクリプト詳細

以下が、作成したスクリプトになります。
 


# 第1引数 ロググループ名
# 第2引数 S3バケット名

function CheckArguments {
    param(
       [Parameter(Mandatory=$true)][string[]]$Arguments

   )

    if ($Arguments.Count -eq 2) {
        return $true
    }

    else {
        return $false        
    }
}

# スクリプト実行時に引数を変数に格納する例
$log_group = $args[0]
$s3 = $args[1]

# 引数が無い場合終了
if([string]::IsNullorEmpty($args[0])) {

    Write-EventLog -LogName Application -Source "CloudLogExptScriptPS" -EntryType Warning -EventId 300 -Message "<ps1.ファイル名>:<$log_group>: <$s3>:IWARN: Argument is incorrect."
    Exit
}

# スクリプト開始メッセージ イベントログ出力
Write-EventLog -LogName Application -Source "CloudLogExptScriptPS" -EntryType Information -EventId 300 -Message "<ps1.ファイル名>:<$log_group>:<$s3>:INFO: Start."

# 引数の数をチェックする
$result = CheckArguments -Arguments $args

if ($result -eq $false) {

# 引数不正イベントログに出力
    Write-EventLog -LogName Application -Source "CloudLogExptScriptPS" -EntryType Warning -EventId 300 -Message "<ps1.ファイル名>: <$log_group>: <$s3>:IWARN: Argument is incorrect."
    Exit     
}

# 関数 エクスポート対象開始日付取得【CurrentTimeToStartUnixTime()】

function CurrentTimeToStartUnixTime() {

# 現在日時の DateTime を取得
$now = Get-Date "0:00:00"

# 前月の1日を取得
$firstday = (Get-Date $now -Day 1).AddMonths(-1)

# UNIX時間に変換 
(($firstday) - (Get-Date("1970/1/1 0:0:0 GMT"))).TotalSeconds

}

# CurrentTimeToStartUnixTime

$firstday_unix = CurrentTimeToStartUnixTime

# 変数に格納された関数名の関数を実行
$from = $firstday_unix

# 関数 エクスポート対象終了日付取得【CurrentTimeToEndtUnixTime()】

function CurrentTimeToEndtUnixTime() {

# 現在日時の DateTime を取得
$now = Get-Date "23:59:59"

# 前月の最終日
$lastday = (Get-Date $now -Day 1).AddDays(-1)

# UNIX時間に変換 
(($lastday) - (Get-Date("1970/1/1 0:0:0 GMT"))).TotalSeconds

}

# CurrentTimeToEndtUnixTime

$lastday_unix = CurrentTimeToEndtUnixTime

# 変数に格納された関数名の関数を実行
$to = $lastday_unix

# 現在日時の DateTime を取得
$now = Get-Date

# 前月を取得
$prevMonth = $now.AddMonths(-1)

# yyyymm形式の文字列に変換して出力
$taskname = $prevMonth.ToString("yyyyMM")

# 末尾000追加
$000 = "000" 

# エクスポートタスク作成
$taskIDinfoJson = aws logs create-export-task --profile exportlogs --task-name "$taskname" --log-group-name "$log_group" --from $from$000 --to $to$000 --destination "$s3" --destination-prefix "$log_group/$taskname"

# エクスポートタスク作成チェック

if($taskIDinfoJson -eq "True"){
else{
    Write-EventLog -LogName Application -Source "CloudLogExptScriptPS" -EntryType Error -EventId 300 -Message "<ps1.ファイル名>:<$log_group>: <$s3>:IERROR: Task startup confirmation error"

    break
}
}

$taskIDinfo = $taskIDinfoJson | ConvertFrom-json

$script:taskID = $taskIDInfo.taskId

# タスクID表示
# Write-Host $script:taskID

$exportStatusInfoJson = aws logs --profile exportlogs describe-export-tasks --task-id "$script:taskID"

$exportStatusInfo = $exportStatusInfoJson | ConvertFrom-Json

$script:exportStatus = $exportStatusInfo.exportTasks.status.code

# タスクのステータスが "COMPLETED" の場合は、"COMPLETED" とタスクのIDを出力し、スクリプトを終了
# タスクのステータスが "RUNNING"の場合は、1分待機し、再度タスクのステータスを取得
# タスクのステータスが "COMPLETED"または "RUNNING" 以外の場合は、エラーメッセージと第1引数、第2引数を出力してスクリプトを終了

for (;;) {
   # タスクの状態を取得
    $exportStatusInfoJson = aws logs --profile exportlogs describe-export-tasks --task-id $script:taskID
    $exportStatusInfo = $exportStatusInfoJson | ConvertFrom-Json
    $script:exportStatus = $exportStatusInfo.exportTasks.status.code

    # Write-Host $script:exportStatus

    if ($script:exportStatus -eq "COMPLETED") {
        $Result = $true

        # スクリプト正常終了
        Write-EventLog -LogName Application -Source "CloudLogExptScriptPS" -EntryType Information -EventId 300 -Message "<ps1.ファイル名>:<$log_group>:<$s3>:INFO: Normal end."

        # タスクが完了している場合の処理
        break
    }

    elseif($script:exportStatus -eq "RUNNING") {
            $Result = $true

        # タスクが実行中の場合の処理
        Start-Sleep -Seconds 60
    }

    else {

        $Result = $false

        # タスクがキャンセル、失敗、保留中の場合の処理
        Write-EventLog -LogName Application -Source "CloudLogExptScriptPS" -EntryType Warning -EventId 300 -Message "<ps1.ファイル名>:<$log_group>: <$s3>:IERROR: Task Status Check Error STATUS = $script:exportStatus"

     break
}

$script:exportStatus = 0

continue

}

 

まとめ

スクリプトが正常に動作するには
・上記で紹介したスクリプト約30個を実行するための別のスクリプト作成
・毎月特定の日時に実行するためのタスクスケジューラの設定
・イベントログ出力のためのソース作成コマンド実施

など他の作業もありましたが、今回は省かせていただきました。
 
初めてスクリプト作成する身としては、条件も多く大変でしたが試行錯誤してなんとか作成できました。 
自身のために書きましたが、誰かの参考になればいいなと思います。

Last modified: 2024-02-17

Author