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は「バケット」と呼ばれる空間にデータを格納します。
まずは、ログの格納先となるバケットを作成します。
Amazon S3
https://s3.console.aws.amazon.com/s3/home
1. S3の[バケットを作成する] ボタンをクリックします。
必要項目を入力します。
⬛バケット名
・任意のバケット名を入力します。
・ただし、この名称がそのままURLなるので、他と重複しない名前にする必要があります。
・今回は、「test-logs-2-0-1-8」とします。
⬛リージョン
・CloudWatchのログと同じリージョンを選択する必要があります。
・今回は
2. バケットが作成されたら、バケットに対する権限を設定します。
対象バケットを開き、[アクセス権限]→[バケットポリシー]をクリックします。
バケットポリシーはJSON形式で記述します。
以下の内容を貼り付けます。
簡単に説明すると、バケットに以下の権限を付与しています。
CloudWatch Logsでロググループを選択して、[アクション]→[データをS3にエクスポート]をクリックします。
エクスポートする範囲と、エクスポート先を設定します。
⬛開始日
・エクスポートしたいログの範囲の、開始日を設定します。
⬛終了日
・エクスポートしたいログの範囲の、終了日を設定します。
⬛バケット名
・エクスポート先のバケット名を設定します。
・今回は作成した「test-logs-2-0-1-8」バケットを設定します。
⬛バケットプレフィックス
・エクスポート先のバケットの、プレフィックス名を設定します。
・今回は権限設定で
・もし
入力したら[エクスポートの開始]ボタンをクリックします。
4. S3で「test-logs-2-0-1-8」バケットの中を確認します。
「log-okiba」プレフィックスが作られています。さらにその中にはログがエクスポートされています。
確認できたら、バケットの中身は削除しましょう。
5. ログの保持期間の設定。
ログローテーションで毎日ログをエクスポートするので、ログの保持期間は短くします。
CloudWatch Logsで、対象のロググループのイベント失効期間をクリックします。
保持期間を変更します。
⬛保持期間
・任意の保持期間を選択します。
・今回は毎日エクスポートするので、
[OK]ボタンをクリックしたら、CloudWatch Logsの設定は完了です。
先程、CloudWatchのログをS3にエクスポートする処理を手動で行いましたが、同じ事を自動で行うLambda関数を作成します。
AWS Lambda
https://console.aws.amazon.com/lambda/home
1. [関数の作成]ボタンをクリックして、作成を開始します。
2. 今回は、「一から作成」でLambda関数を作成します。
⬛名前
・任意の名称を入力します。
・今回は「exportLogTest」とします。
⬛ランタイム
・今回は
⬛ロール
・LambdaにS3やCloudWatchを操作する権限を設定します。
・そのような権限のみが設定されたロールは都合よく無いので、今回はロールを作成します。
・
⬛IAMロール
・
⬛ロール名
・任意の名称を入力します。
・今回は「exportLogTestRole」とします。
権限の内容はポリシードキュメントにJSON形式で書きます。編集リンクをクリックします。
デフォルトは、以下のようにLambdaからCloudWatch Logsにログを出力するための、3つの権限のみが設定されています。
編集したら、[許可]ボタンをクリックします。
Lambda関数の作成画面に戻るので、[関数の作成]ボタンをクリックします。
3. Lambda関数のコードを書きます。
作成したLambda関数に、CloudWatch LogsとS3への権限が設定されていれば下のように、表示されます。
index.jsに、ログをバケットにエクスポートする処理を書きます。
以下の内容を貼り付けるだけでOKです。
キモとなる処理は、
(必要なければ、設定しないでソースの中に直接書き込んでOKです。)
⬛環境変数
⬛タイムアウト
・Lambda関数を実行した時の、タイムアウトまでの時間。
・今回は1分とします。
1. Lambda関数を実行するトリガを設定します。
LambdaのDesignerメニューの中から、
すると、下図のようにトリガとして
「トリガーの設定」メニューが表示されます。
⬛ルール
・
ルールの詳細を設定します。
⬛ルール名
・任意の名称をセットします。
・今回は
⬛ルールの説明
・分かりやすい説明を入力します。
・今回は、毎日、日本時間の01:05にLambda関数を実行するルールを作るので、その旨を記載します。
⬛ルールタイプ
・
・今回は、毎日指定の時間をトリガにしたいので、
⬛スケジュール式
・実行ルールの式をセットします。
・今回は、毎日、日本時間の01:05にLambda関数を実行するルールを作るので、
・式の書き方はルールのスケジュール式を参照。
最後に、[保存]ボタンをクリックして、Lambdaの設定は完了です。
正常に処理が実行できていれば、以下のように日毎にログがエクスポートされます。
手動やLambadaから、エクスポートを行った時に、「エクスポートタスク」が上がりますが、エクスポートタスクを複数立ち上げる事はできません。
ドキュメントにも以下のように書かれています。
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
�� はじめに
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の[バケットを作成する] ボタンをクリックします。
必要項目を入力します。
⬛バケット名
・任意のバケット名を入力します。
・ただし、この名称がそのままURLなるので、他と重複しない名前にする必要があります。
・今回は、「test-logs-2-0-1-8」とします。
⬛リージョン
・CloudWatchのログと同じリージョンを選択する必要があります。
・今回は
米国東部(バージニア北部)
を選択します。2. バケットが作成されたら、バケットに対する権限を設定します。
対象バケットを開き、[アクセス権限]→[バケットポリシー]をクリックします。
バケットポリシーは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
CloudWatch Logsでロググループを選択して、[アクション]→[データをS3にエクスポート]をクリックします。
エクスポートする範囲と、エクスポート先を設定します。
⬛開始日
・エクスポートしたいログの範囲の、開始日を設定します。
⬛終了日
・エクスポートしたいログの範囲の、終了日を設定します。
⬛バケット名
・エクスポート先のバケット名を設定します。
・今回は作成した「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」プレフィックスが作られています。さらにその中にはログがエクスポートされています。
確認できたら、バケットの中身は削除しましょう。
5. ログの保持期間の設定。
ログローテーションで毎日ログをエクスポートするので、ログの保持期間は短くします。
CloudWatch Logsで、対象のロググループのイベント失効期間をクリックします。
保持期間を変更します。
⬛保持期間
・任意の保持期間を選択します。
・今回は毎日エクスポートするので、
3日間
にします。[OK]ボタンをクリックしたら、CloudWatch Logsの設定は完了です。
�� Lambda関数の作成
先程、CloudWatchのログをS3にエクスポートする処理を手動で行いましたが、同じ事を自動で行うLambda関数を作成します。AWS Lambda
https://console.aws.amazon.com/lambda/home
1. [関数の作成]ボタンをクリックして、作成を開始します。
2. 今回は、「一から作成」でLambda関数を作成します。
⬛名前
・任意の名称を入力します。
・今回は「exportLogTest」とします。
⬛ランタイム
・今回は
Node.js 8.10
を選択します。⬛ロール
・LambdaにS3やCloudWatchを操作する権限を設定します。
・そのような権限のみが設定されたロールは都合よく無いので、今回はロールを作成します。
・
カスタムロールの作成
を選択します。カスタムロールの作成
を選択すると、ロール作成画面が開きます。⬛IAMロール
・
新しいIAMロールの作成
を選択します。⬛ロール名
・任意の名称を入力します。
・今回は「exportLogTestRole」とします。
権限の内容はポリシードキュメントにJSON形式で書きます。編集リンクをクリックします。
デフォルトは、以下のようにLambdaからCloudWatch Logsにログを出力するための、3つの権限のみが設定されています。
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- 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関数の作成画面に戻るので、[関数の作成]ボタンをクリックします。
3. Lambda関数のコードを書きます。
作成したLambda関数に、CloudWatch LogsとS3への権限が設定されていれば下のように、表示されます。
index.jsに、ログをバケットにエクスポートする処理を書きます。
以下の内容を貼り付けるだけで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
でまとめたdestination
やlogGroupName
等の必要パラメータを渡して、ログのエクスポートを実行しているところです。(参考:createExportTask)getTimeData
でログの取り込み範囲を2日前〜1日前にしていますが、これはドキュメントに、ログデータは、エクスポートできるようになるまで最大 12時間かかる場合があります。と書かれているためです。(参考:Amazon S3 へのログデータのエクスポート)
params
で渡している必要パラメータは、バケットの変更等に対応しやすいように、直接ソースに書かずに、process.env.○○
で環境変数に設定しています。(必要なければ、設定しないでソースの中に直接書き込んでOKです。)
⬛環境変数
-
BucketName
: test-logs-2-0-1-8 -
DestinationPrefix
: log-okiba -
LogGroupName
: hello-api-logs -
TaskName
: export_task
⬛タイムアウト
・Lambda関数を実行した時の、タイムアウトまでの時間。
・今回は1分とします。
�� 日次実行ルールの作成。
1. Lambda関数を実行するトリガを設定します。LambdaのDesignerメニューの中から、
CloudWatch Events
をクリックします。すると、下図のようにトリガとして
CloudWatch Events
がセットされるので、さらにセットされたアイコンをクリックします。「トリガーの設定」メニューが表示されます。
⬛ルール
・
新規ルールの作成
を選択します。ルールの詳細を設定します。
⬛ルール名
・任意の名称をセットします。
・今回は
daily_exe_test_rule
とします。⬛ルールの説明
・分かりやすい説明を入力します。
・今回は、毎日、日本時間の01:05にLambda関数を実行するルールを作るので、その旨を記載します。
⬛ルールタイプ
・
イベントパターン
は指定のAWSプロダクトで発生するイベントをトリガとするタイプです。・今回は、毎日指定の時間をトリガにしたいので、
スケジュール式
を選択します。⬛スケジュール式
・実行ルールの式をセットします。
・今回は、毎日、日本時間の01:05にLambda関数を実行するルールを作るので、
cron(5 16 * * ? *)
をセットします。(UTCの時差9時間を足した時間)・式の書き方はルールのスケジュール式を参照。
最後に、[保存]ボタンをクリックして、Lambdaの設定は完了です。
�� 動作確認
正常に処理が実行できていれば、以下のように日毎にログがエクスポートされます。
�� 注意
手動や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
コメント
コメントを投稿