タイトル通りです。
管理人は当サイトだけでなく他にもWebサイトや自宅にサーバを持っています。
それらのサーバのログをCloudWatch Logsで収集しているのですが、ずっとCW Logsに入れておくわけにもいかないのでS3へ退避させるLambdaを作成しました。
本記事の概要
目的
- CloudWatch Logsに格納してるログをS3へエクスポートするLambdaを作成する
前提条件
- CloudWatch Logsにロググループとログストリームが存在していること
- Lambdaのランタイムには「Node.js 14.x」を利用する
- 当記事の内容は、ある程度のAWSの基礎的知識を身に着けている前提とする
CW Logs To S3退避用Lambdaを作成する手順
1. Lambda関数を作成する
- Lambdaコンソールを開き、新しい関数を作成します。
- 「一から作成」にチェックがついてることを確認します。
- 以下のパラメータを指定します。
「関数名」「タイム」
※アーキテクチャ は「x86_64」を指定します - 実行ロールは「基本的な Lambda アクセス権限で新しいロールを作成」を選択しておきます。
※後でポリシーを追加します - 詳細設定はデフォルトのまま、画面右下の「関数の作成」をクリックします。
- 関数作成後、初期ファイル (index.js)に後述の「Lambdaコード」を張り付け、デプロイします。
- 環境変数の設定を行います。Lambda関数画面の設定タブから環境変数項目を選択し、以下の変数を設定します。
- Key=BucketName
Valueには退避先S3バケット名を入力してください - Key=DestinationPrefix
Valueには退避元のCloudWatch Logsのロググループ名を入力してください - Key=LogGroupName
Valueには退避元のCloudWatch Logsのロググループ名を入力してください - Key=TaskName
ValueにはLambda関数名を入力してください
- Key=BucketName
2. CWLogsとS3操作用のIAMポリシーを作成する
- IAMコンソールへ遷移し、左ペインから「IAMポリシー」を選択します。
- 以下の権限を持つIAMポリシーを作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:CreateExportTask",
"s3:GetBucketAcl",
"s3:PutObject"
],
"Resource": "*"
}
]
}
- Lambda関数作成時に生成されたIAMロールに上記IAMポリシーを付与します。
3. テスト実行
- 作成したLambda関数を実行してみます。
- S3へログが退避されてること、及びLambda関数の実行ログ(CloudWatch Logs)を確認します。
4. EventBridgeで処理を自動化する
- Lambda関数画面の設定タブからトリガー項目を選択し、新しいトリガーから「EventBridge (CloudWatch Events)」を選択します。
- 各項目に応じた適切なパラメータを指定し、画面右下「追加」をクリックします。
- ルール:新規ルールを作成
- ルール名:<任意のルール名を入力>
- ルールの説明:<任意の説明を入力>
- ルールタイプ:スケジュール式 「cron(5 16 * * ? *)」
※日次で01:05 JSTでスケジュール実行するcron式になります
- EventBradgeが追加されたことを確認します。
Lambdaコード
'use strict';
const aws = require('aws-sdk');
aws.config.update({region: 'ap-northeast-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;
}
コメント