כתיבה והצגה של יומנים


רישום ביומן הוא כלי חשוב לניפוי באגים ולמעקב אחרי קוד. Cloud Functions מאפשר לכם להשתמש ב-SDK של ה-logger ל-Node.js או ל-Python, או בתקן האובייקט console לפיתוח לאינטרנט.

Cloud Logging הוא שירות בתשלום. אם תחרגו מהמכסה ללא עלות, יכול להיות שתחויבו. מידע נוסף זמין במאמר תמחור של Cloud Logging.

כתיבה ביומן

שימוש ב-SDK של יומן Cloud Functions

ה-SDK של ה-logger של Cloud Functions מספק ממשק רגיל לדיווח על סטטוס מהפונקציות ל-Cloud Logging. אפשר להשתמש ב-SDK הזה כדי לתעד אירועים עם נתונים מובְנים, וכך לבצע ניתוח ומעקב בקלות רבה יותר.

ייבוא מחבילת המשנה logger:

// All available logging functions
const {
  log,
  info,
  debug,
  warn,
  error,
  write,
} = require("firebase-functions/logger");
from firebase_functions import logger
  • לפקודות logger.log() יש את רמת היומן INFO.

  • לפקודות logger.info() יש את רמת היומן INFO.

  • לפקודות logger.warn() יש את רמת היומן WARNING.

  • לפקודות logger.error() יש את רמת היומן ERROR.

  • לפקודות logger.debug() יש את רמת היומן DEBUG.

  • להודעות מערכת פנימיות יש את רמת היומן DEBUG.

בדוגמה הזו מוצגת פונקציה שכותבת יומן בסיסי:

exports.helloWorld = onRequest((request, response) => {
  // sends a log to Cloud Logging
  log("Hello logs!");

  response.send("Hello from Firebase!");
});
@https_fn.on_request()
def hello_world(req: https_fn.Request) -> https_fn.Response:
    # sends a log to Cloud Logging
    logger.log("Hello logs!")

    return https_fn.Response("Hello from Firebase!")

להשתמש ברמות יומן שונות לסוגים שונים של יומנים בקוד הפונקציה. אפשר לצרף נתונים מובְנים ליומן כארגומנטים האחרונים. דוגמה לשימוש בפונקציה בכל סוג של יומן:

exports.getInspirationalQuote = onRequest(async (request, response) => {
  const db = getFirestore();
  const today = new Date();
  const quoteOfTheMonthRef = db
      .collection("quotes")
      .doc(`${today.getFullYear()}`)
      .collection("months")
      .doc(`${today.getMonth()}`);

  const DEFAULT_QUOTE =
      "You miss 100% of the shots you don't take. -Wayne Gretzky";
  let quote;
  try {
    const quoteOfTheMonthDocSnap = await quoteOfTheMonthRef.get();

    // Attach relevant debugging information with debug()
    debug("Monthly quote fetch result", {
      docRef: quoteOfTheMonthRef.path,
      exists: quoteOfTheMonthDocSnap.exists,
      createTime: quoteOfTheMonthDocSnap.createTime,
    });

    if (quoteOfTheMonthDocSnap.exists) {
      quote = quoteOfTheMonthDocSnap.data().text;
    } else {
      // Use warn() for lower-severity issues than error()
      warn("Quote not found for month, sending default instead", {
        docRef: quoteOfTheMonthRef.path,
        dateRequested: today.toLocaleDateString("en-US"),
      });

      quote = DEFAULT_QUOTE;
    }
  } catch (err) {
    // Attach an error object as the second argument
    error("Unable to read quote from Firestore, sending default instead",
        err);

    quote = DEFAULT_QUOTE;
  }

  // Attach relevant structured data to any log
  info("Sending a quote!", {quote: quote});
  response.json({inspirationalQuote: quote});
});
@https_fn.on_request()
def get_inspirational_quote(req: https_fn.Request) -> https_fn.Response:
    firestore_client = firestore.client()
    today = datetime.date.today()
    quote_of_the_month_ref = (firestore_client.collection("quotes").doc(str(
        today.year)).collection("months").doc(str(today.month)))

    default_quote = "Python has been an important part of Google since the beginning, and remains so as the system grows and evolves."

    quote = None
    try:
        quote_of_the_month = quote_of_the_month_ref.get()

        # Attach relevant debugging information with debug()
        logger.debug(
            "Monthly quote fetch result",
            docRef=quote_of_the_month.path,
            exists=quote_of_the_month.exists,
            createTime=quote_of_the_month.createTime,
        )

        if quote_of_the_month.exists:
            quote = quote_of_the_month.to_dict()["text"]
        else:
            # Use warn() for lower-severity issues than error()
            logger.warn(
                "Quote not found for month, sending default instead",
                doc_reference=quote_of_the_month.path,
                date_requested=today.strftime("%Y-%m-%d"),
            )
            quote = default_quote
    except:
        e = sys.exc_info()[0]
        # Attach an error object as the second argument
        logger.error("Unable to read quote from Firestore, sending default instead", error=e)
        quote = default_quote

    # Attach relevant structured data to any log
    logger.info("Sending a quote!", quote=quote)
    return https_fn.Response("Hello from Firebase!")

