Dieses Dokument bietet einen Überblick über das Logging und die Fehlerbehebung bei häufigen Problemen mit Cloud-Clientbibliotheken für Java.
Logging
Es gibt zwei Möglichkeiten, das Logging für die Clientbibliotheken zu aktivieren: mit java.util.logging oder mit Client Library Debug Logging mit SLF4J.
java.util.logging verwenden
Die Cloud-Clientbibliotheken für Java verwenden das Java-Logging-API-Paket (java.util.logging). Wenn Sie die Protokollierungsebene konfigurieren, werden Informationen angezeigt, die Ihnen bei der Fehlerbehebung helfen, z. B.:
- Timing der zugrunde liegenden Client-Server-Kommunikation.
- Anfrage- und Antwortnachrichtenheader.
- Ausführliche Meldungen in zugrunde liegenden Abhängigkeitsbibliotheken.
Wenn Sie die ausführliche Protokollierung für Cloud-Clientbibliotheken für Java schnell aktivieren möchten, erstellen Sie eine Datei logging.properties mit folgendem Inhalt:
# 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
Führen Sie als Nächstes Ihre Anwendung mit -Djava.util.logging.config.file=path/to/logging.properties als VM argument und nicht als Program argument aus.
Wenn Sie IntelliJ verwenden, geben Sie das VM-Argument in Run/Debug Configuration (Konfiguration für Ausführung/Debugging) an:

