Memigrasikan logging ke runtime Java generasi kedua

Beberapa aspek logging di runtime generasi kedua (Java 11+) berbeda dengan runtime generasi pertama (Java 8). Tidak seperti runtime generasi pertama, dalam runtime generasi kedua, log aplikasi tidak dikelompokkan dalam log permintaan dalam Log Explorer. Selain itu, di runtime generasi kedua, App Engine menulis setiap log aplikasi yang terkait dengan permintaan sebagai entri log terpisah di Cloud Logging.

Panduan ini menjelaskan cara menerapkan metode logging yang sama dengan yang Anda gunakan di aplikasi runtime generasi pertama, dan mencapai hasil korelasi pemfilteran dan logging yang hampir sama saat memigrasikan aplikasi ke Java 11+.

Perbedaan utama

Tabel berikut membahas perbedaan logging antara runtime generasi pertama dan kedua:

Runtime generasi pertama (Java 8) Runtime generasi kedua (Java 11+)
Log permintaan dan aplikasi (juga disebut log aplikasi) App Engine menyematkan semua log aplikasi dalam log permintaan. App Engine tidak menyematkan log aplikasi dalam log permintaan.
stdout dan stderr App Engine menyematkan log yang ditulis ke stdout dan stderr dalam log permintaan. App Engine tidak menyematkan log yang ditulis ke stdout dan stderr.
Log platform App Engine App Engine tidak memunculkan log platform internal. App Engine memunculkan log platform internal selama startup atau shutdown instance dengan nama log /var/log/google_init.log.
Kuota Cloud Logging API Setiap permintaan sesuai dengan satu penulisan Cloud Logging. Setiap entri log aplikasi yang terkait dengan permintaan sesuai dengan satu operasi tulis Cloud Logging. Penggunaan Cloud Logging API meningkat di runtime generasi kedua.

Log permintaan dan log aplikasi

Perilaku logging di runtime generasi pertama dan kedua berbeda dengan cara berikut:

  • Dalam runtime generasi pertama, App Engine menyematkan log aplikasi di kolom protoPayload.line log permintaan. Anda dapat melihat log aplikasi dengan memperluas permintaan di Logs Explorer.

    Gambar berikut menunjukkan log aplikasi dan permintaan yang terkait di runtime generasi pertama:

    Log yang berkorelasi di Java 8

  • Dalam runtime generasi kedua, log permintaan tidak berisi entri log aplikasi karena kolom protoPayload.line tidak ada dalam log permintaan. Sebagai gantinya, App Engine mencatat setiap log aplikasi sebagai entri terpisah. Nama log bergantung pada penyiapan logging Anda. var/log/app berisi log yang dikeluarkan menggunakan framework logging standar seperti, java.util.logging atau Simple Logging Facade for Java (SLF4J). Log stderr dan stdout berisi log aplikasi yang dicatat ke dalam log menggunakan System.err.print() atau System.out.print().

    Gambar berikut menampilkan log permintaan dan aplikasi terpisah di runtime generasi kedua:

    Memisahkan log di Java 11

stdout dan stderr

Dalam runtime generasi pertama, App Engine menganggap log yang dikeluarkan ke stdout dan stderr sebagai log aplikasi, dan secara otomatis mengelompokkan entri log aplikasi ini dalam log permintaan terkait.

Di runtime generasi kedua, App Engine tidak mengaitkan log yang dikeluarkan ke stdout dan stderr secara default. Untuk mengelompokkan entitas log aplikasi dengan log permintaan menggunakan stdout dan stderr, ikuti petunjuk di Menulis log terstruktur ke stdout dan stderr.

Sebaiknya jangan melakukan logging ke stdout dan stderr karena log platform App Engine tertentu (JVM, Jetty, log infrastruktur internal) juga ditampilkan ke stderr. Log aplikasi dan log platform muncul bersama dengan nama log stderr, yang menyebabkan ambiguitas. Hal ini dilebih-lebihkan di runtime generasi kedua karena App Engine memiliki volume log platform yang lebih tinggi.

Log platform App Engine

Dalam runtime generasi pertama, App Engine tidak mengeluarkan log platform.

Dalam runtime generasi kedua, App Engine memunculkan log platform selama startup atau shutdown instance dengan nama log /var/log/google_init.log.

Anda dapat mengabaikan log platform dengan aman. Agar tidak melihat log ini, tambahkan filter ke Logs Explorer dengan kueri logName="/var/log/google_init.log".

Gambar berikut menampilkan log platform di runtime generasi kedua:

Log platform

Kuota Cloud Logging API

Dalam runtime generasi pertama, App Engine menyematkan semua log aplikasi yang dikeluarkan selama permintaan ke dalam satu log permintaan, dan mengirim permintaan tersemat ke Cloud Logging. Setiap permintaan sesuai dengan satu penulisan Cloud Logging.

Pada runtime generasi kedua, App Engine mengirim setiap log aplikasi ke Cloud Logging dalam entri log terpisah, sehingga menyebabkan peningkatan jumlah total operasi tulis Cloud Logging per permintaan.

