將記錄功能遷移至第二代 Java 執行階段

在第二代執行階段 (Java 11 以上版本) 中,記錄的某些方面與第一代執行階段 (Java 8) 不同。與第一代執行階段不同,在第二代執行階段中,應用程式記錄並未在「記錄檔探索工具」中依要求記錄分組。此外,在第二代執行階段中,App Engine 會將與要求相關聯的每個應用程式記錄,以單獨的記錄項目寫入 Cloud Logging。

本指南說明如何實作與第一代執行階段應用程式相同的記錄方法,並在將應用程式遷移至 Java 11 以上版本時,取得幾乎相同的篩選和記錄相關聯結果。

主要差異

下表說明第一代與第二代執行階段之間的記錄差異:

第一代執行階段 (Java 8) 第二代執行階段 (Java 11 以上版本)
要求和應用程式記錄 (也稱為應用程式記錄) App Engine 會將所有應用程式記錄嵌入要求記錄中。 App Engine 不會在要求記錄中嵌入應用程式記錄。
stdout 和 stderr App Engine 會將寫入 stdout 和 stderr 的記錄嵌入要求記錄中。 App Engine 不會將寫入 stdout 和 stderr 的記錄嵌入。
App Engine 平台記錄檔 App Engine 不會發出內部平台記錄。 App Engine 會在執行個體啟動或關閉期間,以記錄名稱 /var/log/google_init.log 發出內部平台記錄。
Cloud Logging API 配額 每個要求都對應至一個 Cloud Logging 寫入。 與要求相關聯的每個應用程式記錄項目都會對應到一個 Cloud Logging 寫入作業。Cloud Logging API 用量在第二代執行階段增加。

要求記錄和應用程式記錄

第一代與第二代執行階段的記錄行為有以下差異:

  • 在第一代執行階段中,App Engine 會將應用程式記錄嵌入要求記錄的 protoPayload.line 欄位中。您可以在「Logs Explorer」中展開要求,查看應用程式記錄。

    下圖顯示第一代執行階段中關聯的請求和應用程式記錄:

    Java 8 中的相關記錄

  • 在第二代執行階段中,要求記錄檔不包含應用程式記錄項目,因為要求記錄檔中沒有 protoPayload.line 欄位。相反地,App Engine 會將每個應用程式記錄記錄為個別項目。記錄名稱取決於記錄設定。var/log/app 包含使用標準記錄架構 (例如 java.util.logging 或 Simple Logging Facade for Java (SLF4J)) 產生的記錄。stderr 和 stdout 記錄檔包含使用 System.err.print() 或 System.out.print() 記錄的應用程式記錄檔。

    下圖顯示第二代執行階段中的個別要求和應用程式記錄:

    在 Java 11 中分開記錄

stdout 和 stderr

在第一代執行階段中,App Engine 會將傳送至 stdout 和 stderr 的記錄視為應用程式記錄,並自動將這些應用程式記錄項目歸入相關聯的要求記錄下方。

在第二代執行階段中,App Engine 預設不會將記錄與 stdout 和 stderr 關聯。如要使用 stdout 和 stderr 將應用程式記錄實體與要求記錄分組,請按照「將結構化記錄寫入 stdout 和 stderr」中的操作說明操作。

我們不建議您將記錄資料寫入 stdout 和 stderr,因為某些 App Engine 平台記錄資料 (JVM、Jetty、內部基礎架構記錄資料) 也會傳送至 stderr。應用程式記錄和平台記錄會與 stderr 記錄名稱一併顯示,導致混淆。由於 App Engine 的平台記錄量較高,因此在第二代執行階段中,這項問題會更加嚴重。

App Engine 平台記錄

在第一代執行階段中,App Engine 不會發出平台記錄。

在第二代執行階段中,App Engine 會在執行個體啟動或關閉期間,以 /var/log/google_init.log 為記錄名稱,傳送平台記錄。

您可以放心忽略平台記錄。如要避免看到這些記錄,請使用查詢 logName="/var/log/google_init.log" 將篩選器新增至 Logs Explorer。

下圖顯示第二代執行階段中的平台記錄:

平台記錄檔

Cloud Logging API 配額

在第一代執行階段中,App Engine 會將要求期間產生的所有應用程式記錄嵌入單一要求記錄,並將嵌入的要求傳送至 Cloud Logging。每個要求都對應至一筆 Cloud Logging 寫入作業。

在第二代執行階段中,App Engine 會將每個應用程式記錄以個別記錄項目的形式傳送至 Cloud Logging,導致每項要求的 Cloud Logging 寫入總數增加。

