Lambda + S3 で、CloudWatch Logsのログをログローテーションする

Lambda + S3 で、CloudWatch Logsのログをログローテーションする:


�� はじめに

AWSの各種プロダクトのログは、CloudWatchに出力する事ができます。

そして、CloudWatchに出力したログは、手動でS3にエクスポートする事もできます。

しかし、S3に自動でログローテーションする機能はありません。(2018年12月時点)

そこで、今回は、ログローテーションをLambdaで実現したいと思います。


�� 作業手順

今回は、CloudWatchのログを日次処理でS3にエクスポートする処理を行う、Lambda関数を作成します。

作業手順は大きく3つになります。

1. S3のバケットを作成する。

2. CloudWatch LogsのログをS3にエクスポートする処理を行う、Lambda関数を作成する。

3. CloudWatch Eventsで、Lambda関数が日次処理で実行するように設定する。


�� 実装


�� S3のバケット作成

S3は「バケット」と呼ばれる空間にデータを格納します。

まずは、ログの格納先となるバケットを作成します。

Amazon S3
https://s3.console.aws.amazon.com/s3/home

1. S3の[バケットを作成する] ボタンをクリックします。


S0.png


必要項目を入力します。
s00.png
  

⬛バケット名

・任意のバケット名を入力します。

・ただし、この名称がそのままURLなるので、他と重複しない名前にする必要があります。

・今回は、「test-logs-2-0-1-8」とします。

⬛リージョン

・CloudWatchのログと同じリージョンを選択する必要があります。

・今回は米国東部(バージニア北部)を選択します。

2. バケットが作成されたら、バケットに対する権限を設定します。


s01.png


対象バケットを開き、[アクセス権限]→[バケットポリシー]をクリックします。
S02.png
  

バケットポリシーはJSON形式で記述します。

以下の内容を貼り付けます。

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
        { 
            "Action": "s3:GetBucketAcl", 
            "Effect": "Allow", 
            "Resource": "arn:aws:s3:::test-logs-2-0-1-8", 
            "Principal": { "Service": "logs.us-east-1.amazonaws.com" } 
        }, 
        { 
            "Action": "s3:PutObject" , 
            "Effect": "Allow", 
            "Resource": "arn:aws:s3:::test-logs-2-0-1-8/log-okiba/*", 
            "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" } }, 
            "Principal": { "Service": "logs.us-east-1.amazonaws.com" } 
        } 
    ] 
} 
簡単に説明すると、バケットに以下の権限を付与しています。

  • 「test-logs-2-0-1-8」バケットにアクセスする権限(s3:GetBucketAcl)
  • 「test-logs-2-0-1-8」バケットの「log-okiba」プレフィックス(フォルダ)に、ファイルを書き込む権限(s3:PutObject)
  • バケット利用対象サービスは、CloudWatch Logs  
3. 作成したバケットの設定が上手くいっているか、実際にログをエクスポートして確認します。

CloudWatch Logsでロググループを選択して、[アクション]→[データをS3にエクスポート]をクリックします。


S03.png


エクスポートする範囲と、エクスポート先を設定します。


S04.png


⬛開始日

・エクスポートしたいログの範囲の、開始日を設定します。

⬛終了日

・エクスポートしたいログの範囲の、終了日を設定します。

⬛バケット名

・エクスポート先のバケット名を設定します。

・今回は作成した「test-logs-2-0-1-8」バケットを設定します。

⬛バケットプレフィックス

・エクスポート先のバケットの、プレフィックス名を設定します。

