Ведение журнала — важный инструмент для отладки и мониторинга кода. Cloud Functions дает вам возможность использовать SDK средства ведения журнала для Node.js или Python или стандарт объекта console
для веб-разработки.
Облачная регистрация — платная услуга; вам может быть выставлен счет, если вы превысите бесплатную квоту. Дополнительную информацию см. в разделе Цены на ведение журналов в облаке .
Запись журналов
Использование SDK регистратора Cloud Functions
SDK для ведения журнала Cloud Functions предоставляет стандартный интерфейс для сообщения о состоянии функций в Cloud Logging. Вы можете использовать этот SDK для регистрации событий со структурированными данными , что упрощает анализ и мониторинг.
Импортируйте из подпакета logger
:
// 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()
имеют уровень журнала ПРЕДУПРЕЖДЕНИЕ .Команды
logger.error()
имеют уровень журнала ERROR .Команды
logger.debug()
имеют уровень журнала DEBUG .Внутренние системные сообщения имеют уровень журнала DEBUG .
В этом примере демонстрируется функция, записывающая базовый журнал:
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!")
Используйте разные уровни журналирования для разных типов журналов в коде функции. Структурированные данные можно прикрепить к журналу в качестве последнего аргумента. Вот пример того, как функция может использовать каждый тип журнала:
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 .
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 средства ведения журнала для вашей платформы. Вместо этого с 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 (2-го поколения) поддерживают одновременное выполнение нескольких запросов в одном экземпляре функции. Это означает, что журналы разных запросов могут чередоваться, что затрудняет отслеживание потока одного выполнения.
Чтобы помочь в этом, функции, развернутые с помощью Firebase CLI версии 13.33.0 и более поздних версий, автоматически развертываются с возможностью связать идентификатор выполнения с каждой записью журнала, созданной во время обработки этого выполнения.
Идентификатор выполнения уникальным образом идентифицирует все журналы, связанные с одним запросом, обрабатываемым вашей функцией. Никаких изменений кода не требуется; идентификатор выполнения будет автоматически добавлен в ваши журналы.
Чтобы отключить идентификатор выполнения журнала в записях журнала, установите для переменной среды LOG_EXECUTION_ID
значение false в файле dotenv.
Найдите и сопоставьте журналы по идентификатору выполнения.
Вы можете проверять и сопоставлять журналы по идентификатору выполнения в Cloud Logs Explorer.
Разверните запись журнала из вашей функции. Идентификатор выполнения находится в структурированных данных журнала, вложенных в метки как
labels.execution_id
.Щелкните значение
execution_id
и выберите «Показать соответствующие записи» в раскрывающемся меню, чтобы просмотреть все другие журналы, связанные с выполнением этой же функции.
Используя идентификатор выполнения, вы можете сгруппировать все сообщения журнала, относящиеся к одному запросу, даже если ваша функция обрабатывает несколько запросов одновременно.
Улучшите видимость журнала с помощью настраиваемых полей сводки.
Чтобы сделать идентификатор выполнения более видимым в обозревателе журналов, вы можете добавить его как настраиваемое поле сводки . При этом идентификатор выполнения отображается в виде чипа в начале каждой строки записи журнала, аналогично тому, как функции 1-го поколения отображали идентификатор выполнения для всех записей журнала.
Чтобы добавить идентификатор выполнения в поле сводки:
Щелкните значение идентификатора выполнения в структурированной записи журнала в разделе
labels.execution_id
.В раскрывающемся меню выберите «Добавить поле в итоговую строку».
Каждая запись журнала теперь отображает executionId
на видном месте в поле сводки, что упрощает идентификацию и группировку журналов, связанных с конкретным идентификатором выполнения.