LoginSignup
43
34

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-01-16

🔷 はじめに

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

43
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
34