Java の AWS Lambda 関数ログ作成
AWS Lambda は、ユーザーに代わって Lambda 関数を自動的にモニタリングし、Amazon CloudWatch に関数メトリクスを送信します。Lambda 関数には、関数のインスタンスごとに CloudWatch Logs ロググループとログストリームが用意されています。Lambda ランタイム環境は、各呼び出しの詳細をログストリームに送信し、関数のコードからのログやその他の出力を中継します。
このページでは、AWS Command Line Interface、Lambda コンソール、または CloudWatch コンソールを使用して、Lambda 関数のコードからログ出力を生成する方法、またはアクセスログを生成する方法について説明します。
セクション
ログを返す関数の作成
関数コードからログを出力するには、java.lang.Systemstdout
や stderr
に書き込む任意のログ記録モジュールを使用できます。aws-lambda-java-core ライブラリには、コンテキストオブジェクトからアクセスできる LambdaLogger
という名前のロガークラスが用意されています。ロガークラスは複数行のログをサポートしています。
以下の例では、コンテキストオブジェクトによって提供される LambdaLogger
ロガーを使用しています。
例 Handler.java
// Handler value: example.Handler public class Handler implements RequestHandler<Object, String>{ Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public String handleRequest(Object event, Context context) {
LambdaLogger logger = context.getLogger();
String response = new String("SUCCESS"); // log execution detailslogger.log("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv())); logger.log("CONTEXT: " + gson.toJson(context));
// process eventlogger.log("EVENT: " + gson.toJson(event));
return response; } }
例 ログの形式
START RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Version: $LATEST ENVIRONMENT VARIABLES: { "_HANDLER": "example.Handler", "AWS_EXECUTION_ENV": "AWS_Lambda_java8", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "512", ... } CONTEXT: { "memoryLimit": 512, "awsRequestId": "6bc28136-xmpl-4365-b021-0ce6b2e64ab0", "functionName": "java-console", ... } EVENT: { "records": [ { "messageId": "19dd0b57-xmpl-4ac1-bd88-01bbb068cb78", "receiptHandle": "MessageReceiptHandle", "body": "Hello from SQS!", ... } ] } END RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 REPORT RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Duration: 198.50 ms Billed Duration: 200 ms Memory Size: 512 MB Max Memory Used: 90 MB Init Duration: 524.75 ms
Java ランタイムは、呼び出しごとに START
、END
、および REPORT
の各行を記録します。レポート行には、次の詳細が示されます。
レポートログ
-
RequestId - 呼び出しの一意のリクエスト ID。
-
所要時間 - 関数のハンドラーメソッドがイベントの処理に費やした時間。
-
課金期間 - 呼び出しの課金対象の時間。
-
メモリサイズ - 関数に割り当てられたメモリの量。
-
使用中の最大メモリ - 関数によって使用されているメモリの量。
-
初期所要時間 - 最初に処理されたリクエストについて、ハンドラーメソッド外で関数をロードしてコードを実行するためにランタイムにかかった時間。
-
XRAY TraceId - トレースされたリクエストの場合、AWS X-Ray のトレース ID。
-
SegmentId - トレースされたリクエストの場合、X-Ray のセグメント ID。
-
サンプリング済み - トレースされたリクエストの場合、サンプリング結果。
Lambda コンソールの使用
Lambda コンソールを使用して、Lambda 関数を呼び出した後のログ出力を表示できます。詳細については、「AWS Lambda の Amazon CloudWatch Logs へのアクセス」を参照してください。
CloudWatch コンソールの使用
Amazon CloudWatch コンソールを使用して、すべての Lambda 関数呼び出しのログを表示できます。
CloudWatch コンソールでログを表示するには
-
CloudWatch コンソールの [Log groups (ロググループ)] ページ
を開きます。 -
機能のロググループを選択します( /aws/lambda/
関数名
) -
ログストリームを選択します
各ログストリームは、関数のインスタンスに相当します。ログストリームは、Lambda 関数を更新したとき、および複数の同時呼び出しを処理するために追加のインスタンスが作成されたときに表示されます。特定の呼び出しのログを検索するために、AWS X-Ray を使って関数をインストルメント化することをお勧めします。 X-Ray は、リクエストとログストリームの詳細をトレースに記録します。
ログとトレースを X-Ray に関連付けるサンプルアプリケーションを使用するには、AWS Lambda の Error Processor サンプルアプリケーション を参照してください。
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 | base64 -d
次のような出力が表示されます。
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 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
を実行します。詳細については、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-namestream1
--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" }
ログの削除
関数を削除しても、ロググループは自動的には削除されません。ログが無期限に保存されないようにするには、ロググループを削除するか、ログが自動的に削除されるまでの保存期間を設定します。
Log4j 2 および SLF4J による高度なログ記録
AWS Lambda では、そのマネージドランタイムとベースコンテナイメージに Log4j2 が含まれていません。このため、これらは CVE-2021-44228、CVE-2021-45046、および CVE-2021-45105 で説明されている問題の影響を受けません。
お客様の関数に影響を受ける Log4j2 バージョンが含まれているという場合のため、CVE-2021-44228、CVE-2021-45046、および CVE-2021-45105 の問題の緩和に役立つ変更を Lambda Java マネージドランタイムとベースコンテナイメージに適用しました。この変更の結果、Log4J2 を使用しているお客様には、「Transforming org/apache/logging/log4j/core/lookup/JndiLookup (java.net.URLClassLoader@...)
」のような追加のログエントリが表示される場合があります。Log4J2 出力の jndi マッパーを参照するログ文字列は、いずれも「Patched JndiLookup::lookup()
」に置き換えられます。
この変更にかかわらず、Log4j2 が含まれる関数を持つすべてのお客様に、最新バージョンへの更新を強くお勧めします。特に、関数で aws-lambda-java-log4j2 ライブラリを使用しているお客様は、バージョン 1.5.0 (またはそれ以降) に更新して、関数を再デプロイするようにしてください。このバージョンは、基盤となる Log4j2 ユーティリティの依存関係をバージョン 2.17.0 (またはそれ以降) に更新します。更新された aws-lambda-java-log4j2 バイナリは Maven リポジトリ
ログ出力をカスタマイズし、単体テスト中のログ記録をサポートし、AWS SDK 呼び出しをログに記録するには、SLF4J で Apache Log4j 2 を使用します。Log4j は、ログレベルを設定し、アペンダーライブラリを使用できるようにする Java プログラムのログ記録ライブラリです。SLF4J は、関数コードを変更せずに使用するライブラリを切り替えることができるファサードライブラリです。
関数のログにリクエスト ID を追加するには、aws-lambda-java-log4j2 ライブラリのアペンダーを使用します。以下の例では、すべてのログにタイムスタンプとリクエスト ID を追加する Log4j 2 設定ファイルを示しています。
例 src/main/resources/log4j2.xml - アペンダー設定
<Configuration status="WARN">
<Appenders> <Lambda name="Lambda"> <PatternLayout> <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1} - %m%n</pattern> </PatternLayout> </Lambda> </Appenders>
<Loggers><Root level="INFO"> <AppenderRef ref="Lambda"/> </Root>
<Logger name="software.amazon.awssdk" level="WARN" /> <Logger name="software.amazon.awssdk.request" level="DEBUG" /> </Loggers> </Configuration>
この設定では、各行の先頭に日付、時刻、リクエスト ID、ログレベル、クラス名が追加されます。
例 アペンダーのログ形式
START RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Version: $LATEST
2020-03-18 08:52:43 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 INFO Handler -
ENVIRONMENT VARIABLES: { "_HANDLER": "example.Handler", "AWS_EXECUTION_ENV": "AWS_Lambda_java8", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "512", ... }2020-03-18 08:52:43 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 INFO Handler -
CONTEXT: { "memoryLimit": 512, "awsRequestId": "6bc28136-xmpl-4365-b021-0ce6b2e64ab0", "functionName": "java-console", ... }
SLF4J は、Java コードでのログ記録のためのファサードライブラリです。関数コードで、SLF4J ロガーファクトリを使用して、info()
や warn()
などのログレベルのメソッドにより、ロガーを取得します。ビルド設定で、ログ記録ライブラリと SLF4J アダプターをクラスパスに含めます。ビルド設定のライブラリを変更することで、関数コードを変更せずにロガータイプを切り替えることができます。SDK for Java からログをキャプチャするには SLF4J が必要です。
以下の例では、ハンドラークラスは SLF4J を使用してロガーを取得しています。
例 src/main/java/example/HandlerS3.java - SLF4J を使用したログ記録
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
// Handler value: example.Handler public class HandlerS3 implements RequestHandler<S3Event, String>{private static final Logger logger = LoggerFactory.getLogger(HandlerS3.class);
Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public String handleRequest(S3Event event, Context context) { ... logger.info("RECORD: " + record); logger.info("SOURCE BUCKET: " + srcBucket); logger.info("SOURCE KEY: " + srcKey); ... } }
ビルド設定では、Lambda アペンダーおよび SLF4J アダプターのランタイム依存関係と、Log4J 2 の実装依存関係を使用します。
例 build.gradle - 依存関係のログ記録
dependencies { ...
implementation 'org.apache.logging.log4j:log4j-api:[2.17.1,)' implementation 'org.apache.logging.log4j:log4j-core:[2.17.1,)' implementation 'org.apache.logging.log4j:log4j-slf4j18-impl:[2.17.1,)'
... }
テスト用にローカルでコードを実行する場合、Lambda ロガーへのアクセスにコンテキストオブジェクトは使用できず、Lambda アペンダーが使用するリクエスト ID はありません。テスト設定の例については、次のセクションのサンプルアプリケーションを参照してください。
サンプルログ記録コード
このガイドの GitHub リポジトリには、さまざまなログ記録設定の使用方法を示すサンプルアプリケーションが含まれています。各サンプルアプリケーションには、簡易のデプロイとクリーンアップ用のスクリプト、AWS SAM テンプレート、サポートリソースが含まれています。
Java のサンプル Lambda アプリケーション
-
java-basic
- 単位テストと変数ログ記録設定を使用する、最小限の Java 関数のコレクション。 -
java-events
- Amazon API Gateway、Amazon SQS、Amazon Kinesis などのさまざまなサービスからのイベントを処理する方法のスケルトンコードを含む Java 関数のコレクション。これらの関数は、最新バージョンの aws-lambda-java-events ライブラリ (3.0.0 以降) を使用します。これらの例では、依存関係としての AWS SDK が不要です。 -
s3-java
- Amazon S3 からの通知イベントを処理し、Java Class Library (JCL) を使用して、アップロードされたイメージファイルからサムネイルを作成する Java 関数。 -
API ゲートウェイを使用して Lambda 関数を呼び出す - 従業員情報を含む Amazon DynamoDB テーブルをスキャンする Java 関数。次に、Amazon Simple Notification Service を使用して、仕事の記念日を祝うテキストメッセージを従業員に送信します。この例では、API ゲートウェイを使用して関数を呼び出します。
java-basic
サンプルアプリケーションは、ログ記録テストをサポートする最小限のログ記録設定を示しています。ハンドラーコードは、コンテキストオブジェクトによって提供される LambdaLogger
ロガーを使用します。テストでは、アプリケーションは、Log4j 2 ロガーとの TestLogger
インターフェイスを実装するカスタム LambdaLogger
クラスを使用します。また、AWS SDK との互換性のためのファサードとして SLF4J を使用します。ログ記録ライブラリは、デプロイパッケージを小さく保つために、ビルド出力から除外しています。