第 2 世代のランタイム(Java 11 以降)のロギングには、第 1 世代のランタイム(Java 8)とは異なる側面があります。第 1 世代のランタイムとは異なり、第 2 世代のランタイムでは、アプリログがログ エクスプローラ内のリクエストログの下にグループ化されません。また、第 2 世代ランタイムでは、App Engine がリクエストに関連付けられた各アプリログを個別のログエントリとして Cloud Logging に書き込みます。
このガイドでは、第 1 世代のランタイム アプリと同じロギング メソッドを実装し、アプリを Java 11 以降に移行する際に、ほぼ同じフィルタリングとロギングの相関結果を得る方法について説明します。
主な違い
次の表に、第 1 世代のランタイムと第 2 世代のランタイムのロギングの違いを示します。
第 1 世代ランタイム(Java 8) | 第 2 世代のランタイム(Java 11 以降) | |
---|---|---|
リクエストログとアプリログ(アプリケーション ログとも呼ばれます) | App Engine では、リクエストログ内にすべてのアプリログが埋め込まれています。 | App Engine では、リクエストログ内にアプリログが埋め込まれることはありません。 |
stdout と stderr |
App Engine は、stdout と stderr に書き込まれたログをリクエストログ内に埋め込みます。 |
App Engine では、stdout と stderr に書き込まれたログは埋め込まれません。 |
App Engine プラットフォームのログ | App Engine は内部プラットフォーム ログを出力しません。 | App Engine は、ログ名が /var/log/google_init.log のインスタンスの起動時またはシャットダウン中に内部プラットフォーム ログを出力します。 |
Cloud Logging API の割り当て | 各リクエストは、1 つの Cloud Logging の書き込みに対応します。 | リクエストに関連付けられた各アプリのログエントリは、1 つの Cloud Logging の書き込みに対応します。第 2 世代のランタイムでは、Cloud Logging API の使用量が増加します。 |
ログとアプリログをリクエストする
第 1 世代のランタイムと第 2 世代のランタイムのロギング動作は、次のように異なります。
第 1 世代のランタイムでは、App Engine はアプリログをリクエストログの
protoPayload.line
フィールドに埋め込みます。アプリログを表示するには、ログ エクスプローラでリクエストを開きます。次の図は、第 1 世代のランタイムのログを示しています。リクエストログとアプリログが関連付けられています。
第 2 世代のランタイムでは、リクエストログに
protoPayload.line
フィールドが存在しないため、リクエストログにアプリログ エントリは含まれません。代わりに、App Engine は各アプリログを別々のエントリとして記録します。ログ名は、ロギング設定によって異なります。var/log/app
には、java.util.logging
や Simple Logging Facade for Java(SLF4J)などの標準的なロギング フレームワークを使用して出力されたログが含まれています。stderr
ログとstdout
ログには、System.err.print()
またはSystem.out.print()
を使用して記録されたアプリログが含まれます。次の図は、第 2 世代のランタイムのログを示しています。リクエストログとアプリログは個別に表示されています。
stdout
と stderr
第 1 世代のランタイムでは、App Engine は stdout
と stderr
に出力されたログをアプリログと見なし、これらのアプリログ エントリを関連するリクエストログの下に自動的にグループ化します。
第 2 世代のランタイムでは、App Engine はデフォルトで stdout
と stderr
に出力されたログを関連付けません。stdout
と stderr
を使用してアプリログ エンティティをリクエストログとグループ化するには、stdout
と stderr
に構造化ログを書き込むの手順を行います。
特定の App Engine プラットフォーム ログ(JVM、Jetty、内部インフラストラクチャ ログ)も stderr
に出力されるため、stdout
と stderr
へのロギングはおすすめしません。アプリログとプラットフォーム ログは stderr
ログ名で一緒に表示されるため、曖昧さが生じます。App Engine はプラットフォーム ログの量が多いため、第 2 世代ランタイムではこれが誇張されます。
App Engine プラットフォームのログ
第 1 世代ランタイムでは、App Engine はプラットフォーム ログは出力されません。
第 2 世代のランタイムでは、App Engine はインスタンスの起動時またはシャットダウン中にプラットフォーム ログを /var/log/google_init.log
という名前で出力します。
プラットフォームのログは無視して構いません。これらのログが表示されないようにするには、クエリ logName="/var/log/google_init.log"
を使用してログ エクスプローラにフィルタを追加します。
次の画像は、第 2 世代ランタイムでのプラットフォームのログを示しています。
Cloud Logging API の割り当て
第 1 世代のランタイムでは、App Engine はリクエストの実行中に発行されたすべてのアプリログを 1 つのリクエストログに埋め込み、その埋め込まれたリクエストを Cloud Logging に送信します。各リクエストは、1 つの Cloud Logging の書き込みに対応します。
第 2 世代のランタイムでは、App Engine は各アプリログを個別のログエントリで Cloud Logging に送信するため、リクエストあたりの Cloud Logging 書き込みの合計数が増加します。
Google Cloud は、Cloud Logging が使用する全体のストレージに基づいて課金を行います。ログに必要なストレージ全体が大幅に増加しなくても、App Engine がリクエストごとに書き込むアプリログの数によっては、1 分あたりの書き込み量は増加します。アプリが Cloud Logging の書き込み割り当てを超えた場合は、使用量割り当ての増加をリクエストできます。
詳細については、Cloud Logging の料金をご覧ください。
移行プロセスの概要
第 2 世代のランタイムのリクエストログにアプリログが埋め込まれていない場合でも、第 1 世代アプリと同様にログ表示エクスペリエンスは保持できます。
第 2 世代ランタイムでロギングを設定するには、次のいずれかのオプションを選択できます。
java.util.logging
(JUL)パッケージを使用する: App Engine には、リクエストとアプリログをトレース ID と関連付けるサポートが組み込まれています。トレース ID がアプリログに存在する場合は、ログ エクスプローラでリクエストログ内にグループ化されたアプリログが表示されます。Simple Logging Facade for Java(SLF4J)を使用する: アプリで使用する次のロギング バックエンドに応じて、ソースコードを変更してトレース ID を追加する必要があります。
java.util.logging
(JUL)パッケージを使用する
第 1 世代ランタイムを使用するアプリですべてのロギング要件に対して java.util.logging
パッケージを実装している場合、第 2 世代ランタイムへの移行でコードを変更する必要はありません。
次のサンプルは、第 2 世代ランタイムのロギングに java.util.logging
パッケージを使用する方法を示しています。
package com.example.appengine.my_app;
import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.util.logging.Logger;
@WebServlet(name = "HelloAppEngine", value = "/")
public class HelloAppEngine extends HttpServlet {
// Use the java.util.logging.Logger to log messages
private static final Logger logger = Logger.getLogger(HelloAppEngine.class.getName());
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// Sample log messages
logger.info("Info message");
logger.warning("Warning message");
logger.severe("Severe message");
response.setContentType("text/plain");
response.getWriter().println("Hello App Engine");
}
}
リクエストログでアプリログをグループ化する
第 2 世代ランタイムでは、リクエストログの protoPayload.line
フィールドにアプリログは含まれません。ログ エクスプローラでは、trace
フィールドを使用してリクエストログとアプリログをグループ化します。java.util.logging
パッケージは、すべてのリクエストログとアプリログにトレース ID を自動的に追加します。ログ エクスプローラで相関ログを表示するには、相関ログを表示するをご覧ください。
Simple Logging Facade for Java(SLF4J)を使用する
SLF4J は、Java アプリケーションで使用される最も一般的なロギング インターフェースです。ファサードである SLF4J インターフェースは、ロギング バックエンドのプラットフォームに依存しないため、アプリに適したバックエンドを選択できます。
次の図は、java.util.logging
ライブラリと Logback アペンダーを含む 2 つの SLF4J バックエンドのインテグレーションのオプションを示しています。
java.util.logging
パッケージを含む SLF4J
SLF4J では、ロギング バックエンドとして java.util.logging
を含む SLF4J を使用すると、アプリを Cloud Logging と統合できます。デフォルトでは、App Engine はすべてのリクエストログとアプリログにトレース ID を追加します。このメカニズムにより、ログ エクスプローラでリクエストログとアプリログをグループ化できます。
java.util.logging
を含む SLF4J を実装する手順は次のとおりです。
slf4j-jdk14.jar
依存関係をpom.xml
ファイルに追加します。slf4j-jdk14.jar
ファイルは、java.util.logging
ライブラリのバックエンドのインテグレーションを提供します。<!-- SLF4J interface --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.4</version> </dependency> <!-- JUL implementation for SLF4J --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>2.0.9</version> </dependency>
WEB-INF/logging.properties
ファイルを作成してカスタム構成を追加します。com.example.appengine.java8.HelloAppEngine.level = INFO
appengine-web.xml
ファイルを更新して、WEB-INF/logging.properties
に<property>
値を含めます。<system-properties> <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/> </system-properties>
次の画像は、java.util.logging
を含む SLF4J が、トレース ID をアプリログに自動的に追加する方法を示しています。
ログ エクスプローラ ビューを第 1 世代のランタイムのようなリクエスト中心のビューにチューニングするには、相関ログを表示するをご覧ください。
Logback アペンダーを含む SLF4J を使用する
第 1 世代のランタイム アプリで、Logback を含む SLF4J の組み込み実装を使用している場合は、ソースコードを更新し、リクエストとアプリログをグループ化するための追加の手順を実装する必要があります。
アプリを Cloud Logging と統合する手順は次のとおりです。
google-cloud-logging-logback
アペンダーをpom.xml
ファイルに追加して、Logback のロギング アペンダーをインストールします。<!-- SLF4J interface --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.4</version> </dependency> <!-- Logback JARs --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.3.6</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.3.5</version> </dependency> <!-- Google Cloud logging appender for Logback --> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-logging-logback</artifactId> </dependency>
各
LogEntry
フィールドにトレース ID を追加するロギング エンハンサーを作成します。次のTraceIdLoggingEnhancer
クラスは、ApiProxy API を使用して、リクエストに関連付けられたトレース ID を取得します。import com.google.appengine.api.utils.SystemProperty; import com.google.cloud.logging.LogEntry; import com.google.cloud.logging.LoggingEnhancer; import com.google.apphosting.api.ApiProxy; import com.google.apphosting.api.ApiProxy.Environment; // Add trace ID to the log entry public class TraceIdLoggingEnhancer implements LoggingEnhancer { @Override public void enhanceLogEntry(LogEntry.Builder logEntry) { final String PROJECT_ID = SystemProperty.applicationId.get(); Environment environment = ApiProxy.getCurrentEnvironment(); if (environment instanceof ApiProxy.EnvironmentWithTrace) { ApiProxy.EnvironmentWithTrace environmentWithTrace = (ApiProxy.EnvironmentWithTrace) environment; environmentWithTrace .getTraceId() .ifPresent( id -> logEntry.setTrace(String.format("projects/%s/traces/%s", PROJECT_ID, id))); } } } // [END logging_enhancer]
logback.xml
ファイルに Cloud Logging アペンダーの構成を追加して、Logback を構成します。Logback フレームワークは、WEB-INF/classes
のlogback.xml
ファイルを介して構成を管理します。<configuration> <appender name="CLOUD" class="com.google.cloud.logging.logback.LoggingAppender"> <!-- This should be set to the new Logging Enhancer in the app code. --> <enhancer>com.example.appengine.my_app.enhancers.TraceIdLoggingEnhancer</enhancer> <resourceType>gae_app</resourceType> </appender> <root level="info"> <appender-ref ref="CLOUD" /> </root> </configuration>
次の図は、最終的なアプリ ディレクトリの構造を示しています。
相関ログを表示する
各ログエントリのトレース ID フィールドを使用して、ログ エクスプローラで相関ログを表示できます。ログ エクスプローラで相関ログを表示するには:
Google Cloud コンソールのナビゲーション パネルで、[ロギング] を選択してから、[ログ エクスプローラ] を選択します。
[リソースの種類] で [GAE アプリケーション] を選択します。
リクエストログを表示して関連付けるには、[ログ名] で [request_log] を選択します。また、リクエストログで関連付けるには、[関連付け] をクリックして [request_log] を選択します。
[クエリ結果] ペインで、ログエントリを開くには、[開く] をクリックします。エントリを開くと、各リクエストログに関連付けられたアプリログが表示されます。