Google Cloud 會根據 Cloud Logging 使用的整體儲存空間來決定計費。即使記錄檔所需的整體儲存空間並未大幅增加,每分鐘的寫入次數也會增加,具體取決於 App Engine 每個要求寫入的應用程式記錄數量。如果應用程式超過 Cloud Logging 寫入配額,您可以要求提高使用量配額。

詳情請參閱 Cloud Logging 的定價。

轉換程序總覽

即使應用程式記錄檔未嵌入第二代執行階段的請求記錄檔,仍可保留第一代應用程式類似的記錄檔查看體驗。

您可以選擇下列任一選項,在第二代執行階段中設定記錄:

使用 java.util.logging (JUL) 套件

如果您的應用程式使用第一代執行階段,並為所有記錄需求實作 java.util.logging 套件,則無需修改程式碼即可遷移至第二代執行階段。

以下範例說明如何使用 java.util.logging 套件,在第二代執行階段記錄資料:

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

將應用程式記錄與要求記錄分組

在第二代執行階段中,要求記錄中的 protoPayload.line 欄位不包含應用程式記錄。記錄檔探索工具會使用 trace 欄位將要求記錄檔和應用程式記錄檔分組。java.util.logging 套件會自動將追蹤 ID 新增至所有要求和應用程式記錄。如要在 Logs Explorer 中查看相關聯的記錄,請參閱「查看相關聯的記錄」。

使用 Java 適用的 Simple Logging Facade (SLF4J)

SLF4J 是 Java 應用程式中使用率最高的記錄介面。由於是 Facade,SLF4J 介面不受其記錄後端平台限制,因此您可以選擇任何適合應用程式的後端。

下圖顯示兩個 SLF4J 後端的整合選項,包括 java.util.logging 程式庫和 Logback 附加程式:

SLF4J 簡介

搭配 java.util.logging 套件的 SLF4J

當您使用 SLF4J 搭配 java.util.logging 做為記錄後端時,SLF4J 可讓您將應用程式與 Cloud Logging 整合。根據預設,App Engine 會在所有要求和應用程式記錄中新增追蹤 ID。這個機制可在 Logs Explorer 中將要求和應用程式記錄分組。

如要使用 java.util.logging 實作 SLF4J,請按照下列步驟操作:

  1. 將 slf4j-jdk14.jar 依附元件新增至 pom.xml 檔案。slf4j-jdk14.jar 檔案可為 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. 建立 WEB-INF/logging.properties 檔案以新增自訂設定:

    com.example.appengine.java8.HelloAppEngine.level = INFO
    
  3. 更新 appengine-web.xml 檔案,加入 WEB-INF/logging.properties 的 <property> 值:

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

下圖顯示 SLF4J 搭配 java.util.logging 如何自動將追蹤 ID 新增至應用程式記錄:

依追蹤 ID 將應用程式記錄檔分組

如要將記錄檔探索工具檢視畫面調整為以要求為中心的檢視畫面 (例如第一代執行階段),請參閱「查看關聯記錄」。

搭配 Logback 附加程式使用 SLF4J

如果第一代執行階段應用程式使用內建的 SLF4J 實作項目,並搭配使用 Logback,則必須更新原始碼,並實作額外的步驟來分組要求和應用程式記錄。

如要將應用程式與 Cloud Logging 整合,請按照下列步驟操作:

  1. 將 google-cloud-logging-logback 附加程式新增至 pom.xml 檔案,即可安裝 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. 建立記錄增強器,將追蹤 ID 新增至每個 LogEntry 欄位。以下 TraceIdLoggingEnhancer 類別會使用 ApiProxy API 擷取與要求相關聯的追蹤 ID:

      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. 在 logback.xml 檔案中新增 Cloud Logging 附加程式設定,以設定 Logback。Logback 架構會透過 WEB-INF/classes 中的 logback.xml 檔案管理設定:

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

    下圖顯示最終應用程式目錄結構:

    目錄結構

查看相關聯的記錄檔

您可以使用每個記錄項目中的追蹤 ID 欄位,在記錄檔探索工具中查看相關聯的記錄檔。如要在記錄檔探索工具中查看相關聯的記錄,請按照下列步驟操作:

  1. 在 Google Cloud 控制台的導覽面板中,依序選取「Logging」和「Logs Explorer」:

    前往「Logs Explorer」

  2. 在「Resource Type」(資源類型) 中,選取「GAE Application」(GAE 應用程式)。

  3. 如要查看並關聯要求記錄,請在「記錄名稱」中選取「request_log」。或者,如要依據要求記錄檔建立關聯,請按一下「依據」,然後選取「request_log」:

    關聯記錄檔

  4. 如要展開記錄項目,請在「查詢結果」窗格中按一下「展開」。展開後,每個要求記錄都會顯示相關聯的應用程式記錄。