このドキュメントでは、Java 用 Cloud クライアント ライブラリのロギングと一般的な問題のトラブルシューティングの概要について説明します。
ロギング
クライアント ライブラリのロギングを有効にするには、java.util.logging を使用する方法と、SLF4J でクライアント ライブラリのデバッグ ロギングを使用する方法の 2 つがあります。
java.util.logging を使用する
Java 用 Cloud クライアント ライブラリは、Java Logging API(java.util.logging)パッケージを使用します。ロギングレベルを構成すると、トラブルシューティングに役立つ次の情報が表示されます。
- 基盤となるクライアント / サーバー通信のタイミング。
- リクエスト メッセージとレスポンス メッセージのヘッダー。
- 基盤となる依存関係ライブラリの詳細メッセージ。
Java 用 Cloud クライアント ライブラリの詳細ロギングをすばやく有効にするには、次の内容で logging.properties ファイルを作成します。
# run java program pointing to this properties file with the java arg
# -Djava.util.logging.config.file=path/to/logging.properties
handlers=java.util.logging.ConsoleHandler
java.util.logging.SimpleFormatter.format=%1$tF %1$tT,%1$tL %4$-8s %3$-50s - %5$s %6$s%n
# --- ConsoleHandler ---
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
.level=INFO
# --- Specify logging level for certain packages ---
# com.google.api is for HTTP 1.1 layer
com.google.api.level=ALL
# io.grpc is for gRPC + Netty layer
io.grpc.level=FINE
# com.google.auth is for authentication
com.google.auth.level=FINE
# Example when you specify the storage library's level. This works when
# the target Cloud library uses the logging API.
com.google.cloud.storage.level=INFO
次に、Program argument ではなく VM argument として -Djava.util.logging.config.file=path/to/logging.properties を指定して、アプリケーションを実行します。
IntelliJ を使用する場合は、[実行/デバッグ構成] で VM 引数を指定します。

