Migrer la journalisation vers des environnements d'exécution Java de deuxième génération

Certains aspects de la journalisation dans les environnements d'exécution de deuxième génération (Java 11+) sont différents par rapport à l'environnement d'exécution de première génération (Java 8). Contrairement à l'environnement d'exécution de première génération, dans les environnements d'exécution de deuxième génération, les journaux d'application ne sont pas regroupés sous les journaux de requêtes dans l'explorateur de journaux. De plus, dans les environnements d'exécution de deuxième génération, App Engine écrit chaque journal d'application associé à une requête en tant qu'entrée de journal distincte dans Cloud Logging.

Ce guide explique comment mettre en œuvre les mêmes méthodes de journalisation que celles utilisées dans vos applications d'environnement d'exécution de première génération, et obtenir pratiquement les mêmes résultats de filtrage et de mise en corrélation des journaux lors de la migration de votre application vers Java 11+.

Différences majeures

Le tableau suivant décrit les différences de journalisation entre les environnements d'exécution de première et de deuxième génération :

Environnement d'exécution de première génération (Java 8) Environnements d'exécution de deuxième génération (Java 11+)
Journaux de requêtes et d'application (également appelés journaux d'application) App Engine intègre tous les journaux d'application dans le journal de requêtes. App Engine n'intègre pas les journaux d'application dans le journal de requêtes.
stdout et stderr App Engine intègre les journaux écrits dans stdout et stderr dans le journal de requêtes. App Engine n'intègre pas les journaux écrits dans stdout et stderr.
Journaux de plate-forme App Engine App Engine n'émet pas de journaux de plate-forme internes. App Engine émet des journaux de plate-forme internes lors du démarrage ou de l'arrêt d'une instance portant le nom de journal /var/log/google_init.log.
Quotas de l'API Cloud Logging Chaque requête correspond à une écriture Cloud Logging. Chaque entrée de journal d'application associée à une requête correspond à une écriture Cloud Logging. L'utilisation de l'API Cloud Logging augmente dans les environnements d'exécution de deuxième génération.

Journaux de requêtes et journaux d'application

Le comportement de journalisation dans les environnements d'exécution de première et de deuxième génération présente les différences suivantes :

  • Dans l'environnement d'exécution de première génération, App Engine intègre les journaux d'application dans le champ protoPayload.line des journaux de requêtes. Vous pouvez afficher les journaux d'application en développant une requête dans l'explorateur de journaux.

    L'image suivante montre les journaux d'application et de requêtes corrélés dans les environnements d'exécution de première génération :

    Journaux corrélés dans Java 8

  • Dans les environnements d'exécution de deuxième génération, les journaux de requêtes ne contiennent pas d'entrées de journal d'application, car le champ protoPayload.line est absent du journal de requêtes. À la place, App Engine enregistre chaque journal d'application en tant qu'entrée distincte. Le nom du journal dépend de votre configuration de journalisation. var/log/app contient les journaux émis à l'aide de frameworks de journalisation standards tels que java.util.logging ou Simple Logging Facade for Java (SLF4J). Les journaux stderr et stdout contiennent des journaux d'application enregistrés à l'aide de System.err.print() ou System.out.print().

    L'image suivante montre des journaux de requêtes et d'application distincts dans les environnements d'exécution de deuxième génération :

    Journaux distincts dans Java 11

stdout et stderr

Dans l'environnement d'exécution de première génération, App Engine considère les journaux émis vers stdout et stderr comme des journaux d'application, et regroupe automatiquement ces entrées de journal d'application sous le journal de requêtes associé.

Dans les environnements d'exécution de deuxième génération, App Engine ne met pas en corrélation les journaux émis dans stdout et stderr par défaut. Pour regrouper des entités de journal d'application avec le journal de requêtes à l'aide de stdout et stderr, suivez les instructions de la section Écrire des journaux structurés dans stdout et stderr.

