Zapisywanie i wyświetlanie logów

Logowanie to ważne narzędzie do debugowania i monitorowania kodu. Cloud Functions umożliwia korzystanie z pakietu SDK rejestratora w przypadku Node.js lub Pythona albo standardowego obiektu console do tworzenia aplikacji internetowych.

Cloud Logging to usługa płatna. Jeśli przekroczysz bezpłatny limit, możesz otrzymać rachunek. Więcej informacji znajdziesz w cenniku Cloud Logging.

Pisanie dzienników

Korzystanie z pakietu SDK rejestratora Cloud Functions

Pakiet SDK rejestratora Cloud Functions udostępnia standardowy interfejs do przekazywania stanu funkcji do Cloud Logging. Za pomocą tego pakietu SDK możesz rejestrować zdarzenia z danymi strukturalnymi, co ułatwia analizowanie i monitorowanie.

Importowanie z podpakietu logger:

Node.js

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

Python

from firebase_functions import logger
  • Polecenia logger.log() mają poziom rejestrowania INFO.

  • Polecenia logger.info() mają poziom rejestrowania INFO.

  • Polecenia logger.warn() mają poziom logu WARNING.

  • Polecenia logger.error() mają poziom logu ERROR.

  • Polecenia logger.debug() mają poziom logu DEBUG.

  • Wewnętrzne wiadomości systemowe mają poziom dziennika DEBUG.

Ten przykład pokazuje funkcję zapisującą podstawowy log:

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

Używaj różnych poziomów logowania dla różnych typów logów w kodzie funkcji. Uporządkowane dane można dołączyć do logu jako ostatni argument. Oto przykład, jak funkcja może używać poszczególnych typów logów:

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

Za pomocą logger.write() możesz pisać wpisy logu z dodatkowymi poziomami ważności logu: CRITICAL, ALERTEMERGENCY. Zobacz 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)

Jak korzystać z aplikacji console.log

Zalecanym rozwiązaniem do rejestrowania danych z funkcji jest używanie pakietu SDK rejestratora na Twojej platformie. W Node.js możesz zamiast tego używać standardowych wywołań logowania w JavaScript, takich jak console.logconsole.error, ale najpierw musisz zażądać specjalnego modułu, aby poprawić standardowe metody i zapewnić ich prawidłowe działanie:

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

Po zażądaniu modułu zgodności rejestratora możesz używać metod console.log() w kodzie w normalny sposób:

exports.helloError = functions.https.onRequest((request, response) => {
  console.log('I am a log entry!');
  response.send('Hello World...');
});
  • Polecenia console.log() mają poziom rejestrowania INFO.
  • Polecenia console.info() mają poziom rejestrowania INFO.
  • Polecenia console.warn() mają poziom logu ERROR.
  • Polecenia console.error() mają poziom logu ERROR.
  • Wewnętrzne wiadomości systemowe mają poziom dziennika DEBUG.

Wyświetlanie logów

Logi Cloud Functions można wyświetlać w Google Cloudkonsoli,Cloud Logging interfejsie lub za pomocą narzędzia wiersza poleceń firebase.

Korzystanie z wiersza poleceń Firebase

Aby wyświetlić logi za pomocą narzędzia firebase, użyj polecenia functions:log:

firebase functions:log

Aby wyświetlić logi dotyczące konkretnej funkcji, podaj jej nazwę jako argument:

firebase functions:log --only <FUNCTION_NAME>

Pełny zakres opcji wyświetlania logów znajdziesz w pomocy dotyczącej functions:log:

firebase help functions:log

Korzystanie z konsoli Google Cloud

Logi funkcji możesz wyświetlać w Google Cloudkonsoli.

Korzystanie z interfejsu Cloud Logging

Logi Cloud Functions możesz wyświetlać w interfejsie Cloud Logging.

Analizowanie logów

Cloud Logging oferuje zaawansowany zestaw narzędzi do analizy logów, których możesz używać do monitorowania Cloud Functions.

Wykresy i alerty

Po utworzeniu wskaźników opartych na logach do monitorowania funkcji możesz tworzyć wykresy i alerty na podstawie tych wskaźników. Możesz na przykład utworzyć wykres, aby wizualizować opóźnienie w czasie, lub utworzyć alert, który będzie Cię informować, czy określony błąd występuje zbyt często.

Szczegółowe informacje o tym, jak używać wskaźników opartych na logach na wykresach i w zasadach alertów, znajdziesz w artykule Tworzenie wykresów i alertów.

Zrozumienie i używanie identyfikatorów wykonania

Domyślnie funkcje Cloud Run (2 generacji) obsługują równoczesne wykonywanie wielu żądań w ramach jednej instancji funkcji. Oznacza to, że dzienniki z różnych żądań mogą być przeplatane, co utrudnia śledzenie przebiegu pojedynczego wykonania.

Aby to ułatwić, funkcje wdrażane za pomocą wiersza poleceń Firebase w wersji 13.33.0 i nowszych są automatycznie wdrażane z opcją powiązania identyfikatora wykonania z każdym wpisem w logu wygenerowanym podczas obsługi tego wykonania.

Identyfikator wykonania jednoznacznie identyfikuje wszystkie logi powiązane z pojedynczym żądaniem obsługiwanym przez funkcję. Nie musisz wprowadzać żadnych zmian w kodzie. Identyfikator wykonania zostanie automatycznie dodany do Twoich logów.

Aby wyłączyć rejestrowanie identyfikatora wykonania w swoich wpisach w logu, ustaw zmienną środowiskową LOG_EXECUTION_ID na wartość false w pliku dotenv.

Znajdowanie i korelacja logów według identyfikatora wykonania

W eksploratorze logów Cloud możesz sprawdzać i korelować logi według identyfikatora wykonania.

  1. Rozwiń wpis logu z funkcji. Identyfikator wykonania znajduje się w danych dziennika strukturalnego, zagnieżdżonych pod etykietami jako labels.execution_id.

  2. Kliknij wartość execution_id i w menu wybierz „Pokaż pasujące wpisy”, aby wyświetlić wszystkie inne logi powiązane z tym samym wykonaniem funkcji.

Używając identyfikatora wykonania, możesz grupować wszystkie komunikaty dziennika związane z jednym żądaniem, nawet jeśli funkcja obsługuje wiele żądań jednocześnie.

Zwiększanie widoczności logów za pomocą niestandardowych pól podsumowania

Aby identyfikator wykonania był lepiej widoczny w Eksploratorze logów, możesz dodać go jako [niestandardowe pole podsumowania][cloud-logging-preference]. Po dodaniu identyfikatora wykonania jako pola podsumowania każdy wpis logu będzie zawierać identyfikator wykonania jako element na początku wiersza logu, podobnie jak funkcje 1 generacji wyświetlały identyfikator wykonania dla wszystkich wpisów logu.

Aby dodać identyfikator wykonania do pola podsumowania:

  1. W strukturalnym wpisie dziennika kliknij wartość identyfikatora wykonania w sekcjilabels.execution_id.

  2. Z menu wybierz „Dodaj pole do wiersza podsumowania”.

W przypadku każdego wpisu w dzienniku w polu podsumowania jest teraz wyraźnie widoczny symbol executionId, co ułatwia identyfikowanie i grupowanie dzienników powiązanych z określonym identyfikatorem wykonania.