・今回は権限設定でarn:aws:s3:::test-logs-2-0-1-8/log-okiba/*と設定したので、「log-okiba」とします。

・もしarn:aws:s3:::test-logs-2-0-1-8/*と設定していたら、記載しなくても大丈夫でした。  

入力したら[エクスポートの開始]ボタンをクリックします。

4. S3で「test-logs-2-0-1-8」バケットの中を確認します。

「log-okiba」プレフィックスが作られています。さらにその中にはログがエクスポートされています。


S05.png


確認できたら、バケットの中身は削除しましょう。

5. ログの保持期間の設定。

ログローテーションで毎日ログをエクスポートするので、ログの保持期間は短くします。

CloudWatch Logsで、対象のロググループのイベント失効期間をクリックします。


S06.png


保持期間を変更します。
S07.png


⬛保持期間

・任意の保持期間を選択します。

・今回は毎日エクスポートするので、3日間にします。

[OK]ボタンをクリックしたら、CloudWatch Logsの設定は完了です。


�� Lambda関数の作成

先程、CloudWatchのログをS3にエクスポートする処理を手動で行いましたが、同じ事を自動で行うLambda関数を作成します。

AWS Lambda
https://console.aws.amazon.com/lambda/home

1. [関数の作成]ボタンをクリックして、作成を開始します。


L00.png


2. 今回は、「一から作成」でLambda関数を作成します。


L01.png


⬛名前

・任意の名称を入力します。

・今回は「exportLogTest」とします。

⬛ランタイム

・今回はNode.js 8.10を選択します。
L02.png

⬛ロール

・LambdaにS3やCloudWatchを操作する権限を設定します。

・そのような権限のみが設定されたロールは都合よく無いので、今回はロールを作成します。

カスタムロールの作成を選択します。

カスタムロールの作成を選択すると、ロール作成画面が開きます。


L02_iam01.png


⬛IAMロール

新しいIAMロールの作成を選択します。

⬛ロール名

・任意の名称を入力します。

・今回は「exportLogTestRole」とします。

権限の内容はポリシードキュメントにJSON形式で書きます。編集リンクをクリックします。



L02_iam02.png


デフォルトは、以下のようにLambdaからCloudWatch Logsにログを出力するための、3つの権限のみが設定されています。

  • logs:CreateLogGroup
  • logs:CreateLogStream
  • logs:PutLogEvents
ここに、以下のようなログをエクスポートする権限と、S3バケットにアクセスして、書き込む権限を追加します。

  • logs:CreateExportTask
  • s3:GetBucketAcl
  • s3:PutObject
よってポリシードキュメントは以下のように編集します。

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
        { 
            "Effect": "Allow", 
            "Action": [ 
                "logs:CreateLogGroup", 
                "logs:CreateLogStream", 
                "logs:PutLogEvents", 
                "logs:CreateExportTask", 
                "s3:GetBucketAcl", 
                "s3:PutObject" 
            ], 
            "Resource": "*" 
        } 
    ] 
} 
編集したら、[許可]ボタンをクリックします。

Lambda関数の作成画面に戻るので、[関数の作成]ボタンをクリックします。



L02_iam03.png


3. Lambda関数のコードを書きます。

作成したLambda関数に、CloudWatch LogsとS3への権限が設定されていれば下のように、表示されます。
L03.png

index.jsに、ログをバケットにエクスポートする処理を書きます。



L04.png


以下の内容を貼り付けるだけでOKです。

'use strict'; 
 
const aws = require('aws-sdk'); 
aws.config.update({region: 'us-east-1'}); // バージニア北部にグローバルリージョンを指定 
 
/** 
 * メイン処理 
 * @param event : 呼び出し元サービスから渡される値 
 * @param context : AWS側の各種情報 
 * @param callback : 呼び出し元サービスへ返す値 
 *  
 */ 
exports.handler = (event, context, callback) => { 
  const cloudwatchlogs = new aws.CloudWatchLogs(); 
  let params; 
  let getToTime = []; 
  getToTime = getTimeData(); 
 
 
  /*  
  "destination"で設定したS3バケットに、"destinationPrefix"で設定したフォルダを作り、 
  "logGroupName"で設定したCludWatchのロググループのlogをexportする。 
  exportするlogの範囲は、"from"から"to"で設定した範囲。 
  */ 
  params = { 
    'destination': process.env.BucketName, 
    'from': getToTime[0], 
    'to': getToTime[1], 
    'logGroupName': process.env.LogGroupName, 
    'destinationPrefix': `${process.env.DestinationPrefix}/${getToTime[2]}`, 
    'taskName': `${process.env.TaskName}/${getToTime[2]}` 
  }; 
 
  console.log(JSON.stringify(params)); 
 
  /* logのexport処理 */ 
  cloudwatchlogs.createExportTask(params, (err, data) => { 
    let response; 
    if (err) { 
      console.log(err, err.stack); 
      response = err.stack; 
    } else { 
      console.log(data); 
      response = data; 
    } 
    callback(null, response); 
  }); 
}; 
 
 
/** 
 * ログ取得の開始日時、終了日時、日付フォーマットを返す。 
 * ログデータは、エクスポートできるようになるまで最大 12時間かかる場合があるので、 
 * 1日前のログを取得するように日時を調整。 
 * @return arr : [from, to, format] 
 *  
 */ 