Nous vous déconseillons la journalisation vers stdout et stderr, car certains journaux de la plate-forme App Engine (JVM, Jetty, journaux d'infrastructure internes) sont également émis dans stderr. Les journaux d'application et de plate-forme apparaissent ensemble avec le nom de journal stderr, ce qui crée une ambiguïté. Cette ambiguïté est d'autant plus grande dans les environnements d'exécution de deuxième génération, car App Engine dispose d'un volume plus élevé de journaux de plate-forme.

Journaux de plate-forme App Engine

Dans l'environnement d'exécution de première génération, App Engine n'émet pas de journaux de plate-forme.

Dans les environnements d'exécution de deuxième génération, App Engine émet des journaux de plate-forme lors du démarrage ou de l'arrêt de l'instance avec le nom de journal /var/log/google_init.log.

Vous pouvez ignorer les journaux de plate-forme en toute sécurité. Pour éviter de voir ces journaux, ajoutez un filtre à l'explorateur de journaux avec la requête logName="/var/log/google_init.log".

L'image suivante montre des journaux de plate-forme dans les environnements d'exécution de deuxième génération :

Journaux de plate-forme

Quotas de l'API Cloud Logging

Dans l'environnement d'exécution de première génération, App Engine intègre tous les journaux d'application émis lors d'une requête dans un journal de requêtes unique et envoie la requête intégrée à Cloud Logging. Chaque requête correspond à une écriture Cloud Logging.

Dans les environnements d'exécution de deuxième génération, App Engine envoie chaque journal d'application à Cloud Logging dans des entrées de journal distinctes, ce qui entraîne une augmentation du nombre total d'écritures Cloud Logging par requête.

Google Cloud détermine la facturation en fonction de l'espace de stockage global utilisé par Cloud Logging. Même si l'espace de stockage global requis pour les journaux n'augmente pas de façon significative, le nombre d'écritures par minute augmente en fonction du nombre de journaux d'application qu'App Engine écrit par requête. Si votre application dépasse le quota d'écritures Cloud Logging, vous pouvez demander une augmentation de votre quota d'utilisation.

Pour en savoir plus, consultez la section Tarifs de Cloud Logging.

Présentation du processus de migration

Même si les journaux d'application ne sont pas intégrés aux journaux de requêtes dans les environnements d'exécution de deuxième génération, il est possible de conserver une expérience d'affichage des journaux semblable aux applications de première génération.

Vous pouvez choisir l'une des options suivantes pour configurer la journalisation dans les environnements d'exécution de deuxième génération :

Utiliser le package java.util.logging (JUL)

Si vos applications utilisant l'environnement d'exécution de première génération mettent en œuvre le package java.util.logging pour répondre à tous les besoins de journalisation, la migration vers des environnements d'exécution de deuxième génération ne nécessite aucune modification du code.

L'exemple suivant montre comment utiliser le package java.util.logging pour la journalisation dans les environnements d'exécution de deuxième génération :

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

Regrouper les journaux d'application avec le journal de requêtes

Dans les environnements d'exécution de deuxième génération, le champ protoPayload.line du journal de requêtes ne contient pas de journaux d'application. L'explorateur de journaux utilise le champ trace pour regrouper les journaux de requêtes et les journaux d'application. Le package java.util.logging ajoute automatiquement l'ID de trace à tous les journaux de requêtes et d'application. Pour afficher les journaux corrélés dans l'explorateur de journaux, consultez la section Afficher les journaux corrélés.

Utiliser Simple Logging Facade for Java (SLF4J)

SLF4J est l'interface de journalisation la plus utilisée dans les applications Java. En tant que façade, l'interface SLF4J est indépendante de la plate-forme de son backend de journalisation, ce qui vous permet de choisir n'importe quel backend adapté à vos applications.

L'image suivante montre les options d'intégration pour deux backends SLF4J incluant la bibliothèque java.util.logging et l'appender Logback :

Présentation de SLF4J

SLF4J avec le package java.util.logging

SLF4J vous permet d'intégrer votre application à Cloud Logging lorsque vous utilisez SLF4J avec java.util.logging comme backend de journalisation. Par défaut, App Engine ajoute un ID de trace à tous les journaux de requêtes et d'application. Ce mécanisme permet de regrouper les journaux de requêtes et d'application dans l'explorateur de journaux.

Pour implémenter SLF4J avec java.util.logging, procédez comme suit :

  1. Ajoutez la dépendance slf4j-jdk14.jar à votre fichier pom.xml. Le fichier slf4j-jdk14.jar fournit l'intégration du backend pour la bibliothèque 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. Créez un fichier WEB-INF/logging.properties pour ajouter des configurations personnalisées :

    com.example.appengine.java8.HelloAppEngine.level = INFO
    
  3. Mettez à jour votre fichier appengine-web.xml pour inclure la valeur <property> pour WEB-INF/logging.properties :

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

L'image suivante montre comment SLF4J avec java.util.logging ajoute automatiquement l'ID de trace à un journal d'application :

Regrouper les journaux d'application par requête avec ID de trace

Pour modifier l'affichage de l'explorateur de journaux afin d'obtenir une vue centrée sur les requêtes comme pour l'environnement d'exécution de première génération, consultez la section Afficher les journaux corrélés.

Utiliser SLF4J avec l'appender Logback

Si vos applications d'environnement d'exécution de première génération utilisent l'implémentation intégrée de SLF4J avec Logback, vous devez mettre à jour votre code source et mettre en place des étapes supplémentaires pour regrouper les journaux de requêtes et d'application.

Pour intégrer votre application à Cloud Logging, procédez comme suit :

  1. Ajoutez l'appender google-cloud-logging-logback au fichier pom.xml afin d'installer l'appender de journalisation pour 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. Créez un outil d'amélioration de la journalisation pour ajouter un ID de trace à chaque champ LogEntry. La classe TraceIdLoggingEnhancer suivante utilise l'API ApiProxy pour récupérer l'ID de trace associé à une requête :

      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. Ajoutez la configuration de l'appender Cloud Logging dans le fichier logback.xml pour configurer Logback. Le framework de Logback gère la configuration via le fichier logback.xml dans 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'image suivante illustre la structure de répertoire finale de l'application :

    Structure des répertoires

Afficher les journaux corrélés

Vous pouvez afficher les journaux corrélés dans l'explorateur de journaux à l'aide du champ d'ID de trace dans chaque entrée de journal. Pour afficher les journaux corrélés dans l'explorateur de journaux, procédez comme suit :

  1. Dans le panneau de navigation de la console Google Cloud, sélectionnez Logging, puis Explorateur de journaux :

    Accéder à l'explorateur de journaux

  2. Dans Type de ressource, sélectionnez Application GAE.

  3. Pour afficher et mettre en corrélation les journaux de requêtes, sélectionnez request_log dans le champ Nom du journal. Sinon, pour mettre en corrélation par journaux de requêtes, cliquez sur Corréler par et sélectionnez request_log :

    Corréler les journaux

  4. Dans le volet Résultats de la requête, cliquez sur Développer pour développer une entrée de journal. Lors du développement, chaque journal de requêtes affiche les journaux d'application associés.