Esegui la migrazione del logging a runtime Java di seconda generazione

Alcuni aspetti del logging nei runtime di seconda generazione (Java 11 e versioni successive) sono diversi dal runtime di prima generazione (Java 8). A differenza del runtime di prima generazione, nei runtime di seconda generazione i log delle app non vengono raggruppati nei log delle richieste all'interno di Esplora log. Inoltre, nei runtime di seconda generazione, App Engine scrive ogni log dell'app associato a una richiesta come voce di log separata in Cloud Logging.

Questa guida descrive come implementare gli stessi metodi di logging utilizzati nelle app di runtime di prima generazione e ottenere quasi gli stessi risultati di correlazione tra filtri e log durante la migrazione dell'app a Java 11 e versioni successive.

Differenze principali

La seguente tabella illustra le differenze nel logging tra runtime di prima e seconda generazione:

runtime di prima generazione (Java 8) Runtime di seconda generazione (Java 11 e versioni successive)
Log delle richieste e delle app (chiamati anche log delle applicazioni) App Engine incorpora tutti i log delle app nel log delle richieste. App Engine non incorpora i log delle app nel log delle richieste.
stdout e stderr App Engine incorpora i log scritti in stdout e stderr nel log delle richieste. App Engine non incorpora i log scritti in stdout e stderr.
Log della piattaforma App Engine App Engine non emette log interni della piattaforma. App Engine emette log interni della piattaforma durante l'avvio o l'arresto di un'istanza con nome log /var/log/google_init.log.
Quota API Cloud Logging Ogni richiesta corrisponde a una scrittura in Cloud Logging. Ogni voce di log dell'app associata a una richiesta corrisponde a una scrittura di Cloud Logging. L'utilizzo dell'API Cloud Logging è aumentato nei runtime di seconda generazione.

Log delle richieste e log delle app

Il comportamento di logging nei runtime di prima e di seconda generazione varia nei seguenti aspetti:

  • Nel runtime di prima generazione, App Engine incorpora i log delle app nel campo protoPayload.line dei log delle richieste. Puoi visualizzare i log delle app espandendo una richiesta in Esplora log.

    L'immagine seguente mostra i log delle app e delle richieste correlati nel runtime di prima generazione:

    Log correlati in Java 8

  • Nei runtime di seconda generazione, i log delle richieste non contengono voci di log delle app perché il campo protoPayload.line è assente nel log delle richieste. App Engine, invece, registra ogni log dell'app come voce separata. Il nome del log dipende dalla configurazione del logging. var/log/app contiene log emessi utilizzando framework di logging standard come java.util.logging o Simple Logging Facade for Java (SLF4J). I log stderr e stdout contengono log delle app registrati utilizzando System.err.print() o System.out.print().

    L'immagine seguente mostra log di richieste e app separati nei runtime di seconda generazione:

    Log separati in Java 11

stdout e stderr

Nel runtime di prima generazione, App Engine considera i log emessi in stdout e stderr come log delle app e raggruppa automaticamente queste voci di log dell'app nel log delle richieste associato.

Nei runtime di seconda generazione, App Engine non correla i log emessi a stdout e stderr per impostazione predefinita. Per raggruppare le entità dei log dell'app con il log delle richieste utilizzando stdout e stderr, segui le istruzioni riportate in Scrivere log strutturati in stdout e stderr.

Sconsigliamo di eseguire il logging su stdout e stderr poiché alcuni log della piattaforma App Engine (JVM, Jetty, log dell'infrastruttura interna) vengono emessi anche in stderr. I log delle app e della piattaforma vengono visualizzati insieme al nome di log stderr, il che causa ambiguità. Questo aspetto è esagerato nei runtime di seconda generazione poiché App Engine ha un volume maggiore di log della piattaforma.

Log della piattaforma App Engine

Nel runtime di prima generazione, App Engine non emette log della piattaforma.

Nei runtime di seconda generazione, App Engine emette log della piattaforma durante l'avvio o l'arresto dell'istanza con il nome log /var/log/google_init.log.

Puoi ignorare tranquillamente i log della piattaforma. Per evitare di visualizzare questi log, aggiungi un filtro a Esplora log con la query logName="/var/log/google_init.log".

L'immagine seguente mostra i log della piattaforma nei runtime di seconda generazione:

Log della piattaforma

Quota dell'API Cloud Logging

Nel runtime di prima generazione, App Engine incorpora tutti i log delle app emessi durante una richiesta in un unico log delle richieste e invia la richiesta incorporata a Cloud Logging. Ogni richiesta corrisponde a una scrittura in Cloud Logging.

Nei runtime di seconda generazione, App Engine invia ogni log dell'app a Cloud Logging in voci di log separate, causando un aumento del numero totale di scritture di Cloud Logging per richiesta.

Google Cloud determina la fatturazione in base allo spazio di archiviazione complessivo utilizzato da Cloud Logging. Anche se lo spazio di archiviazione complessivo necessario per i log non aumenta in modo significativo, le scritture al minuto aumentano, a seconda del numero di log dell'app scritti da App Engine per richiesta. Se la tua app supera la quota di scrittura di Cloud Logging, puoi richiedere un aumento della quota di utilizzo.

Per ulteriori informazioni, consulta i pricing per Cloud Logging.

Panoramica del processo di migrazione

Anche se i log delle app non sono incorporati nei log delle richieste nei runtime di seconda generazione, è possibile mantenere l'esperienza di visualizzazione dei log come per le app di prima generazione.

Puoi scegliere una delle seguenti opzioni per configurare il logging nei runtime di seconda generazione:

Utilizza il pacchetto java.util.logging (JUL)

Se le tue app che utilizzano il runtime di prima generazione implementano il pacchetto java.util.logging per tutti i requisiti di logging, la migrazione ai runtime di seconda generazione non richiede modifiche al codice.

Il seguente esempio mostra come utilizzare il pacchetto java.util.logging per accedere ai runtime di seconda generazione:

    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");
      }
    }