function getTimeData() { 
  let arr=[]; 
  let now = new Date(); 
  now.setTime(now.getTime() + 1000*60*60*9);// JSTに変換 
  let yyyy,mm,dd; 
  console.log(now); 
 
  /* 開始日:fromをarrにセット */ 
  now.setDate(now.getDate()-2); 
  now.setHours(0); 
  now.setMinutes(0); 
  now.setSeconds(0); 
  now.setMilliseconds(0); 
  arr.push(now.getTime()); 
  console.log(`ログ取得from:${now.getFullYear()}/${now.getMonth() + 1}/${now.getDate()}`); 
 
  /* 終了日:toをarrにセット */ 
  now.setDate(now.getDate()+1); 
  arr.push(now.getTime()); 
  console.log(`ログ取得to:${now.getFullYear()}/${now.getMonth() + 1}/${now.getDate()}`); 
 
  yyyy = now.getFullYear(); 
  mm = ('0' + (now.getMonth() + 1)).slice(-2); 
  dd = ('0' + now.getDate()).slice(-2); 
  arr.push(`${yyyy}-${mm}-${dd}`); 
 
  return arr; 
} 
キモとなる処理は、createExportTaskに、paramでまとめたdestinationlogGroupName等の必要パラメータを渡して、ログのエクスポートを実行しているところです。(参考:createExportTask

getTimeDataでログの取り込み範囲を2日前〜1日前にしていますが、これはドキュメントに、

ログデータは、エクスポートできるようになるまで最大 12時間かかる場合があります。
と書かれているためです。(参考:Amazon S3 へのログデータのエクスポート

paramsで渡している必要パラメータは、バケットの変更等に対応しやすいように、直接ソースに書かずに、process.env.○○で環境変数に設定しています。

(必要なければ、設定しないでソースの中に直接書き込んでOKです。)


L05.png


⬛環境変数


  • BucketName : test-logs-2-0-1-8

  • DestinationPrefix : log-okiba

  • LogGroupName : hello-api-logs

  • TaskName : export_task
また、エクスポート処理は数秒では完了しない可能性が高いので、タイムアウトする時間も延長します。


L06.png


⬛タイムアウト

・Lambda関数を実行した時の、タイムアウトまでの時間。

・今回は1分とします。


�� 日次実行ルールの作成。

1. Lambda関数を実行するトリガを設定します。

LambdaのDesignerメニューの中から、CloudWatch Eventsをクリックします。

すると、下図のようにトリガとしてCloudWatch Eventsがセットされるので、さらにセットされたアイコンをクリックします。


L07.png


「トリガーの設定」メニューが表示されます。
L08.png


⬛ルール

新規ルールの作成を選択します。
L09.png


ルールの詳細を設定します。
L09.png


⬛ルール名

・任意の名称をセットします。

・今回はdaily_exe_test_ruleとします。

⬛ルールの説明

・分かりやすい説明を入力します。

・今回は、毎日、日本時間の01:05にLambda関数を実行するルールを作るので、その旨を記載します。

⬛ルールタイプ

イベントパターンは指定のAWSプロダクトで発生するイベントをトリガとするタイプです。

・今回は、毎日指定の時間をトリガにしたいので、スケジュール式を選択します。

⬛スケジュール式

・実行ルールの式をセットします。

・今回は、毎日、日本時間の01:05にLambda関数を実行するルールを作るので、cron(5 16 * * ? *)をセットします。(UTCの時差9時間を足した時間)

・式の書き方はルールのスケジュール式を参照。

最後に、[保存]ボタンをクリックして、Lambdaの設定は完了です。


L10.png



�� 動作確認

正常に処理が実行できていれば、以下のように日毎にログがエクスポートされます。


S08.png



�� 注意

手動やLambadaから、エクスポートを行った時に、「エクスポートタスク」が上がりますが、エクスポートタスクを複数立ち上げる事はできません。

ドキュメントにも以下のように書かれています。

アカウントごとに、一度に 1 つのアクティブ (実行中または保留中) のエクスポートタスクがあります。この制限は変更できません。
そのため、エクスポートの自動実行を複数設定している場合、他と実行のタイミングが被らないように、注意が必要です。


�� 参考

AWS CLI を使用した Amazon S3 へのログデータのエクスポート
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/S3ExportTasks.html

CloudWatch Logs に蓄積したログをS3に定期的にエクスポートする
https://honeybe.hatenablog.jp/entry/2018/03/14/114635

コメント

このブログの人気の投稿

投稿時間:2021-06-17 22:08:45 RSSフィード2021-06-17 22:00 分まとめ(2089件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)