Ведение журналов – важный инструмент для отладки и мониторинга кода.
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, интерфейсе Cloud Logging или с помощью инструмента командной строки firebase.
Использование интерфейса командной строки Firebase
Чтобы посмотреть журналы с помощью инструмента 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 версии 13.33.0 и более поздних, автоматически развертываются с возможностью связывания идентификатора выполнения с каждой записью в журнале, созданной во время обработки этого выполнения.
Идентификатор выполнения уникально идентифицирует все журналы, связанные с одним запросом, обрабатываемым вашей функцией. Изменять код не нужно – идентификатор выполнения будет автоматически добавлен в журналы.
Чтобы отключить регистрацию идентификатора выполнения в записях журнала, задайте для переменной среды LOG_EXECUTION_ID значение false в файле dotenv.
Как найти и сопоставить журналы по идентификатору выполнения
Вы можете проверять и сопоставлять журналы по идентификатору выполнения в Cloud Logs Explorer.
Разверните запись в журнале функции. Идентификатор выполнения находится в структурированных данных журнала, вложенных в ярлыки как
labels.execution_id.Нажмите на значение
execution_idи в раскрывающемся меню выберите "Показать совпадающие записи", чтобы посмотреть все остальные журналы, связанные с выполнением этой функции.
С помощью идентификатора выполнения можно сгруппировать все сообщения в журнале, связанные с одним запросом, даже если функция обрабатывает несколько запросов одновременно.
Как улучшить видимость журналов с помощью настраиваемых полей сводки
Чтобы идентификатор выполнения было проще найти в Logs Explorer, вы можете добавить его в качестве [пользовательского поля сводки][cloud-logging-preference]. После того как вы добавите идентификатор выполнения в качестве поля сводки, каждая запись в журнале будет отображать идентификатор выполнения в виде чипа в начале строки журнала, как это было в функциях первого поколения.
Чтобы добавить идентификатор выполнения в поле сводки:
Нажмите на значение идентификатора выполнения в структурированной записи в журнале в разделе
labels.execution_id.В раскрывающемся меню выберите "Добавить поле в строку сводки".
Теперь в каждой записи журнала в поле сводки на видном месте отображается executionId, что упрощает идентификацию и группировку журналов, связанных с определенным идентификатором выполнения.