העברת רישום ביומן לזמני ריצה של Java מדור שני

יש הבדלים מסוימים בין ההיבטים של הכניסה לזמני הריצה מהדור השני (Java 11 ומעלה) לבין זמני הריצה מהדור הראשון (Java 8). בשונה מהסביבות של זמן הריצה מהדור הראשון, בסביבות של זמן הריצה מהדור השני, יומני האפליקציות לא מקובצים ביומני הבקשות ב-Logs Explorer. בנוסף, בסביבות זמן הריצה מהדור השני, App Engine כותב כל יומן אפליקציה שמשויך לבקשה כרשומה נפרדת ביומן ב-Cloud Logging.

במדריך הזה מוסבר איך להטמיע את אותן שיטות רישום ביומן שבהן השתמשתם באפליקציות של סביבת זמן ריצה מהדור הראשון, ולקבל כמעט את אותן תוצאות של סינון ושל קורלציה של רישום ביומן כשמעבירים את האפליקציה ל-Java 11 ומעלה.

ההבדלים העיקריים

בטבלה הבאה מפורטים ההבדלים ברישום ביומן בין סביבות זמן ריצה מהדור הראשון לבין סביבות זמן ריצה מהדור השני:

סביבת זמן ריצה מהדור הראשון (Java 8) זמני ריצה מהדור השני (Java 11 ואילך)
יומני בקשות ואפליקציות ‫App Engine מטמיע את כל יומני האפליקציה ביומן הבקשות. ‫App Engine לא מטמיע יומני אפליקציות ביומן הבקשות.
stdout ו-stderr יומנים שנכתבו אל stdout ו-stderr מוטמעים ביומן הבקשות של App Engine. ‫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.

אפשר להתעלם מיומני הפלטפורמה. כדי להימנע מהצגת היומנים האלה, מוסיפים מסנן ל-Logs Explorer עם השאילתה logName="/var/log/google_init.log".

התמונה הבאה מציגה יומנים של פלטפורמה בסביבות זמן ריצה מהדור השני:

יומני פלטפורמה

מכסת 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 ביומן הבקשות לא מכיל יומני אפליקציות. ב-Logs Explorer נעשה שימוש בשדה trace כדי לקבץ יומני בקשות ויומני אפליקציות. החבילה java.util.logging מוסיפה באופן אוטומטי את מזהה המעקב לכל הבקשות ולכל יומני האפליקציות. כדי להציג יומנים עם קורלציה ב-Logs Explorer, ראו הצגת יומנים עם קורלציה.

שימוש ב-Simple Logging Facade for Java‏ (SLF4J)

‫SLF4J הוא ממשק הרישום הפופולרי ביותר שמשמש באפליקציות Java. ממשק SLF4J הוא חזית, ולכן הוא לא תלוי בפלטפורמה של בק-אנד הרישום ביומן שלו, כך שאתם יכולים לבחור כל בק-אנד שמתאים לאפליקציות שלכם.

בתמונה הבאה מוצגות אפשרויות שילוב לשני עורפי SLF4J, כולל ספריית java.util.logging וה-appender של Logback:

סקירה כללית של SLF4J

‫SLF4J עם חבילת java.util.logging

‫SLF4J מאפשר לכם לשלב את האפליקציה עם Cloud Logging כשאתם משתמשים ב-SLF4J עם java.util.logging כקצה העורפי של רישום היומן. כברירת מחדל, App Engine מוסיף מזהה מעקב לכל הבקשות וליומני האפליקציות. המנגנון הזה מאפשר לקבץ את היומנים של הבקשות והאפליקציות ב-Logs Explorer.

כדי להטמיע את SLF4J עם java.util.logging, פועלים לפי השלבים הבאים:

  1. מוסיפים את התלות slf4j-jdk14.jar לקובץ pom.xml. קובץ slf4j-jdk14.jar מספק את שילוב ה-Backend לספרייה 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 ומוסיפים את הערך <property> בשביל WEB-INF/logging.properties:

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

בתמונה הבאה אפשר לראות איך SLF4J עם java.util.logging מוסיף באופן אוטומטי את מזהה המעקב ליומן של האפליקציה:

קיבוץ של יומני אפליקציות לפי בקשה עם מזהה מעקב

כדי לשנות את התצוגה ב-Logs Explorer לתצוגה ממוקדת בבקשות כמו בדור הראשון של זמן הריצה, אפשר לעיין במאמר הצגת יומנים מקושרים.

שימוש ב-SLF4J עם Logback appender

אם אפליקציות זמן הריצה מהדור הראשון משתמשות בהטמעה המובנית של SLF4J עם Logback, צריך לעדכן את קוד המקור ולבצע שלבים נוספים כדי לקבץ את בקשות היומן ואת יומני האפליקציה.

כדי לשלב את האפליקציה עם Cloud Logging, פועלים לפי השלבים הבאים:

  1. כדי להתקין את תוסף הרישום של Logback, מוסיפים את התוסף google-cloud-logging-logback לקובץ pom.xml:

     <!-- 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. יוצרים כלי לשיפור הרישום ביומן כדי להוסיף מזהה מעקב לכל שדה LogEntry. המחלקות הבאות TraceIdLoggingEnhancer משתמשות ב-ApiProxy API כדי לאחזר את מזהה המעקב שמשויך לבקשה:

      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. מוסיפים את ההגדרה של Cloud Logging appender בקובץ logback.xml כדי להגדיר את Logback. הגדרות מנוהלות באמצעות קובץ logback.xml ב-WEB-INF/classes במסגרת Logback:

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

    בתמונה הבאה מוצג המבנה הסופי של תיקיית האפליקציה:

    מבנה הספרייה

צפייה ביומנים עם קורלציה

אפשר לראות יומנים עם קורלציה ב-Logs Explorer באמצעות השדה trace ID בכל רשומה ביומן. כדי להציג יומנים עם קורלציה ב-Logs Explorer:

  1. בחלונית הניווט של מסוף Google Cloud , בוחרים באפשרות Logging ואז באפשרות Logs Explorer:

    כניסה לדף Logs Explorer

  2. בקטע Resource Type, בוחרים באפשרות GAE Application.

  3. כדי להציג יומני בקשות ולבצע ביניהם קורלציה, בוחרים באפשרות request_log בשם היומן. לחלופין, כדי לבצע קורלציה לפי יומני בקשות, לוחצים על Correlate by (קורלציה לפי) ובוחרים באפשרות request_log (יומן בקשות):

    הצלבת נתונים מיומנים

  4. בחלונית Query results, כדי להרחיב רשומה ביומן, לוחצים על Expand. כשמרחיבים את היומן, מוצגים יומני האפליקציה שמשויכים לכל בקשה.