AWS Lambda Functionのログを取得するgulpタスクを作ってみた

2015.08.14

最近、Lambda Functionの開発をしてたりするのですがマネジメントコンソール上でCloudWatch Logsに保存されるLambda Functionログを確認するのがかなり辛いということがありました。そこでlambchop-tailも試してみたんですが元々node-aws-lambdaを利用してデプロイ1を行っていることもあり、直近のLambda FunctionのログをCloudWatch Logsから取得するgulpタスクを作りました。

ソースコード

node-aws-lambdaのGulp exampleに以下のソースコードを追加すると動作します。なお、取得するLogStreamの数をgulpコマンドのオプションとして指定できるようにしたかったのでminimist2を利用しています。

var AWS = require("aws-sdk");
var minimist = require('minimist');

var knownOptions = {
    string: 'logslimit',
    'default' : {
      'logslimit' : 1
    }
};

var options = minimist(process.argv.slice(2), knownOptions);

gulp.task('logs', function(callback) {
  var config = require("./lambda-config.js");
  var cloudwatchlogs = new AWS.CloudWatchLogs({
    region : config.region
  });

  var logGroupName = '/aws/lambda/' + config.functionName;
  cloudwatchlogs.describeLogStreams({
    logGroupName : logGroupName,
    descending : true, // 直近のログを取得する
    limit : options.logslimit, // --logslimit オプションで指定可能
    orderBy : 'LastEventTime'
  }, function(err, data) {
    if (err) {
      console.log(err, err.stack);
      return;
    }
    data.logStreams.forEach(function(logStream) {
      // ログの取得。paginationは未実装
      cloudwatchlogs.getLogEvents({
        logGroupName : logGroupName,
        logStreamName : logStream.logStreamName
      }, function(err, data) {
        if (err) {
          console.log(err, err.stack);
          return;
        }
        // ログ出力
        data.events.forEach(function(event) {
          var lines = event.message.split('\n');
          lines.pop(); // 最後に付与されている改行文字を除去
          // 先頭行を出力
          console.log(lines.shift());
          // 1ログに2行以上ログがあれば出力。その際にインデントする
          for ( var i in lines) {
            console.log('\t' + lines[i]);
          }
        });
      });
    });
  });
});

コメントにもあるようにgetLogEventsメソッドのpaginationは未実装です。今の所、アプリの規模が小さくそこまでログがなかったので。paginationが必要な場合は追加実装してください。

実行

hello-world blueprintのログを取得してみます。まずはhello-world blueprintのソースを貼っておきます。

console.log('Loading function');

exports.handler = function(event, context) {
    console.log('Received event:', JSON.stringify(event, null, 2));
    console.log('value1 =', event.key1);
    console.log('value2 =', event.key2);
    console.log('value3 =', event.key3);
    context.succeed(event.key1);  // Echo back the first key value
    // context.fail('Something went wrong');
};

このFunctionに対してlogsタスクを実行すると以下の様な感じでログを取得できます。引数の--logslimitオプションはデフォルト値が1なので、1でよい場合は指定不要です。以下ではオプションがあることを示すため指定しています。

$ gulp logs --logslimit 1
[13:18:15] Using gulpfile ~/gulpfile.js
[13:18:15] Starting 'logs'...
2015-07-01T08:34:04.329Z	8lkpgcs36e4jsizq	Loading function
START RequestId: edb60818-1fcb-11e5-abb3-c31e55314433
2015-07-01T08:34:04.332Z	edb60818-1fcb-11e5-abb3-c31e55314433	Received event: {
	  "key1": "value1",
	  "key2": "value2",
	  "key3": "value3"
	}
2015-07-01T08:34:04.332Z	edb60818-1fcb-11e5-abb3-c31e55314433	value1 = value1
2015-07-01T08:34:04.332Z	edb60818-1fcb-11e5-abb3-c31e55314433	value2 = value2
2015-07-01T08:34:04.332Z	edb60818-1fcb-11e5-abb3-c31e55314433	value3 = value3
END RequestId: edb60818-1fcb-11e5-abb3-c31e55314433
REPORT RequestId: edb60818-1fcb-11e5-abb3-c31e55314433	Duration: 2.03 ms	Billed Duration: 100 ms 	Memory Size: 128 MB	Max Memory Used: 27 MB
$ 

ソースを読むと分かりますが、1ログの中で改行が存在する場合は2行目以降はインデントしています。

まとめ

これを作ったおかげでマネジメントコンソール上でログを確認するというストレスから開放されました。ただ、Lambda FunctionからCloudWatch Logsへのログの出力にはタイムラグがあるので、そこは待ちが発生するのが残念です(´・ω・`)

よければご利用下さい。


  1. node-aws-lambdaの利用方法はAWS LambdaファンクションをGulpでデプロイを参照して下さい。 
  2. Pass arguments from the command lineというレシピがあったのでgulpで引数を利用する際はminimistを利用するのがよいようです。