Lambda実行時にデフォルトで表示されるログを非表示にしつつ、アプリケーションで意図したログだけをCloudWatch Logsに出力する方法です。
CloudWatch Logsの料金は高いので、なるべく保存するログを減らしたいという目的で対応しました。
通常のログ出力(何もしない場合)
まずは何もしない場合です。
今回のテストで利用するLambdaです。
Node.js 12.X です。
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
の書き込み許可を外すことで、自動でログストリームが作成されないため、結果としてログを出力しないように設定可能です。
上記はCreateLogStream の許可を外して、PutLogEvents だけが残っている状態です。 |
ただしこの対応を行うとconsole.log
も出力されなくなります。
Streamの作成
CreateLogStream
の許可を外したことで、ログストリームが自動で作成されなくなりました。
そのため、ログストリームを手動で作成します。
CloudWatchのロググループでログストリームの作成を行ってください。
手動でログ出力
では残りはログを出力する処理を書いていきます。
ログの出力はaws-sdk
を利用します。
では全体的なコードをお見せします。
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でログストリームの作成+作成したログストリームにログ出力などの対応でも問題ありません。
その方がログが整理されて出力可能なのでより良いと思います。