Dieses Dokument bietet einen Überblick über das Logging und die Behebung häufiger Probleme 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.:
- Zeitpunkt 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 richtigen Konfiguration 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 Protokollierungsebene zu konfigurieren. Weitere Informationen zur Verwendung der Java Logging API finden Sie unter Java Logging Overview.
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 sensible Daten wie personenidentifizierbare Informationen für Sie oder Ihre Kunden, private Schlüssel oder andere Sicherheitsdaten enthalten können, die bei einem Datenleck gefährdet sein könnten. Achten Sie immer auf eine gute Datenhygiene bei Ihren Anwendungslogs und befolgen Sie das Prinzip der geringsten Berechtigung. 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 Bibliotheken-BOM enthalten. Bevor Sie das Debug-Logging der Clientbibliothek aktivieren, müssen Sie Logging-Abhängigkeiten wie SLF4J und entsprechende Logging-Implementierungen und -Konfigurationen einrichten.
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. Das Debug-Logging ist nicht aktiviert, sofern es nicht explizit aktiviert wird, auch wenn die Voraussetzungen erfüllt sind.
Sie können das Debug-Logging für Clientbibliotheken 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 ein anderer Wert angegeben wird, ist das Debug-Logging der Clientbibliothek deaktiviert.
Beispiele für Logging-Einrichtungen
Die Dokumentation enthält ein Beispiel für die Fehlerbehebungsprotokollierung mit Logback.
Fügen Sie Ihrer Anwendung Logback-Abhängigkeiten hinzu. Dadurch wird die slf4j-Abhängigkeit transitiv eingefügt. Nutzer sollten in der Logback-Einrichtung nach den neuesten Versionen suchen. 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 Logs 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. - Sie sehen einen der im gRPC-Leitfaden zur Fehlerbehebung angegebenen Konflikte.
Fehlerbehebung bei ClassNotFoundException, NoSuchMethodError und NoClassDefFoundError
Diese Fehler werden häufig dadurch verursacht, dass mehrere Versionen oder inkompatible Versionen derselben Abhängigkeit im Klassenpfad vorhanden sind. 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 im Abhängigkeitsbaum, 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 Ihre Laufzeitumgebung möglicherweise in Konflikt stehende JARs in Ihrem Laufzeit-Classpath. Ein typischer Fall ist, dass Hadoop, Spark oder andere Serversoftware, auf der Ihre Anwendung ausgeführt wird, in den Klassenpfad JARs mit den Versionen netty, guava oder protobuf-java enthält.
Konflikte während des Builds erkennen
Wenn Sie Fehler bei der Verknüpfung von Abhängigkeiten zur Kompilierzeit erkennen möchten, 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>
Es gibt jedoch keine Möglichkeit, Konflikte im Laufzeit-Klassenpfad zu erkennen. Sie müssen genau wissen, welche JARs/Klassen im Laufzeit-Classpath enthalten sind, da jede Serverumgebung anders ist.
Konflikt beheben
Es gibt verschiedene Strategien zur Konfliktlösung. 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 viel Aufwand und mehrere Bibliotheksversionen erfordern, um die Kompatibilität zu gewährleisten.
- Wenn Sie Ihre Abhängigkeiten nicht ändern und neue Versionen 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 Abhängigkeitsverwaltung. 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 für „libraries-bom“ werden 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 Cloud de Confiance by S3NS 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>