בעזרת logger.write() אפשר לכתוב רשומות ביומן עם רמות חומרה נוספות של יומן: CRITICAL,‏ ALERT ו-EMERGENCY. מידע נוסף זמין במאמר LogSeverity.

exports.appHasARegression = onRegressionAlertPublished((event) => {
  write({
    // write() lets you set additional severity levels
    // beyond the built-in logger functions
    severity: "EMERGENCY",
    message: "Regression in production app",
    issue: event.data.payload.issue,
    lastOccurred: event.data.payload.resolveTime,
  });
});
@crashlytics_fn.on_regression_alert_published()
def app_has_regression(alert: crashlytics_fn.CrashlyticsRegressionAlertEvent) -> None:
    logger.write(
        severity="EMERGENCY",
        message="Regression in production app",
        issue=alert.data.payload.issue,
        last_occurred=alert.data.payload.resolve_time,
    )
    print(alert)

שימוש ב-console.log

הפתרון המומלץ לרישום ביומן מפונקציה הוא להשתמש ב-SDK של ה-logger לפלטפורמה שלכם. ב-Node.js, אפשר להשתמש במקום זאת בקריאות רגילות של רישום ביומן ב-JavaScript, כמו console.log ו-console.error, אבל קודם צריך לדרוש מודול מיוחד כדי לתקן את השיטות הרגילות כדי שהן יפעלו כמו שצריך:

require("firebase-functions/logger/compat");

אחרי שמגדירים את מודול התאימות של היומן, אפשר להשתמש בשיטות של console.log() בקוד כרגיל:

exports.helloError = functions.https.onRequest((request, response) => {
  console.log('I am a log entry!');
  response.send('Hello World...');
});
  • לפקודות console.log() יש את רמת היומן INFO.
  • לפקודות console.info() יש את רמת היומן INFO.
  • לפקודות console.warn() יש את רמת היומן ERROR.
  • לפקודות console.error() יש את רמת היומן ERROR.
  • להודעות מערכת פנימיות יש את רמת היומן DEBUG.

צפייה ביומנים

אפשר לראות את היומנים של Cloud Functions במסוף Google Cloud, בממשק המשתמש של Cloud Logging או באמצעות הכלי בשורת הפקודה firebase.

שימוש ב-Firebase CLI

כדי להציג יומנים באמצעות הכלי firebase, משתמשים בפקודה functions:log:

firebase functions:log

כדי להציג יומנים של פונקציה ספציפית, מציינים את שם הפונקציה כארגומנט:

firebase functions:log --only <FUNCTION_NAME>

כדי לראות את כל האפשרויות להצגת יומנים, אפשר לעיין במאמרי העזרה של functions:log:

firebase help functions:log

באמצעות מסוף Google Cloud

אפשר להציג יומנים של פונקציות במסוף Google Cloud.

שימוש בממשק המשתמש של Cloud Logging

אפשר להציג יומנים של Cloud Functions בממשק המשתמש של Cloud Logging.

ניתוח יומנים

Cloud Logging מציע חבילה חזקה של כלים לניתוח יומנים, שבעזרתם תוכלו לעקוב אחרי Cloud Functions.

תרשימים והתראות

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

במאמר יצירת תרשימים והתראות מוסבר בפירוט איך להשתמש במדדים שמבוססים על יומנים בתרשימים ובמדיניות ההתראות.

הסבר על מזהי הרצות ושימוש בהם

כברירת מחדל, פונקציות Cloud Run (דור שני) תומכות בהרצה בו-זמנית של כמה בקשות במכונה אחת של פונקציה. המשמעות היא שיומני בקשות שונות יכולים להיות מופרדים, וכך קשה יותר לעקוב אחרי התהליך של ביצוע יחיד.

כדי לעזור בכך, פונקציות שנפרסו באמצעות Firebase CLI בגרסה 13.33.0 ואילך מופצות באופן אוטומטי עם אפשרות לשייך מזהה הפעלה לכל רשומת יומן שנוצרת במהלך הטיפול בהפעלה הזו.

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

כדי להשבית את הרישום ביומן של מזהה ההפעלה ברשאות היומן, מגדירים את משתנה הסביבה LOG_EXECUTION_ID כ-false בקובץ dotenv.

חיפוש יומנים ויצירת קורלציה ביניהם לפי מזהה הביצוע

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

  1. מרחיבים את הרשומה ביומן מהפונקציה. מזהה הביצוע נמצא בנתוני היומן המובְנים, בתצוגת עץ מתחת לתוויות בתור labels.execution_id.

  2. לוחצים על הערך של execution_id ובוחרים באפשרות 'הצגת רשומות תואמות' בתפריט הנפתח כדי לראות את כל היומנים האחרים שמשויכים לאותה הפעלת פונקציה.

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

שיפור החשיפה של היומנים באמצעות שדות סיכום בהתאמה אישית

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

כדי להוסיף את מזהה ההרצה לשדה הסיכום:

  1. לוחצים על הערך של מזהה הביצוע ברשומה המובנית ביומן בקטע labels.execution_id.

  2. בתפריט הנפתח, בוחרים באפשרות 'הוספת שדה לשורת הסיכום'.

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