Wenn die JVM Ihres Programms mit der Konfiguration korrekt ausgeführt wird, sehen Sie die Protokollierung auf FINE-Ebene in Ihrer Konsole.
Beispielausgabe:
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)
...
Das ist eine Möglichkeit, die Logging-Ebene zu konfigurieren. Weitere Informationen zur Verwendung der Java Logging API finden Sie unter Java Logging – Übersicht.
Debug-Logging der Clientbibliothek (SLF4J)
Cloud-Clientbibliotheken bieten optionales Debug-Logging, das Ihnen bei der Fehlerbehebung bei der Integration Ihrer Anwendung in die API helfen kann. Wenn die Protokollierung aktiviert ist, werden wichtige Ereignisse wie Anfragen und Antworten zusammen mit Daten-Payloads und Metadaten wie Headern in den Standardfehlerstream protokolliert.
ACHTUNG:Das Debug-Logging der Clientbibliothek umfasst Ihre Daten-Payloads im Klartext, die vertrauliche Daten wie personenidentifizierbare Informationen (PII) für Sie oder Ihre Kunden, private Schlüssel oder andere Sicherheitsdaten enthalten können, die bei einem Datenleck gefährdet wären. Achten Sie immer auf eine gute Datenhygiene bei Ihren Anwendungslogs und befolgen Sie den Grundsatz des geringstmöglichen Zugriffs. Google empfiehlt außerdem, das Debug-Logging der Clientbibliothek nur vorübergehend während des aktiven Debuggings zu aktivieren und nicht dauerhaft in der Produktion zu verwenden.
Voraussetzungen
Unsere Bibliotheken unterstützen das Debug-Logging über die SLF4J-Schnittstelle.
Die slf4j-api-Abhängigkeit ist nicht in Clientbibliotheken und Libraries BOM enthalten. Sie müssen Protokollierungsabhängigkeiten wie SLF4J und entsprechende Protokollierungsimplementierungen und -konfigurationen einrichten, bevor Sie das Debug-Logging der Clientbibliothek aktivieren.
NOTE: Sie benötigen SLF4J und entsprechende Logging-Anbieter wie Logback oder Log4j2 in Ihrem Klassenpfad, um die Debug-Logging-Funktion der Clientbibliothek zu verwenden. Andernfalls erfolgt kein Debug-Logging, auch wenn Sie es über die Umgebungsvariable aktivieren.
Logging mit einer Umgebungsvariablen aktivieren
Das Debug-Logging ist standardmäßig deaktiviert. Die Debug-Protokollierung wird nicht automatisch aktiviert, auch wenn die Voraussetzungen erfüllt sind.
Sie können das Debug-Logging der Clientbibliothek aktivieren, indem Sie die Umgebungsvariable GOOGLE_SDK_JAVA_LOGGING auf true festlegen. Die Groß-/Kleinschreibung spielt dabei keine Rolle.
Wenn der Wert nicht festgelegt ist oder einen anderen Wert hat, ist das Debug-Logging der Clientbibliothek deaktiviert.
Beispiele für Logging-Konfigurationen
Die Dokumentation enthält ein Beispiel für das Debug-Logging mit Logback.
Fügen Sie Ihrer Anwendung Logback-Abhängigkeiten hinzu. Dadurch wird die slf4j-Abhängigkeit transitiv eingefügt. Die neuesten Versionen finden Sie in der Logback-Einrichtung. Sie können diesen Schritt überspringen, wenn Ihre Anwendung bereits Logback-Abhängigkeiten im Klassenpfad hat.
Wenn Sie Maven verwenden:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>LATEST_VERSION</version>
</dependency>
Fügen Sie den Inhalt der Logback-Konfigurationsdatei hinzu, wenn Sie Logs auf DEBUG-Ebene sehen möchten. Sie können diesen Schritt überspringen, wenn Sie nur Protokolle auf INFO-Ebene benötigen. Weitere Informationen finden Sie unter Logback-Konfiguration.
<!-- 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 ist nicht richtig konfiguriert
Wenn Sie Ausnahmen im Zusammenhang mit ALPN is not configured properly sehen, z. B.:
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.
Mit dem Kompatibilitätscheck können Sie herausfinden, ob Ihre Umgebung mit gRPC-basierten Clients kompatibel ist.
Inkompatibilität kann eines der folgenden Dinge bedeuten:
- Sie verwenden keine unterstützte Plattform.
- Es gibt Classpath-Konflikte mit
netty. - Einer der im gRPC-Leitfaden zur Fehlerbehebung angegebenen Konflikte wird angezeigt.
Fehlerbehebung bei ClassNotFoundException, NoSuchMethodError und NoClassDefFoundError
Diese Fehler werden häufig dadurch verursacht, dass sich mehrere Versionen oder inkompatible Versionen derselben Abhängigkeit im Klassenpfad befinden. Diese Abhängigkeitskonflikte treten häufig bei guava oder protobuf-java auf.
Mehrere Quellen können zu Classpath-Konflikten führen:
- Mehrere Versionen derselben transitiven Abhängigkeit im Abhängigkeitsbaum.
- Ihr Laufzeit-Classpath enthält andere Versionen von Abhängigkeiten als die, die Sie im Build angegeben haben.
Wenn Sie beispielsweise eine direkte oder transitive Abhängigkeit von Guava-Version 19.0 haben und google-cloud-java Guava-Version 30.0 verwendet, verwendet google-cloud-java möglicherweise Guava-Methoden, die in Guava 19.0 nicht vorhanden sind, und verursacht NoSuchMethodError.
Wenn Ihr Klassenpfad eine ältere Version von protobuf-java enthält, google-cloud-java jedoch eine neuere Version erfordert, wird möglicherweise NoClassDefFoundError angezeigt, das die Initialisierung von google-cloud-java-Klassen verhindert.
Beispiel:
java.lang.NoClassDefFoundError: Could not initialize class com.google.pubsub.v1.PubsubMessage$AttributesDefaultEntryHolder
Konflikt validieren
Prüfen Sie die Abhängigkeitsstruktur, um festzustellen, ob Sie mehrere Versionen derselben Abhängigkeiten haben:
$ mvn dependency:tree
Suchen Sie nach Versionen potenziell in Konflikt stehender Abhängigkeiten wie guava oder protobuf-java.
Wenn der Fehler nur zur Laufzeit auftritt, enthält Ihr Laufzeit-Classpath möglicherweise inkompatible JARs. Ein typischer Fall ist, dass Hadoop, Spark oder andere Serversoftware, auf der Ihre Anwendung ausgeführt wird, in den JARs netty, guava oder protobuf-java im Klassenpfad inkompatible Versionen hat.
Konflikte während des Builds erkennen
Um Fehler bei der Verknüpfung von Abhängigkeiten zur Kompilierzeit zu erkennen, fügen Sie die Linkage Checker Enforcer Rule in Ihre pom.xml ein:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version>
<dependencies>
<dependency>
<groupId>com.google.cloud.tools</groupId>
<artifactId>linkage-checker-enforcer-rules</artifactId>
<version>1.5.7</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>enforce-linkage-checker</id>
<!-- Important! Should run after compile -->
<phase>verify</phase>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<LinkageCheckerRule
implementation="com.google.cloud.tools.dependencies.enforcer.LinkageCheckerRule"/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
Laufzeit-Classpath-Konflikte können jedoch nicht erkannt werden. Sie müssen genau wissen, welche JARs/Klassen im Laufzeit-Classpath enthalten sind, da jede Serverumgebung anders ist.
Konflikt lösen
Es gibt verschiedene Strategien zur Behebung von Konflikten. Sie müssen jedoch die Ursache der Konflikte kennen:
- Wenn Sie den Abhängigkeitsbaum steuern, führen Sie ein Upgrade der in Konflikt stehenden Abhängigkeiten durch (z. B. ein Upgrade von Guava). Dieser Ansatz ist der robusteste, kann aber einen erheblichen Aufwand und mehrere Bibliotheksreleases erfordern, um die Kompatibilität zu gewährleisten.
- Wenn Sie keine neuen Versionen Ihrer Abhängigkeiten ändern und pushen können, importieren Sie
com.google.cloud:libraries-bom:25.1.0(oder eine neuere Version), um konsistente Abhängigkeitsversionen auszuwählen. Dieser Ansatz vereinfacht die Verwaltung von Abhängigkeiten. So können Sie beispielsweise von konsistenten Versionen von Guava undcom.google.cloud:google-cloud-storageabhängig sein, ohne die Versionen explizit festzulegen:
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>25.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
...
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-storage</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
...
</dependencies>
...
In den Versionshinweisen zur Bibliotheks-BOM sind die kompatiblen Abhängigkeitsbibliotheken aufgeführt. Beispiel: https://github.com/googleapis/java-cloud-bom/releases/tag/v26.31.0 zeigt Folgendes:
These client libraries are built with the following Java libraries: - Guava: 32.1.3-jre - Protobuf Java: 3.25.2 - Google Auth Library: 1.22.0 - Google API Client: 2.2.0 - gRPC: 1.61.0 - GAX: 2.41.0 - Google Cloud Core: 2.31.0Wenn Sie das Abhängigkeitsdiagramm Ihres Projekts (
mvn dependency:tree -Dverbose,gradle dependenciesodersbt dependencyTree) untersuchen, stellen Sie möglicherweise fest, dass einige Abhängigkeiten unerwartete Versionen haben, was zu Abhängigkeitskonflikten führen kann.Wenn durch das Ändern von Abhängigkeitsversionen andere Fehler auftreten, sollten Sie Abhängigkeiten verschleiern, die mit Google Cloud Java-Bibliotheken in Konflikt stehen.
So schattieren Sie beispielsweise
guavaundprotobuf-java:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>...</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope> <relocations> <!-- move protobuf to a shaded package --> <relocation> <pattern>com.google.protobuf</pattern> <shadedPattern>myapp.shaded.com.google.protobuf</shadedPattern> </relocation> <!-- move Guava to a shaded package --> <relocation> <pattern>com.google.common</pattern> <shadedPattern>myapp.shaded.com.google.common</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin>