20
10

More than 3 years have passed since last update.

Lambdaのデフォルトログを出力させずに意図したログのみを出力する

Posted at

Lambda実行時にデフォルトで表示されるログを非表示にしつつ、アプリケーションで意図したログだけをCloudWatch Logsに出力する方法です。

CloudWatch Logsの料金は高いので、なるべく保存するログを減らしたいという目的で対応しました。

通常のログ出力(何もしない場合)

まずは何もしない場合です。

今回のテストで利用するLambdaです。
Node.js 12.X です。

Lambda
exports.handler = async (event) => {
    console.log('log test');
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

出力されるログは以下のようになります。

START RequestId: XXXXXX Version: $LATEST
2020-03-13T13:33:26.678Z    XXXXXX  INFO    log test
END RequestId:  XXXXXX 
REPORT RequestId:  XXXXXX   Duration: 17.18 ms  Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 70 MB  Init Duration: 108.39 ms    

このようにLambda上で出力するように書いたのは、log testだけなのですが、START~ END~ REPORT~ というLambdaがデフォルトで出力するログが一緒に出力されています。
今回の記事は、これらのデフォルトのログは出力しないようにしつつ、Lambdaで書いたメッセージだけを出力したいという内容です。

デフォルトのログを出力しないようにする

IAMの権限修正

Lambdaのデフォルトログを出力しないようにするには、IAMを修正します。

Lambdaを作成した時にロールも同時に作成した場合、そのロールにはCloudWatch logサービスへの書き込み許可が設定されています。

また、CloudWatch logsのCreateLogStream, PutLogEventsアクションに対して書き込み許可が設定されています。

このうちCreateLogStreamの書き込み許可を外すことで、自動でログストリームが作成されないため、結果としてログを出力しないように設定可能です。

アクション許可設定.png

上記はCreateLogStreamの許可を外して、PutLogEventsだけが残っている状態です。

ただしこの対応を行うとconsole.logも出力されなくなります。

Streamの作成

CreateLogStreamの許可を外したことで、ログストリームが自動で作成されなくなりました。
そのため、ログストリームを手動で作成します。

CloudWatchのロググループでログストリームの作成を行ってください。

ログストリームの作成.png
ログストリームの作成.png

手動でログ出力

では残りはログを出力する処理を書いていきます。

ログの出力はaws-sdkを利用します。
では全体的なコードをお見せします。

ログ出力Lambda
const LOG_GROUP_NAME = '/aws/lambda/loglog';
const LOG_STREAM_NAME = 'test';

const AWS = require('aws-sdk');
const cloudwatchlogs = new AWS.CloudWatchLogs({region: 'ap-northeast-1'});

const outLog = async (msg) => {
  const describeParams = {
    logGroupName: LOG_GROUP_NAME,
    logStreamNamePrefix: LOG_STREAM_NAME,
  };
  const data = await cloudwatchlogs.describeLogStreams(describeParams).promise();
  console.log(data);
  let sequenceToken = null;
  if (data.logStreams[0]) {
    sequenceToken = data.logStreams[0].uploadSequenceToken;
  }
  console.log('sequenceToken:' + sequenceToken);

  const params = {
    logEvents: [{
      message: msg,
      timestamp: Date.now()
    }],
    logGroupName: LOG_GROUP_NAME,
    logStreamName: LOG_STREAM_NAME,
    sequenceToken: sequenceToken,
  };
  console.log('put start');
  await cloudwatchlogs.putLogEvents(params).promise();
  console.log('put end');
};

exports.handler = async (event) => {

    await outLog('log test');
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

解説

ログの出力はputLogEventsメソッドを利用します。putLogEvents AWSドキュメント

入力パラメータには、ログを出力するためのロググループやログストリーム、出力するメッセージなどを指定してください。

PutLogEventsを2回以上呼び出すとsequenceTokenを付与しないと拒否されてしまいます。
そのため、describeLogStreamsメソッドを利用して、uploadSequenceTokenを取得し、その値をPutLogEventsに渡してあげています。
describeLogStreams AWSドキュメント

今回outLogというfunctionを作成しましたが、どのLambdaでも使うということであれば、Lambda-Layerにしてしまうのも良いと思います。

その他

今回の対応ではCreateLogStreamを拒否にしましたが、CreateLogStreamは許可としつつ、
PutLogEventsで許可するリソースを一部に限定(例えば固定値+日付など)にすることで、Lambdaでログストリームの作成+作成したログストリームにログ出力などの対応でも問題ありません。
その方がログが整理されて出力可能なのでより良いと思います。

20
10
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
20
10