เขียนและดูบันทึก

การบันทึกเป็นเครื่องมือสำคัญสำหรับการแก้ไขข้อบกพร่องและการตรวจสอบโค้ด Cloud Functions ให้คุณเลือกใช้ logger SDK สำหรับ Node.js หรือ Python หรือออบเจ็กต์ console มาตรฐานสำหรับการพัฒนาเว็บ

Cloud Logging เป็นบริการที่มีค่าใช้จ่าย โดยระบบอาจเรียกเก็บเงินจากคุณหากคุณใช้โควต้าเกินขีดจำกัดที่ไม่มีค่าใช้จ่าย ดูข้อมูลเพิ่มเติมได้ที่ ราคา Cloud Logging

การเขียนบันทึก

การใช้ Cloud Functions logger SDK

Cloud Functions logger SDK มีอินเทอร์เฟซมาตรฐาน สำหรับรายงานสถานะจากฟังก์ชันไปยัง Cloud Logging คุณสามารถใช้ SDK นี้เพื่อบันทึกเหตุการณ์ด้วย Structured Data, ซึ่งช่วยให้วิเคราะห์และตรวจสอบได้ง่ายขึ้น

นำเข้าจากแพ็กเกจย่อย logger ดังนี้

Node.js

// All available logging functions
const {
  log,
  info,
  debug,
  warn,
  error,
  write,
} = require("firebase-functions/logger");

Python

from firebase_functions import logger
  • คำสั่ง logger.log() มีระดับบันทึกเป็น INFO

  • คำสั่ง logger.info() มีระดับบันทึกเป็น INFO

  • คำสั่ง logger.warn() มีระดับบันทึกเป็น WARNING

  • คำสั่ง logger.error() มีระดับบันทึกเป็น ERROR

  • คำสั่ง logger.debug() มีระดับบันทึกเป็น DEBUG

  • ข้อความระบบภายในมีระดับบันทึกเป็น DEBUG

ตัวอย่างนี้แสดงฟังก์ชันการเขียนบันทึกพื้นฐาน

Node.js

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

  response.send("Hello from Firebase!");
});

Python

@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!")

ใช้ระดับบันทึกที่แตกต่างกันสำหรับบันทึกประเภทต่างๆ ในโค้ดฟังก์ชัน คุณสามารถแนบ Structured Data กับบันทึกเป็นอาร์กิวเมนต์สุดท้ายได้ ตัวอย่างวิธีที่ฟังก์ชันใช้บันทึกแต่ละประเภทมีดังนี้

Node.js

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

Python

@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

Node.js

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

Python

@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

โซลูชันที่แนะนำสำหรับการบันทึกจากฟังก์ชันคือการใช้ logger SDK สำหรับแพลตฟอร์มของคุณ ใน Node.js คุณสามารถใช้การเรียกการบันทึก JavaScript มาตรฐาน เช่น console.log และ console.error แทนได้ แต่ก่อนอื่นคุณต้องกำหนดให้โมดูลพิเศษแก้ไขวิธีการมาตรฐานเพื่อให้ทำงานได้อย่างถูกต้อง

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

เมื่อกำหนดให้โมดูลความเข้ากันได้ของ logger แล้ว คุณจะใช้วิธีการ 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 UI หรือผ่านเครื่องมือบรรทัดคำสั่ง 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 คอนโซล ได้

การใช้ UI ของ Cloud Logging

คุณสามารถดูบันทึกสำหรับCloud Functions ใน UI Cloud Logging

การวิเคราะห์บันทึก

Cloud Logging มีชุดเครื่องมือวิเคราะห์บันทึกที่มีประสิทธิภาพซึ่งคุณสามารถ ใช้เพื่อตรวจสอบ Cloud Functions ได้

แผนภูมิและการแจ้งเตือน

เมื่อสร้างเมตริกตามบันทึกเพื่อตรวจสอบฟังก์ชันแล้ว คุณจะสร้างแผนภูมิและการแจ้งเตือนตามเมตริกเหล่านี้ได้ เช่น คุณสามารถสร้างแผนภูมิเพื่อแสดงภาพข้อมูลเวลาในการตอบสนองเมื่อเวลาผ่านไป หรือสร้างการแจ้งเตือนเพื่อแจ้งให้คุณทราบหากเกิดข้อผิดพลาดบางอย่างบ่อยเกินไป

