كتابة السجلّات وعرضها

تسجيل الأحداث هو أداة مهمة لتصحيح أخطاء الرموز البرمجية ومراقبتها. Cloud Functions تمنحك خيار استخدام حزمة SDK لتسجيل الأحداث في Node.js أو Python، أو استخدام عنصر console العادي للتطوير على الويب.

‫Cloud Logging هي خدمة مدفوعة، وقد يتم تحصيل رسوم منك إذا تجاوزت الحصة المجانية. لمزيد من المعلومات، اطّلِع على أسعار Cloud Logging.

كتابة السجلات

استخدام حزمة SDK لتسجيل الأحداث Cloud Functions

توفر حزمة SDK لتسجيل الأحداث في Cloud Functions واجهة عادية للإبلاغ عن الحالة من الدوال إلى Cloud Logging. يمكنك استخدام حزمة تطوير البرامج (SDK) هذه لتسجيل الأحداث مع بيانات منظَّمة، ما يسهّل عملية التحليل والرصد.

يمكنك الاستيراد من الحزمة الفرعية 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!")

استخدِم مستويات سجلّ مختلفة لأنواع مختلفة من السجلات في رمز الدالة. يمكن إرفاق بيانات منظَّمة بسجلّ كآخر وسيطة. في ما يلي مثال على كيفية استخدام الدالة لكل نوع من أنواع السجلّات:

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

الحلّ المقترَح لتسجيل الأحداث من دالة هو استخدام حزمة SDK لتسجيل الأحداث على منصتك. باستخدام 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 console أو Cloud Logging UI أو من خلال أداة سطر الأوامر firebase.

استخدام Firebase CLI

لعرض السجلّات باستخدام أداة firebase، استخدِم الأمر functions:log:

firebase functions:log

لعرض سجلّات دالة معيّنة، قدِّم اسم الدالة كحجة:

firebase functions:log --only <FUNCTION_NAME>

للاطّلاع على النطاق الكامل لخيارات عرض السجلّات، اطّلِع على تعليمات functions:log:

firebase help functions:log

استخدام ConsoleGoogle Cloud

يمكنك عرض سجلّات الدوال في الـ Google Cloud console.

استخدام واجهة مستخدم Cloud Logging

يمكنك عرض سجلّات Cloud Functions في واجهة المستخدم Cloud Logging.

تحليل السجلات

Cloud Logging تقدّم مجموعة فعّالة من أدوات تحليل السجلّات التي يمكنك استخدامها لمراقبة Cloud Functions.

المخططات والتنبيهات

بعد إنشاء مقاييس مستندة إلى السجلّات لمراقبة الدوال، يمكنك إنشاء مخططات وتنبيهات استنادًا إلى هذه المقاييس. على سبيل المثال، يمكنك إنشاء رسم بياني لتصوُّر وقت الاستجابة بمرور الوقت، أو إنشاء تنبيه لإعلامك إذا حدث خطأ معيّن بشكل متكرّر.

لمعرفة معلومات مفصّلة حول كيفية استخدام المقاييس المستندة إلى السجلّات في المخططات وسياسات التنبيهات، اطّلِع على إنشاء المخططات والتنبيهات.

التعرّف على معرّفات التنفيذ واستخدامها

تتيح دوال Cloud Run (الجيل الثاني) بشكلٍ تلقائي التنفيذ المتزامن لطلبات متعدّدة ضمن مثيل دالة واحد. هذا يعني أنّه يمكن أن تتداخل السجلّات من طلبات مختلفة، ما يصعّب تتبُّع سير تنفيذ واحد.

للمساعدة في ذلك، يتم تلقائيًا تفعيل الدوال التي يتم تفعيلها باستخدام الإصدار 13.33.0 والإصدارات الأحدث من Firebase CLI مع خيار ربط معرّف تنفيذ بكل إدخال في السجلّ يتم إصداره أثناء معالجة هذا التنفيذ.

يحدّد معرّف التنفيذ بشكلٍ فريد جميع السجلّات المرتبطة بطلب واحد تعالجه الدالة. لا يُطلب إجراء أي تغييرات على الرموز البرمجية، وسيتم تلقائيًا إضافة معرّف التنفيذ إلى السجلّات.

لإيقاف معرّف تنفيذ تسجيل الأحداث في إدخالات السجلّ، اضبط الـ متغيّر البيئة LOG_EXECUTION_ID على "false" في ملف ‎.env.

العثور على السجلّات وربطها حسب معرّف التنفيذ

يمكنك فحص السجلّات وربطها حسب معرّف التنفيذ في مستكشف سجلّات Cloud.

  1. وسِّع إدخال في السجلّ من الدالة. يقع معرّف التنفيذ ضمن بيانات السجلّ المنظَّمة، والمضمّنة ضمن التصنيفات كـ labels.execution_id.

  2. انقر على قيمة execution_id واختَر "عرض الإدخالات المطابقة" من القائمة المنسدلة للاطّلاع على جميع السجلّات الأخرى المرتبطة بتنفيذ الدالة نفسه.

باستخدام معرّف التنفيذ، يمكنك تجميع كل رسائل السجلّ المرتبطة بطلب واحد، حتى إذا كانت الدالة تعالج طلبات متعدّدة في وقت واحد.

تحسين مدى ظهور السجلّات باستخدام حقول الملخّص المخصّصة

لجعل معرّف التنفيذ أكثر وضوحًا في مستكشف السجلّات، يمكنك إضافته كـ [حقل ملخّص مخصّص][cloud-logging-preference]. بعد إضافة معرّف التنفيذ كحقل ملخّص، سيظهر معرّف التنفيذ كـ شريحة في بداية سطر السجلّ لكل إدخال في السجلّ، على غرار الطريقة التي كانت تعرض بها دوال الجيل الأول معرّف التنفيذ لجميع إدخالات في السجلّ.

لإضافة معرّف التنفيذ إلى حقل الملخّص:

  1. انقر على قيمة معرّف التنفيذ في إدخال السجلّ المنظَّم ضمن labels.execution_id.

  2. انقر على "إضافة حقل إلى سطر الملخّص" من القائمة المنسدلة.

يعرض كل إدخال في السجلّ الآن executionId بشكلٍ بارز في حقل الملخّص، ما يسهّل تحديد السجلّات المرتبطة بمعرّف تنفيذ معيّن وتجميعها.