日志是用于调试和监控代码的重要工具。Cloud Functions 让您可以选择使用适用于 Node.js 或 Python 的 logger SDK,或是面向 Web 开发的 console 对象标准。
Cloud Logging 是一项收费服务,超出免费配额后,您可能需要付费。如需了解详情,请参阅 Cloud Logging 价格。
写入日志
使用 Cloud Functions logger SDK
Cloud Functions logger SDK 提供了一个标准接口,用于将函数状态报告给 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
使用适用于您平台的 logger SDK 是通过函数进行日志记录的建议解决方案。使用 Node.js 时,您可以改用标准 JavaScript 日志记录调用(如 console.log 和 console.error),但您首先需要使用一个特殊模块来修补标准方法,以使其正常运作:
require("firebase-functions/logger/compat"); 纳入所需的 Logger 兼容性模块后,您可以像往常一样在代码中使用 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 日志级别。
查看日志
您可以在 Google Cloud 控制台、Cloud Logging 界面或通过 firebase 命令行工具查看 Cloud Functions 的日志。
使用 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 Logging 界面中查看 Cloud Functions 的日志。
分析日志
Cloud Logging 提供了一套功能强大的日志分析工具,您可以使用这些工具监控 Cloud Functions。
图表和提醒
创建基于日志的指标以监控您的函数后,您可以根据这些指标创建图表和提醒。例如,您可以创建一个图表来直观呈现指定时间段内的延迟,或创建一个提醒来让您知道某个错误是否出现得过于频繁。
如需详细了解如何在图表和提醒政策中使用基于日志的指标,请参阅创建图表和提醒。
了解和使用执行 ID
默认情况下,Cloud Run functions(第 2 代)支持在单个函数实例中并发执行多个请求。这意味着来自不同请求的日志可能会交错,这会导致更难以跟踪单次执行的流。
为解决此问题,使用 Firebase CLI 13.33.0 版及更高版本部署的函数会自动部署,并提供一个选项,用于将执行 ID 与处理该执行期间发出的每个日志条目相关联。
执行 ID 可唯一标识与您的函数处理的单个请求相关的所有日志。无需更改代码;执行 ID 会自动添加到日志中。
如需停止在日志条目中记录执行 ID,请在 dotenv 文件中将环境变量 LOG_EXECUTION_ID 设为 false。
按执行 ID 查找和关联日志
您可以在 Cloud Logs Explorer 中按执行 ID 检查和关联日志。
展开来自函数的日志条目。执行 ID 位于结构化日志数据中,以
labels.execution_id的形式嵌套在标签下。点击
execution_id的值,从下拉菜单中选择“显示匹配条目”,以查看与该函数执行相关的所有其他日志。
通过使用执行 ID,您可以将与单个请求相关的所有日志消息归为一组,即使函数同时处理多个请求也是如此。
使用自定义摘要字段增强日志可见性
如果想使执行 ID 在 Logs Explorer 中展示得更明显,您可以将其添加为 [自定义摘要字段][cloud-logging-preference]。将执行 ID 添加为摘要字段后,每个日志条目都会在日志行的开头显示内含执行 ID 的条状标签,类似于第 1 代函数为所有日志条目显示执行 ID 的方式。
如需将执行 ID 添加到摘要字段,请执行以下操作:
点击结构化日志条目中
labels.execution_id下的执行 ID 值。从下拉菜单中选择“向摘要行添加字段”。
现在,每个日志条目都会在摘要字段中醒目地显示 executionId,您可以更轻松地识别和分组与特定执行 ID 相关的日志。