Google Cloud menentukan penagihan berdasarkan penyimpanan keseluruhan yang digunakan Cloud Logging. Meskipun penyimpanan keseluruhan yang diperlukan untuk log tidak meningkat secara signifikan, penulisan per menit akan meningkat, bergantung pada jumlah log aplikasi yang ditulis App Engine per permintaan. Jika aplikasi Anda melebihi kuota tulis Cloud Logging, Anda dapat meminta peningkatan kuota penggunaan.

Untuk mengetahui informasi selengkapnya, lihat harga untuk Cloud Logging.

Ringkasan proses migrasi

Meskipun log aplikasi tidak disematkan dalam log permintaan di runtime generasi kedua, pengalaman melihat log dapat dipertahankan seperti aplikasi generasi pertama.

Anda dapat memilih salah satu opsi berikut untuk menyiapkan logging di runtime generasi kedua:

Menggunakan paket java.util.logging (JUL)

Jika aplikasi Anda yang menggunakan runtime generasi pertama menerapkan paket java.util.logging untuk semua persyaratan logging, migrasi ke runtime generasi kedua tidak memerlukan perubahan kode.

Contoh berikut menunjukkan cara menggunakan paket java.util.logging untuk logging di runtime generasi kedua:

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

Mengelompokkan log aplikasi dengan log permintaan

Dalam runtime generasi kedua, kolom protoPayload.line dalam log permintaan tidak berisi log aplikasi. Logs Explorer menggunakan kolom trace untuk mengelompokkan log permintaan dan log aplikasi. Paket java.util.logging secara otomatis menambahkan ID rekaman aktivitas ke semua log permintaan dan aplikasi. Untuk melihat log yang terkait di Logs Explorer, lihat Melihat log yang terkait.

Menggunakan Simple Logging Facade for Java (SLF4J)

SLF4J adalah antarmuka logging yang paling populer digunakan dalam aplikasi Java. Sebagai facade, antarmuka SLF4J tidak bergantung pada platform backend logging-nya, sehingga Anda dapat memilih backend yang sesuai untuk aplikasi Anda.

Gambar berikut menunjukkan opsi integrasi untuk dua backend SLF4J, termasuk library java.util.logging dan appender Logback:

Ringkasan SLF4J

SLF4J dengan paket java.util.logging

SLF4J memungkinkan Anda mengintegrasikan aplikasi dengan Cloud Logging saat menggunakan SLF4J dengan java.util.logging sebagai backend logging. Secara default, App Engine menambahkan ID trace ke semua log permintaan dan aplikasi. Mekanisme ini memungkinkan pengelompokan log permintaan dan aplikasi di Logs Explorer.

Untuk menerapkan SLF4J dengan java.util.logging, ikuti langkah-langkah berikut:

  1. Tambahkan dependensi slf4j-jdk14.jar ke file pom.xml Anda. File slf4j-jdk14.jar menyediakan integrasi backend untuk library 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. Buat file WEB-INF/logging.properties untuk menambahkan konfigurasi kustom:

    com.example.appengine.java8.HelloAppEngine.level = INFO
    
  3. Perbarui file appengine-web.xml Anda untuk menyertakan nilai <property> untuk WEB-INF/logging.properties:

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

Gambar berikut menunjukkan cara SLF4J dengan java.util.logging otomatis menambahkan ID rekaman aktivitas ke log aplikasi:

Mengelompokkan log aplikasi menurut permintaan dengan ID rekaman aktivitas

Untuk menyesuaikan tampilan Logs Explorer ke tampilan yang berfokus pada permintaan seperti runtime generasi pertama, lihat Melihat log yang terkait.

Menggunakan SLF4J dengan appender Logback

Jika aplikasi runtime generasi pertama Anda menggunakan implementasi bawaan SLF4J dengan Logback, Anda harus mengupdate kode sumber, dan menerapkan langkah tambahan untuk mengelompokkan log aplikasi dan permintaan.

Untuk mengintegrasikan aplikasi Anda dengan Cloud Logging, ikuti langkah-langkah berikut:

  1. Tambahkan appender google-cloud-logging-logback ke file pom.xml untuk menginstal appender logging untuk 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. Buat pengoptimal logging untuk menambahkan ID rekaman aktivitas ke setiap kolom LogEntry. Class TraceIdLoggingEnhancer berikut menggunakan ApiProxy API untuk mengambil ID rekaman aktivitas yang terkait dengan permintaan:

      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. Tambahkan konfigurasi appender Cloud Logging dalam file logback.xml untuk mengonfigurasi Logback. Framework Logback mengelola konfigurasi melalui file logback.xml di 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>
    

    Gambar berikut menunjukkan struktur direktori aplikasi akhir:

    Struktur direktori

Melihat log yang berkorelasi

Anda dapat melihat log yang terkait di Logs Explorer menggunakan kolom ID rekaman aktivitas di setiap entri log. Untuk melihat log yang terkait di Logs Explorer:

  1. Di panel navigasi konsol Google Cloud, pilih Logging, lalu pilih Logs Explorer:

    Buka Logs Explorer

  2. Di Resource Type, pilih GAE Application.

  3. Untuk melihat dan mengaitkan log permintaan, di Nama Log, pilih request_log. Atau, untuk melakukan korelasi menurut log permintaan, klik Correlate by, lalu pilih request_log:

    Menggabungkan log

  4. Di panel Query results, untuk meluaskan entri log, klik Expand. Saat diperluas, setiap log permintaan akan menampilkan log aplikasi terkait.