Raggruppare i log delle app con il log delle richieste

Nei runtime di seconda generazione, il campo protoPayload.line nel log delle richieste non contiene log dell'app. Esplora log utilizza il campo trace per raggruppare i log delle richieste e i log delle app. Il pacchetto java.util.logging aggiunge automaticamente l'ID traccia a tutti i log delle richieste e delle app. Per visualizzare i log correlati in Esplora log, consulta Visualizza i log correlati.

Utilizza Simple Logging Facade per Java (SLF4J)

SLF4J è l'interfaccia di logging più diffusa nelle applicazioni Java. Essendo una facade, l'interfaccia SLF4J è indipendente dalla piattaforma dal suo backend di logging, consentendoti di scegliere qualsiasi backend adatto alle tue app.

L'immagine seguente mostra le opzioni di integrazione per due backend SLF4J, tra cui la libreria java.util.logging e l'appender Logback:

Panoramica di SLF4J

SLF4J con pacchetto java.util.logging

SLF4J consente di integrare la tua app con Cloud Logging quando utilizzi SLF4J con java.util.logging come backend di logging. Per impostazione predefinita, App Engine aggiunge un ID traccia a tutti i log di richieste e app. Questo meccanismo consente di raggruppare i log delle richieste e delle app in Esplora log.

Per implementare SLF4J con java.util.logging:

  1. Aggiungi la dipendenza slf4j-jdk14.jar al file pom.xml. Il file slf4j-jdk14.jar fornisce l'integrazione del backend per la libreria 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>
    
  2. Crea un file WEB-INF/logging.properties per aggiungere configurazioni personalizzate:

    com.example.appengine.java8.HelloAppEngine.level = INFO
    
  3. Aggiorna il file appengine-web.xml in modo da includere il valore <property> per WEB-INF/logging.properties:

    <system-properties>
      <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
    

L'immagine seguente mostra come SLF4J con java.util.logging aggiunge automaticamente l'ID traccia a un log dell'app:

Raggruppa i log dell'app per richiesta con ID traccia

Per ottimizzare la visualizzazione Esplora log in base a una visualizzazione incentrata sulle richieste come il runtime di prima generazione, consulta Visualizzare i log correlati.

Utilizza SLF4J con l'appendice di logback

Se le app di runtime di prima generazione utilizzano l'implementazione integrata di SLF4J con Logback, devi aggiornare il codice sorgente e implementare passaggi aggiuntivi per raggruppare i log delle richieste e delle app.

Per integrare la tua app con Cloud Logging, segui questi passaggi:

  1. Aggiungi l'appender google-cloud-logging-logback al file pom.xml per installare l'appendice di logging per 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>
    
  2. Crea uno strumento di miglioramento dei log per aggiungere un ID traccia a ogni campo LogEntry. La seguente classe TraceIdLoggingEnhancer utilizza l'API ApiProxy per recuperare l'ID traccia associato a una richiesta:

      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]
    
  3. Aggiungi la configurazione dell'appendice Cloud Logging nel file logback.xml per configurare il logback. Il framework di logback gestisce la configurazione tramite il file logback.xml in WEB-INF/classes:

    <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>
    

    L'immagine seguente mostra la struttura finale della directory dell'app:

    Struttura delle directory

Visualizza log correlati

Puoi visualizzare i log correlati in Esplora log utilizzando il campo ID traccia in ogni voce di log. Per visualizzare i log correlati in Esplora log:

  1. Nel pannello di navigazione della console Google Cloud, seleziona Logging, quindi Esplora log:

    Vai a Esplora log

  2. In Tipo di risorsa, seleziona Applicazione GAE.

  3. Per visualizzare e correlare i log delle richieste, in Nome log, seleziona request_log. In alternativa, per eseguire la correlazione in base ai log delle richieste, fai clic su Correla per e seleziona request_log:

    Correlazione dei log

  4. Nel riquadro Risultati delle query, per espandere una voce di log, fai clic su Espandi. Al momento dell'espansione, ogni log delle richieste mostrerà i log dell'app associati.