あくまで個人的なメモ

あくまで個人的なメモ

CloudWatch Logs に蓄積したログをS3に定期的にエクスポートする

前回各サーバのログを集約させた。

これをS3にexportしてログの集計など他の処理に繋げる。 また、古いログなどCloudWatch Logsで見る必要がないログはexportしてから消してしまうのも一つの手だと思う。 (S3のほうがアーカイブ料金は若干安い)

S3バケットの作成

export先として指定するバケットを作る。ログの出力先用に作ると良いと思う。 export元のCloudWatch Logsと同じリージョンになるように注意すること。

バケットポリシーの設定

作成したバケットの Permissions > Bucket policy を選択し、バケットポリシーを編集する。

下記は作成したバケット名が「export-log-backet-name」の場合の例。Resourceを書き換えてね。

{
    "Version": "2012-10-17",
    "Statement": [
      {
          "Action": "s3:GetBucketAcl",
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::export-log-backet-name",
          "Principal": { "Service": "logs.ap-northeast-1.amazonaws.com" }
      },
      {
          "Action": "s3:PutObject" ,
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::export-log-backet-name/*",
          "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" } },
          "Principal": { "Service": "logs.ap-northeast-1.amazonaws.com" }
      }
    ]
}

Exportしてみる。

CloudWatch 画面からLogs > 対象のロググループを選択。 ActionsからExport data to Amazon S3 を選択。

S3 bucket name を上記で作成したものを選択。Advanced を選択して S3 bucket prefix を入れるとバケット内のフォルダを指定できる。

対象のバケットに無事にexportされたらこれを自動化する。

exportするLambda Functionを書く

'use strict';

const aws = require('aws-sdk');
aws.config.update({region: 'ap-northeast-1'});

exports.handler = (event, context, callback) => {
    const s3 = new aws.S3();
    const cloudwatchlogs = new aws.CloudWatchLogs();

    var getToTS = function() {
        var now = new Date();
        now.setHours(0);
        now.setMinutes(0);
        now.setSeconds(0);
        now.setMilliseconds(0);
        return now.getTime();
    };
    var getFromTS = function(toTS) {
        var to = new Date(toTS);
        to.setDate(to.getDate()-1);
        return to.getTime();
    };
    var dateFormat = function(date) {
        var y = ('000' + date.getFullYear()).slice(-4);
        var m = ('0' + (date.getMonth() + 1)).slice(-2);
        var d = ('0' + date.getDate()).slice(-2);
        return y + "-" + m + "-" + d;
    };

    // 日次での処理を想定している。
    var toTS = getToTS(); // 実行日時の00:00:00.0
    var fromTS = getFromTS(toTS); // 実行日時1日前の00:00:00.0
    var s3BucketName = 'logs-bucket'; // 出力先のS3バケット
    var s3prefix = 'hoge-logs/' + (dateFormat(new Date(fromTS))); // 出力ファイルのprefix
    var taskName = 'export_task_' + (dateFormat(new Date(fromTS)));
    var logGroupName = 'log_group';

    // 上記の設定で CloudWatch Logs の「log_group」というロググループに溜められたログの内容が
    // s3://logs-bucket/hoge-logs/yyyy-mm-dd/ に出力される。

    var response = cloudwatchlogs.createExportTask(
        {
            'taskName': taskName,
            'logGroupName': logGroupName,
            'from': fromTS,
            'to': toTS,
            'destination': s3BucketName,
            'destinationPrefix': s3prefix
        }, function(err, data) {
            if (err) {
                console.log(err, err.stack); // an error occurred
            } else {
                console.log(data); // successful response
            }
        }
    );

    callback(null, response);
};

注意点は、複数エクスポートタスクの作成は出来ないらしい。 複数のexportが必要であればcreateExportTaskで作成したタスクの完了を検知して次のタスクを積むような制御が必要。

createExportTask自体はタスクの作成のみなのでタスクの進捗状況はdescribeExportTasks辺りで確認する。

(あとで書くかもしれない。書かないかもしれない)

定期的に Lambda Function を実行するように設定する。

Lambda Functionを新規で作る。定期実行には CloudWatch Events を使うのでTriggerに CloudWatch Eventsを追加する。

Ruleの設定

新しくruleを作る。

Rule name、Rule descriptionは適当に。

Rule typeはSchedule expression。UTCでの起動タイミングになる。cron(5 0 * * ? *)で毎日00:05(UTC)に実行される。

参考