Zapisywanie i wyświetlanie logów


Logowanie to ważne narzędzie do debugowania i monitorowania kodu. Cloud Functions umożliwia użycie pakietu SDK rejestratora dla Node.js lub Pythona albo standardu obiektu console do tworzenia aplikacji internetowych.

Cloud Logging to płatna usługa. Jeśli przekroczysz limit bezpłatnych logów, możesz zostać obciążony opłatą. Więcej informacji znajdziesz w cenniku Cloud Logging.

Dzienniki pisania

Korzystanie z poziomu pakietu SDK do rejestrowania zdarzeń Cloud Functions

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

Importowanie z podkategorii logger:

Node.jsPython
// All available logging functions
const {
  log,
  info,
  debug,
  warn,
  error,
  write,
} = require("firebase-functions/logger");
from firebase_functions import logger
  • Polecenia logger.log() mają poziom rejestrowania INFO.

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

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

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

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

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

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

Node.jsPython
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!")

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

Node.jsPython
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!")

Za pomocą logger.write() możesz zapisywać wpisy w logu z dodatkowymi poziomami ważności CRITICAL, ALERTEMERGENCY. Zobacz Poważność logów.

Node.jsPython
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)

Jak korzystać z aplikacji console.log

Zalecane rozwiązanie do rejestrowania danych z funkcji to użycie pakietu SDK rejestratora dla danej platformy. W Node.js możesz zamiast tego używać standardowych wywołań logowania JavaScript, takich jak console.log i console.error, ale najpierw musisz wymagać specjalnego modułu, aby standardowe metody działały prawidłowo:

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

Gdy wymagany moduł zgodności z rejestratorem jest już dostępny, możesz używać metod console.log() w kodu w zwykły 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 logowania ERROR.
  • Polecenia console.error() mają poziom logowania ERROR.
  • Wewnętrzne wiadomości systemowe mają poziom logowania DEBUG.

Wyświetlanie logów

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

Korzystanie z wiersza poleceń Firebase

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

firebase functions:log

Aby wyświetlić dzienniki 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 konsoli Google Cloud.

Korzystanie z interfejsu Cloud Logging

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

Analizowanie logów

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

Wykresy i alerty

Po utworzeniu wskaźników opartych na logach, które służą do monitorowania funkcji, możesz tworzyć wykresy i alerty na ich podstawie. Możesz na przykład utworzyć wykres, aby zobrazować opóźnienie w czasie, lub alert, który poinformuje Cię, jeśli określony błąd wystąpi zbyt często.

Szczegółowe informacje o używaniu wskaźników opartych na logach w wykresach i zasadach tworzenia alertów znajdziesz w artykule Tworzenie wykresów i alertów.

Identyfikatory wykonania

Domyślnie funkcje Cloud Run (2 generacji) obsługują jednoczesne 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 ułatwić Ci to zadanie, funkcje wdrażane za pomocą wiersza poleceń Firebase w wersji 13.33.0 lub nowszej są wdrażane automatycznie z opcją powiązania identyfikatora wykonania z każdym wpisem w logach wyemitowanym podczas obsługi tego wykonania.

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

Aby wyłączyć rejestrowanie identyfikatora wykonania w rekordach logowania, ustaw zmienną środowiskową LOG_EXECUTION_ID w pliku dotenv na „false”.

Znajdowanie i porównywanie logów według identyfikatora wykonania

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

  1. Rozwiń wpis logu z Twojej funkcji. Identyfikator wykonania znajduje się w uporządkowanych danych dziennika, zagnieżdżony pod etykietami jako labels.execution_id.

  2. Kliknij wartość execution_id i w menu kliknij „Pokaż pasujące wpisy”, aby wyświetlić wszystkie inne dzienniki powiązane z tą samą funkcją.

Za pomocą identyfikatora wykonania możesz grupować wszystkie komunikaty logowania związane z pojedynczym żądaniem, nawet jeśli funkcja obsługuje wiele żądań jednocześnie.

Zwiększanie widoczności logów dzięki niestandardowym polom podsumowania

Aby identyfikator wykonania był lepiej widoczny w Eksploratorze logów, możesz dodać go jako niestandardowe pole podsumowania. Identyfikator wykonania jest wyświetlany jako element na początku każdej linii wpisu w dzienniku, podobnie jak w przypadku funkcji 1 generacji, które wyświetlały identyfikator wykonania dla wszystkich wpisów w dzienniku.

Aby dodać identyfikator wykonania do pola podsumowania:

  1. Kliknij wartość identyfikatora wykonania w zapisie dziennika ustrukturyzowanego w sekcji labels.execution_id.

  2. W menu kliknij „Dodaj pole do wiersza podsumowania”.

W każdym wpisie w logu w polu podsumowania wyświetlany jest teraz wyraźnie parametr executionId, dzięki czemu łatwiej jest rozpoznawać i grupować dzienniki powiązane z konkretnym identyfikatorem wykonania.