ดูข้อมูลโดยละเอียดเกี่ยวกับวิธีใช้เมตริกตามบันทึกในแผนภูมิและนโยบายการแจ้งเตือนได้ที่การสร้างแผนภูมิและการแจ้งเตือน

ทำความเข้าใจและใช้รหัสการดำเนินการ

โดยค่าเริ่มต้น ฟังก์ชัน Cloud Run (รุ่นที่ 2) รองรับการดำเนินการคำขอหลายรายการพร้อมกันภายในอินสแตนซ์ฟังก์ชันเดียว ซึ่งหมายความว่าบันทึกจากคำขอต่างๆ อาจมีการสลับกัน ทำให้ติดตามโฟลว์ของการดำเนินการเดียวได้ยากขึ้น

เพื่อช่วยในเรื่องนี้ ฟังก์ชันที่ติดตั้งใช้งานโดยใช้ Firebase CLI เวอร์ชัน 13.33.0 ขึ้นไปจะติดตั้งใช้งานโดยอัตโนมัติพร้อมตัวเลือกในการเชื่อมโยงรหัสการดำเนินการกับรายการบันทึกแต่ละรายการที่ปล่อยออกมาในระหว่างการจัดการการดำเนินการนั้น

รหัสการดำเนินการจะระบุบันทึกทั้งหมดที่เชื่อมโยงกับคำขอเดียวที่ฟังก์ชันจัดการโดยไม่ซ้ำกัน คุณไม่จำเป็นต้องเปลี่ยนแปลงโค้ด โดยระบบจะเพิ่มรหัสการดำเนินการลงในบันทึกโดยอัตโนมัติ

หากต้องการปิดใช้รหัสการดำเนินการบันทึกในรายการบันทึก ให้ตั้งค่า ตัวแปรสภาพแวดล้อม LOG_EXECUTION_ID เป็น "false" ในไฟล์ dotenv

ค้นหาและเชื่อมโยงบันทึกตามรหัสการดำเนินการ

คุณสามารถตรวจสอบและเชื่อมโยงบันทึกตามรหัสการดำเนินการใน Cloud Logs Explorer ได้

  1. ขยายรายการบันทึกจากฟังก์ชัน รหัสการดำเนินการจะอยู่ในข้อมูลบันทึกที่มีโครงสร้าง ซึ่งฝังอยู่ภายใต้ป้ายกำกับเป็น labels.execution_id

  2. คลิกค่าของ execution_id แล้วเลือก "แสดงรายการที่ตรงกัน" จากเมนูแบบเลื่อนลงเพื่อดูบันทึกอื่นๆ ทั้งหมดที่เชื่อมโยงกับการดำเนินการฟังก์ชันเดียวกัน

การใช้รหัสการดำเนินการจะช่วยให้คุณจัดกลุ่มข้อความบันทึกทั้งหมดที่เกี่ยวข้องกับคำขอเดียวได้ แม้ว่าฟังก์ชันจะจัดการคำขอหลายรายการพร้อมกันก็ตาม

ปรับปรุงการมองเห็นบันทึกด้วยช่องสรุปที่กำหนดเอง

หากต้องการให้รหัสการดำเนินการมองเห็นได้ง่ายขึ้นใน Logs Explorer คุณสามารถเพิ่มรหัสการดำเนินการเป็น[ช่องสรุปที่กำหนดเอง][cloud-logging-preference]ได้ หลังจากเพิ่ม รหัสการดำเนินการเป็นช่องสรุปแล้ว รายการบันทึกทุกรายการจะแสดงรหัสการดำเนินการเป็น ชิปที่จุดเริ่มต้นของบรรทัดบันทึก ซึ่งคล้ายกับ วิธีที่ฟังก์ชันรุ่นที่ 1 แสดงรหัสการดำเนินการสำหรับรายการบันทึกทั้งหมด

วิธีเพิ่มรหัสการดำเนินการลงในช่องสรุป

  1. คลิกค่าของรหัสการดำเนินการในรายการบันทึกที่มีโครงสร้างภายใต้ labels.execution_id

  2. เลือก "เพิ่มช่องลงในบรรทัดสรุป" จากเมนูแบบเลื่อนลง

ตอนนี้รายการบันทึกแต่ละรายการจะแสดง executionId อย่างชัดเจนในช่องสรุป ซึ่งช่วยให้ระบุและจัดกลุ่มบันทึกที่เชื่อมโยงกับรหัสการดำเนินการที่เฉพาะเจาะจงได้ง่ายขึ้น