Node.js の AWS Lambda 関数ログ作成 - AWS Lambda

Node.js の AWS Lambda 関数ログ作成

AWS Lambda は、ユーザーに代わって Lambda 関数を自動的にモニタリングし、Amazon CloudWatch にログを送信します。Lambda 関数には、関数のインスタンスごとに CloudWatch Logs ロググループとログストリームが用意されています。Lambda ランタイム環境は、各呼び出しの詳細をログストリームに送信し、関数のコードからのログやその他の出力を中継します。詳細については、「AWS Lambda での Amazon CloudWatch Logs の使用」を参照してください。

このページでは、AWS Command Line Interface、Lambda コンソール、または CloudWatch コンソールを使用して、Lambda 関数のコードからログ出力を生成する方法、またはアクセスログを生成する方法について説明します。

ログを返す関数の作成

関数コードからログを出力するには、コンソールオブジェクトのメソッドか、stdout または stderr に書き込む任意のログ記録のライブラリを使用します。次の例では、環境変数の値とイベントオブジェクトをログに記録します。

例 index.js ファイル - ログ記録
exports.handler = async function(event, context) { console.log("ENVIRONMENT VARIABLES\n" + JSON.stringify(process.env, null, 2)) console.info("EVENT\n" + JSON.stringify(event, null, 2)) console.warn("Event not processed.") return context.logStreamName }
例 ログの形式
START RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac Version: $LATEST 2019-06-07T19:11:20.562Z c793869b-ee49-115b-a5b6-4fd21e8dedac INFO ENVIRONMENT VARIABLES { "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/my-function", "AWS_LAMBDA_LOG_STREAM_NAME": "2019/06/07/[$LATEST]e6f4a0c4241adcd70c262d34c0bbc85c", "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs12.x", "AWS_LAMBDA_FUNCTION_NAME": "my-function", "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "NODE_PATH": "/opt/nodejs/node10/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules", ... } 2019-06-07T19:11:20.563Z c793869b-ee49-115b-a5b6-4fd21e8dedac INFO EVENT { "key": "value" } 2019-06-07T19:11:20.564Z c793869b-ee49-115b-a5b6-4fd21e8dedac WARN Event not processed. END RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac REPORT RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac Duration: 128.83 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 74 MB Init Duration: 166.62 ms XRAY TraceId: 1-5d9d007f-0a8c7fd02xmpl480aed55ef0 SegmentId: 3d752xmpl1bbe37e Sampled: true

Node.js ランタイムは、呼び出しごとに STARTEND、および REPORT の各行を記録します。関数によってログに記録される各エントリに、タイムスタンプ、リクエスト ID、およびログレベルを追加します。レポート行には、次の詳細が示されます。

REPORT 行のデータフィールド
  • RequestId - 呼び出しの一意のリクエスト ID。

  • 所要時間 - 関数のハンドラーメソッドがイベントの処理に要した時間。

  • 課金期間 - 呼び出しの課金対象の時間。

  • メモリサイズ - 関数に割り当てられたメモリの量。

  • 使用中の最大メモリ - 関数によって使用されているメモリの量。

  • 初期所要時間 - 最初に処理されたリクエストについて、ハンドラーメソッド外で関数をロードしてコードを実行するためにランタイムにかかった時間。

  • XRAY TraceId - トレースされたリクエストの場合、AWS X-Ray のトレース ID

  • SegmentId - トレースされたリクエストの場合、X-Ray のセグメント ID。

  • サンプリング済み - トレースされたリクエストの場合、サンプリング結果。

ログは、Lambda コンソール、CloudWatch Logs コンソール、またはコマンドラインで表示することができます。

Node.js での Lambda の高度なログ記録コントロールの使用

関数のログのキャプチャ、処理、使用方法をより細かく制御できるように、サポートされている Node.js ランタイムに以下のログ記録オプションを設定できます。

  • ログの形式 - 関数のログをプレーンテキスト形式と構造化された JSON 形式から選択します

  • ログレベル - JSON 形式のログの場合、Lambda が Amazon CloudWatch に送信するログの詳細レベル (ERROR、DEBUG、INFO など) を選択します。

  • ロググループ - 関数がログを送信する CloudWatch ロググループを選択します

これらのログ記録オプションの詳細と、それらのオプションを使用するように関数を設定する方法については、「Lambda 関数の高度なログ記録コントロールの設定」を参照してください。

Node.js Lambda 関数でログ形式とログレベルのオプションを使用するには、以下のセクションのガイダンスを参照してください。

Node.js での構造化 JSON ログの使用

関数のログ形式として JSON を選択した場合、Lambda は console.traceconsole.debugconsole.logconsole.infoconsole.error、および console.warn のコンソールメソッドを使用してログ出力を構造化された JSON として CloudWatch に送信します。各 JSON ログオブジェクトには、以下のキーを含む少なくとも 4 つのキーと値のペアが含まれます。

  • "timestamp" - ログメッセージが生成された時刻

  • "level" - メッセージに割り当てられたログレベル

  • "message" - ログメッセージの内容

  • "requestId" - 関数呼び出しの一意のリクエスト ID

関数が使用するログ記録方法によっては、この JSON オブジェクトに追加のキーペアが含まれる場合もあります。例えば、関数が console メソッドを使用して複数の引数を使用しているエラーオブジェクトをログに記録する場合、JSON オブジェクトには、errorMessageerrorTypestackTrace というキーを含む追加のキーと値のペアが含まれます。

コードで既に Powertools for AWS Lambda などの別のログ記録ライブラリを使用して JSON 構造化ログを生成している場合は、変更を加える必要はありません。Lambda は既に JSON でエンコードされたログを二重にエンコードしないため、関数のアプリケーションログは以前と同様にキャプチャされます。

Powertools for AWS Lambda ログ記録パッケージを使用して Node.js ランタイムで JSON 構造化ログを作成する方法の詳細については、「TypeScript での AWS Lambda 関数ログ」を参照してください。

JSON 形式のログ出力の例

次の例は、関数のログ形式を JSON に設定したときに、単一および複数の引数を持つ console メソッドを使用して生成されたさまざまなログ出力が CloudWatch Logs にどのようにキャプチャされるかを示しています。

最初の例では、console.error メソッドを使用して単純な文字列を出力します。

例 Node.js ログ記録コード
export const handler = async (event) => { console.error("This is a warning message"); ... }
例 JSON ログレコード
{ "timestamp":"2023-11-01T00:21:51.358Z", "level":"ERROR", "message":"This is a warning message", "requestId":"93f25699-2cbf-4976-8f94-336a0aa98c6f" }

console メソッドでは、1 つまたは複数の引数を使用して、より複雑な構造化されたログメッセージを出力することもできます。次の例では、console.log を使用して、1 つの引数を使用して 2 つのキーと値のペアを出力します。Lambda が CloudWatch Logs に送信する JSON オブジェクトの "message" フィールドは、文字列化されていないことに注意してください。

例 Node.js ログ記録コード
export const handler = async (event) => { console.log({data: 12.3, flag: false}); ... }
例 JSON ログレコード
{ "timestamp": "2023-12-08T23:21:04.664Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": { "data": 12.3, "flag": false } }

次の例では、console.log メソッドを再度使用してログ出力を作成します。今回このメソッドは、2 つのキーと値のペアを含むマップと 1 つの識別文字列の 2 つの引数を取得します。この場合、2 つの引数を指定したため、Lambda は "message" フィールドを文字列化することに注意してください。

例 Node.js ログ記録コード
export const handler = async (event) => { console.log('Some object - ', {data: 12.3, flag: false}); ... }
例 JSON ログレコード
{ "timestamp": "2023-12-08T23:21:04.664Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": "Some object - { data: 12.3, flag: false }" }

Lambda は、console.log を使用して生成された出力にログレベル INFO を割り当てます。

最後の例は、console メソッドを使用してエラーオブジェクトを CloudWatch Logs に出力する方法を示しています。複数の引数を使用してエラーオブジェクトをログに記録すると、Lambda はフィールド errorMessageerrorTypestackTrace をログ出力に追加することに注意してください。

例 Node.js ログ記録コード
export const handler = async (event) => { let e1 = new ReferenceError("some reference error"); let e2 = new SyntaxError("some syntax error"); console.log(e1); console.log("errors logged - ", e1, e2); };
例 JSON ログレコード
{ "timestamp": "2023-12-08T23:21:04.632Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": { "errorType": "ReferenceError", "errorMessage": "some reference error", "stackTrace": [ "ReferenceError: some reference error", " at Runtime.handler (file:///var/task/index.mjs:3:12)", " at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)" ] } } { "timestamp": "2023-12-08T23:21:04.646Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": "errors logged - ReferenceError: some reference error\n at Runtime.handler (file:///var/task/index.mjs:3:12)\n at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29) SyntaxError: some syntax error\n at Runtime.handler (file:///var/task/index.mjs:4:12)\n at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)", "errorType": "ReferenceError", "errorMessage": "some reference error", "stackTrace": [ "ReferenceError: some reference error", " at Runtime.handler (file:///var/task/index.mjs:3:12)", " at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)" ] }

複数のエラータイプをログに記録する場合、追加のフィールド errorMessageerrorTypestackTraceconsole メソッドに最初に渡されたエラータイプから抽出されます。

構造化された JSON ログでの埋め込みメトリクスフォーマット (EMF、Embedded Metric Format) クライアントライブラリの使用

AWS では、埋め込みメトリクスフォーマット (EMF、Embedded Metric Format) ログの作成に使用できるオープンソースのクライアントライブラリを提供しています。これらのライブラリを使用する既存の関数があり、関数のログ形式を JSON に変更すると、CloudWatch はコードによって生成されたメトリクスを認識しなくなる可能性があります。

コードが現在、console.log または Powertools for AWS Lambda (TypeScript) を使用して EMF ログを直接出力している場合でも、関数のログ形式を JSON に変更すると、CloudWatch はこれらを解析できなくなります。

重要

関数の EMF ログが引き続き CloudWatch によって適切に解析されるようにするには、EMF および Powertools for AWS Lambda ライブラリを最新バージョンに更新してください。JSON ログ形式に切り替える場合は、関数に埋め込まれているメトリクスとの互換性を確認するためのテストを実施することもお勧めします。console.log を使用してコードが EMF ログを直接出力する場合は、以下のコード例のように、これらのメトリクスを stdout に直接出力するようにコードを変更してください。

例 埋め込みメトリクスを stdout に出力するコード
process.stdout.write(JSON.stringify( { "_aws": { "Timestamp": Date.now(), "CloudWatchMetrics": [{ "Namespace": "lambda-function-metrics", "Dimensions": [["functionVersion"]], "Metrics": [{ "Name": "time", "Unit": "Milliseconds", "StorageResolution": 60 }] }] }, "functionVersion": "$LATEST", "time": 100, "requestId": context.awsRequestId } ) + "\n")

Node.js でのログレベルフィルタリングの使用

AWS Lambda でログレベルに従ってアプリケーションログをフィルタリングするには、関数で JSON 形式のログを使用する必要があります。このためには以下の 2 つの方法があります。

  • 標準のコンソールメソッドを使用してログ出力を作成し、JSON ログ形式を使用するように関数を設定します。その後、AWS Lambda は「Node.js での構造化 JSON ログの使用」で説明されている JSON オブジェクトの「level」キー値のペアを使用してログ出力をフィルタリングします。関数のログ形式を設定する方法については、「Lambda 関数の高度なログ記録コントロールの設定」を参照してください。

  • 別のログ記録ライブラリまたはメソッドを使用して、ログ出力のレベルを定義する「level」キーと値のペアを含む JSON 構造化ログをコード内に作成する。例えば、Powertools for AWS Lambda を使用してコードから JSON 構造化されたログ出力を生成できます。Node.js ランタイムで Powertools を使用する方法の詳細については、「TypeScript での AWS Lambda 関数ログ」を参照してください。

    Lambda で関数のログをフィルタリングするには、JSON ログ出力に "timestamp" のキーと値のペアも含める必要があります。時間は、有効な RFC 3339 タイムスタンプ形式で指定する必要があります。有効なタイムスタンプを指定しない場合、Lambda はログに INFO レベルを割り当ててタイムスタンプを追加します。

ログレベルのフィルタリングを使用するように関数を設定する場合、AWS Lambda が CloudWatch Logs に送信するログのレベルを以下のオプションから選択します。

ログレベル 標準的な使用状況
TRACE (最も詳細) コードの実行パスを追跡するために使用される最も詳細な情報
DEBUG システムデバッグの詳細情報
INFO 関数の通常の動作を記録するメッセージ
WARN 対処しないと予期しない動作を引き起こす可能性がある潜在的なエラーに関するメッセージ
ERROR コードが期待どおりに動作しなくなる問題に関するメッセージ
FATAL (詳細度が最も低い) アプリケーションの機能停止を引き起こす重大なエラーに関するメッセージ

Lambda は、選択したレベル以下のログを CloudWatch に送信します。例えば、ログレベルを WARN に設定すると、Lambda は WARN、ERROR、FATAL の各レベルに対応するログを送信します。

Lambda コンソールを使用する

Lambda コンソールを使用して、Lambda 関数を呼び出した後のログ出力を表示できます。

組み込み Code エディタからコードがテスト可能である場合、[実行結果] でログを確認できます。コンソールのテスト機能を使用して関数を呼び出すと、[詳細] セクションで [ログ出力] を確認できます。

CloudWatch コンソールの使用

Amazon CloudWatch コンソールを使用して、すべての Lambda 関数呼び出しのログを表示できます。

CloudWatch コンソールでログを表示するには
  1. CloudWatch コンソールの [Log groups (ロググループ)] ページを開きます。

  2. 機能のロググループを選択します( /aws/lambda/関数名)

  3. ログストリームを選択します

各ログストリームは、関数のインスタンスに相当します。ログストリームは、Lambda 関数を更新したとき、および複数の同時呼び出しを処理するために追加のインスタンスが作成されたときに表示されます。特定の呼び出しのログを検索するために、AWS X-Ray を使って関数をインストルメント化することをお勧めします。  X-Ray は、リクエストとログストリームの詳細をトレースに記録します。

AWS Command Line Interface (AWS CLI) を使用する

AWS CLI は、コマンドラインシェルでコマンドを使用して AWS サービスとやり取りするためのオープンソースツールです。このセクションの手順を完了するには、以下が必要です。

AWS CLI および --log-type コマンドオプションを使用して、呼び出しのログを取得します。レスポンスには、LogResultフィールドが含まれ、このフィールドには、呼び出しから base64 コードされた最大 4 KB のログが含まれます。

例 ログ ID を取得します

次の例は、LogResultという名前の関数のmy-functionフィールドからログ ID を取得する方法を示しています。

aws lambda invoke --function-name my-function out --log-type Tail

次のような出力が表示されます。

{ "StatusCode": 200, "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...", "ExecutedVersion": "$LATEST" }
例 ログをデコードします

同じコマンドプロンプトで、base64 ユーティリティを使用してログをデコードします。次の例は、my-functionの base64 でエンコードされたログを取得する方法を示しています 。

aws lambda invoke --function-name my-function out --log-type Tail \ --query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode

AWS CLI バージョン 2 を使用している場合、cli-binary-format オプションは必須です。これをデフォルト設定にするには、aws configure set cli-binary-format raw-in-base64-out を実行します。詳細については、バージョン 2 の AWS Command Line Interface ユーザーガイドの「AWS CLI でサポートされているグローバルコマンドラインオプション」を参照してください。

以下の出力が表示されます。

START RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Version: $LATEST "AWS_SESSION_TOKEN": "AgoJb3JpZ2luX2VjELj...", "_X_AMZN_TRACE_ID": "Root=1-5d02e5ca-f5792818b6fe8368e5b51d50;Parent=191db58857df8395;Sampled=0"",ask/lib:/opt/lib", END RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 REPORT RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Duration: 79.67 ms Billed Duration: 80 ms Memory Size: 128 MB Max Memory Used: 73 MB

base64このユーティリティは、Linux、macOS、および Windows の Ubuntu で使用できます。macOS ユーザーは、base64 -Dを使用する必要があります 。

例 get-logs.sh スクリプト

同じコマンドプロンプトで、次のスクリプトを使用して、最後の 5 つのログイベントをダウンロードします。このスクリプトはsedを使用して出力ファイルから引用符を削除し、ログが使用可能になるまで15秒待機します。この出力には Lambda からのレスポンスと、get-log-events コマンドからの出力が含まれます。

次のコードサンプルの内容をコピーし、Lambda プロジェクトディレクトリに get-logs.sh として保存します。

AWS CLI バージョン 2 を使用している場合、cli-binary-format オプションは必須です。これをデフォルト設定にするには、aws configure set cli-binary-format raw-in-base64-out を実行します。詳細については、バージョン 2 の AWS Command Line Interface ユーザーガイドの「AWS CLI でサポートされているグローバルコマンドラインオプション」を参照してください。

#!/bin/bash aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"key": "value"}' out sed -i'' -e 's/"//g' out sleep 15 aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name stream1 --limit 5
例 macOS および Linux (専用)

同じコマンドプロンプトで、macOS と Linux ユーザーが次のコマンドを実行して、スクリプトが実行可能であることを確認する必要があります。

chmod -R 755 get-logs.sh
例 最後の 5 つのログイベントを取得します

同じコマンドプロンプトで、次のスクリプトを実行して、最後の 5 つのログイベントを取得します。

./get-logs.sh

次のような出力が表示されます。

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" } { "events": [ { "timestamp": 1559763003171, "message": "START RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf Version: $LATEST\n", "ingestionTime": 1559763003309 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tENVIRONMENT VARIABLES\r{\r \"AWS_LAMBDA_FUNCTION_VERSION\": \"$LATEST\",\r ...", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tEVENT\r{\r \"key\": \"value\"\r}\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "END RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "REPORT RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\tDuration: 26.73 ms\tBilled Duration: 27 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n", "ingestionTime": 1559763018353 } ], "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795", "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080" }

ログの削除

関数を削除しても、ロググループは自動的には削除されません。ログが無期限に保存されないようにするには、ロググループを削除するか、ログが自動的に削除されるまでの保存期間を設定します。