Логирование — важный инструмент для отладки и мониторинга кода. 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");
Питон
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!");
});
Питон
@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});
});
Питон
@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,
});
});
Питон
@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 logger для вашей платформы. С 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 CLI
Для просмотра журналов с помощью инструмента 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 (2-го поколения) поддерживают одновременное выполнение нескольких запросов в одном экземпляре функции. Это означает, что журналы из разных запросов могут перемежаться, что затрудняет отслеживание потока одного выполнения.
Чтобы помочь в этом, функции, развернутые с помощью Firebase CLI версии 13.33.0 и более поздних версий, автоматически развертываются с возможностью связывания идентификатора выполнения с каждой записью журнала, созданной во время обработки этого выполнения.
Идентификатор выполнения однозначно идентифицирует все журналы, связанные с одним запросом, обработанным вашей функцией. Изменения кода не требуются; идентификатор выполнения будет автоматически добавлен в ваши журналы.
Чтобы отключить регистрацию идентификатора выполнения в записях журнала, установите для переменной среды LOG_EXECUTION_ID
значение false в файле dotenv.
Найти и сопоставить журналы по идентификатору выполнения
Вы можете проверять и сопоставлять журналы по идентификатору выполнения в Cloud Logs Explorer.
Разверните запись журнала из вашей функции. Идентификатор выполнения находится в структурированных данных журнала, вложенных под метками как
labels.execution_id
.Щелкните значение
execution_id
и выберите «Показать соответствующие записи» в раскрывающемся меню, чтобы увидеть все остальные журналы, связанные с выполнением этой же функции.
Используя идентификатор выполнения, вы можете сгруппировать все сообщения журнала, относящиеся к одному запросу, даже если ваша функция обрабатывает несколько запросов одновременно.
Улучшите видимость журнала с помощью настраиваемых полей сводки
Чтобы сделать идентификатор выполнения более заметным в Logs Explorer, вы можете добавить его как пользовательское поле сводки . Это отобразит идентификатор выполнения как чип в начале каждой строки записи журнала, аналогично тому, как функции 1-го поколения отображали идентификатор выполнения для всех записей журнала.
Чтобы добавить идентификатор выполнения в поле сводки:
Щелкните значение идентификатора выполнения в структурированной записи журнала под
labels.execution_id
.В раскрывающемся меню выберите «Добавить поле в строку сводки».
Теперь в каждой записи журнала отображается executionId
в поле сводки, что упрощает идентификацию и группировку журналов, связанных с определенным идентификатором выполнения.