プログラムの JVM が構成どおりに実行されている場合は、コンソールに FINE レベルのロギングが表示されます。
出力例:
2023-04-05 13:03:01,761 FINE com.google.auth.oauth2.DefaultCredentialsProvider - Attempting to load credentials from well known file: /usr/local/google/home/suztomo/.config/gcloud/application_default_credentials.json
2023-04-05 13:03:01,847 FINE io.grpc.ManagedChannelRegistry - Unable to find OkHttpChannelProvider
java.lang.ClassNotFoundException: io.grpc.okhttp.OkHttpChannelProvider
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
...
これは、ロギングレベルを構成する方法の一つです。Java Logging API の使用方法について詳しくは、Java Logging の概要をご覧ください。
クライアント ライブラリのデバッグ ロギング(SLF4J)
Cloud クライアント ライブラリには、アプリケーションと API の統合のトラブルシューティングに役立つオプトインのデバッグ ロギングが用意されています。 ロギングが有効になると、リクエストやレスポンスなどの主要なイベントが、データ ペイロードやヘッダーなどのメタデータとともに、標準エラー ストリームに記録されます。
警告: クライアント ライブラリのデバッグ ロギングには、平文のデータ ペイロードが含まれます。これには、自分や顧客の個人情報(PII)、秘密鍵、漏洩すると侵害される可能性のあるその他のセキュリティ データなどの機密データが含まれる可能性があります。アプリケーション ログでは常に適切なデータの整備を実践し、最小権限の原則に従ってください。また、Google では、クライアント ライブラリのデバッグ ロギングは、アクティブなデバッグ中にのみ一時的に有効にし、本番環境では永続的に使用しないことをおすすめします。
前提条件
このライブラリは、SLF4J インターフェースを使用したデバッグ ロギングをサポートしています。
クライアント ライブラリと ライブラリ BOM には、slf4j-api の依存関係は含まれていません。 クライアント ライブラリのデバッグ ロギングを有効にする前に、SLF4J や対応するロギングの実装と構成など、ロギングの依存関係を設定する必要があります。
NOTE: クライアント ライブラリの デバッグ ロギング機能を使用するには、SLF4J と対応するロギング プロバイダ( logback、log4j2 など)がクラスパスに必要です。そうしないと、 環境変数を使用して有効にしてもデバッグ ロギングは行われません。
環境変数を使用してロギングを有効にする
デフォルトでは、デバッグ ロギングはオフになっています。 前提条件を満たしていても、明示的に有効にしない限り、デバッグ ロギングは有効になりません。
クライアント ライブラリのデバッグ ロギングを有効にするには、環境変数 GOOGLE_SDK_JAVA_LOGGING を true(大文字と小文字を区別しない)に設定します。
設定されていない場合や他の値の場合、クライアント ライブラリのデバッグ ロギングは無効になります。
ロギングの設定例
ドキュメントでは、Logback を使用したデバッグ ロギングの例を示しています。
Logback の依存関係をアプリケーションに追加すると、slf4j の依存関係が推移的に取り込まれます。 最新バージョンについては、Logback の設定 をご覧ください。 アプリケーションのクラスパスに logback の依存関係がすでにある場合は、この手順を省略できます。
Maven を使用している場合:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>LATEST_VERSION</version>
</dependency>
DEBUG レベルのログを表示する場合は、logback 構成ファイルにコンテンツを追加します。 INFO レベルのログのみが必要な場合は、この手順をスキップできます。詳細については、Logback の構成 をご覧ください。
<!-- set Client Library log level to DEBUG -->
<logger name="com.google.api" level="DEBUG"/>
<!-- set Auth Library log level to DEBUG -->
<logger name="com.google.auth" level="DEBUG"/>
ALPN が正しく構成されていない
ALPN is not configured properly に関連する例外が表示される場合は、次のようにします。
Caused by: java.lang.IllegalArgumentException: ALPN is not configured properly. See https://github.com/grpc/grpc-java/blob/master/SECURITY.md#troubleshooting for more information.
互換性チェッカーを使用して、環境が gRPC ベースのクライアントと互換性があるかどうかを確認します。
非互換性とは、次のいずれかを意味します。
- サポートされているプラットフォームを使用していない。
- クラスパスで
nettyとの競合がある。 - gRPC のトラブルシューティング ガイドで指定されている競合が発生している。
ClassNotFoundException、NoSuchMethodError、NoClassDefFoundError のトラブルシューティング
これらのエラーは、クラスパスに同じ依存関係の複数のバージョンまたは競合するバージョンが存在することが原因で発生することがよくあります。これらの依存関係の競合は、guava または protobuf-java で発生することがよくあります。
クラスパスの競合は、次の複数のソースが原因で発生する可能性があります。
- 依存関係ツリーに同じ推移的依存関係の複数のバージョンがある。
- ランタイム クラスパスの依存関係のバージョンが、ビルドで指定したバージョンと異なる。
たとえば、Guava バージョン 19.0 に直接的または推移的な依存関係があり、google-cloud-java が Guava バージョン 30.0 を使用している場合、google-cloud-java は Guava 19.0 に存在しない Guava メソッドを使用し、NoSuchMethodError が発生する可能性があります。
同様に、クラスパスに古いバージョンの protobuf-java があり、google-cloud-java で新しいバージョンが必要な場合は、google-cloud-java クラスの初期化に失敗する NoClassDefFoundError が表示されることがあります。
次に例を示します。
java.lang.NoClassDefFoundError: Could not initialize class com.google.pubsub.v1.PubsubMessage$AttributesDefaultEntryHolder
競合を検証する
依存関係ツリーを確認して、同じ依存関係の複数のバージョンがあるかどうかを確認します。
$ mvn dependency:tree
guava や protobuf-java など、競合する可能性のある依存関係のバージョンを探します。
ランタイムでのみエラーが発生する場合は、ランタイム環境で競合する JAR がランタイム クラスパスに導入されている可能性があります。一般的なケースとして、アプリケーションが実行される Hadoop、Spark、その他のサーバー ソフトウェアのクラスパスに、競合するバージョンの netty、