Cloud Functions部署后日志探索器无法查看日志求助
Cloud Functions部署后日志无显示问题排查与解决方案
问题描述
此前部署Cloud Functions时,日志探索器可正常查看所有日志。为解决业务错误引入Cloud Tasks SDK创建队列,完成队列配置并部署函数(执行命令firebase deploy --only functions:FUNCTIONS_NAME)后,终端显示部署成功,Firebase控制台也能看到已部署的函数,但点击查看日志无内容;日志探索器「最近」栏能识别到对应函数,进入后仍无任何日志输出。相关JavaScript代码如下:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); const database = admin.firestore(); exports.taskCallback = functions.https .onRequest(async (req, res) => { const {UID} = req.body; const docRef = database.collection("ADSGHANA").doc(UID); const doc = await docRef.get(); if (!doc.exists) { console.log(`Document with UID ${UID} does not exist.`); res.status(404).send("Document not found."); return; } const {TimestampDeparture, PostStatus} = doc.data(); const now = admin.firestore.Timestamp.now(); if (now == TimestampDeparture && PostStatus !== "Cancelled") { await docRef.update({PostStatus: "Started"}); console.log(`Post with UID ${UID} has been started.`); res.status(200).send("Post started successfully."); } else { console.log(`Post with UID ${UID} is not ready to start.`); res.status(200).send("Post not ready to start yet."); } }); exports.scheduledTask = functions.firestore.document("ADSGHANA/{UID}") .onCreate(async (snapshot, context) => { const data = snapshot.data(); const {UID, TimestampDeparture} = data; const now = admin.firestore.Timestamp.now(); if (now == TimestampDeparture) { console.log(`Post with UID ${UID} should have already started.`); return null; } const project = JSON.parse(process.env.FIREBASE_CONFIG).projectId; const location = "us-central1"; const queue = "scheduleAds"; const task = { httpRequest: { httpMethod: "POST", url: `https://${location}/${project}.cloudfunctions.net/taskCallback?UID=${UID}`, body: Buffer.from(JSON.stringify({UID})).toString("base64"), headers: { "Content-Type": "application/json", }, }, scheduleTime: TimestampDeparture, }; const {CloudTasksClient} = require("@google-cloud/tasks"); const client = new CloudTasksClient(); const parent = client.queuePath(project, location, queue); const [response] = await client.createTask({parent, task}); console.log(`Created task ${response.name}`); return null; });
排查思路与解决步骤
1. 检查函数服务账号日志权限
引入Cloud Tasks后,函数运行的默认服务账号(格式为[项目ID]@appspot.gserviceaccount.com)可能丢失日志写入权限:
- 进入Google Cloud控制台的「IAM与管理员」页面
- 找到对应服务账号,确认其拥有
Logging > Logging Writer角色,若没有则添加该角色
2. 调整Cloud Tasks客户端初始化逻辑
代码中将CloudTasksClient的引入和初始化放在函数内部,会导致每次函数调用重复初始化,可能引发异常导致静默失败:
- 将
const {CloudTasksClient} = require("@google-cloud/tasks");移到文件顶部 - 将
const client = new CloudTasksClient();也移到顶部,全局初始化一次
3. 修复Timestamp比较逻辑
原代码中用==比较Firestore Timestamp对象,属于引用比较而非值比较,会导致逻辑判断错误,进而影响日志输出:
- 替换为
now.isEqual(TimestampDeparture)进行时间值比较
4. 添加异常捕获逻辑
原代码未处理异步操作可能抛出的异常,异常会导致函数静默终止且无日志输出:
- 在两个函数的异步逻辑外层添加
try-catch块,捕获并打印错误信息
5. 验证函数触发与调用
- 手动触发
scheduledTask:在Firestore的ADSGHANA集合中创建测试文档,检查是否有日志生成 - 手动调用
taskCallback:用Postman等工具发送POST请求到函数URL,携带UID参数,确认日志是否输出
6. 检查日志过滤规则
日志探索器可能因过滤条件错误导致看不到日志:
- 确认选择了正确的函数名称、时间范围
- 检查是否排除了
INFO/DEBUG级别日志,调整过滤规则为显示所有级别
调整后的示例代码
const functions = require("firebase-functions"); const admin = require("firebase-admin"); const {CloudTasksClient} = require("@google-cloud/tasks"); // 移至顶部全局引入 admin.initializeApp(); const database = admin.firestore(); const client = new CloudTasksClient(); // 全局初始化客户端 exports.taskCallback = functions.https .onRequest(async (req, res) => { try { const {UID} = req.body; if (!UID) { console.log("请求体缺少UID参数"); res.status(400).send("Missing UID parameter"); return; } const docRef = database.collection("ADSGHANA").doc(UID); const doc = await docRef.get(); if (!doc.exists) { console.log(`UID为${UID}的文档不存在`); res.status(404).send("Document not found."); return; } const {TimestampDeparture, PostStatus} = doc.data(); const now = admin.firestore.Timestamp.now(); // 修复Timestamp值比较逻辑 if (now.isEqual(TimestampDeparture) && PostStatus !== "Cancelled") { await docRef.update({PostStatus: "Started"}); console.log(`UID为${UID}的帖子已启动`); res.status(200).send("Post started successfully."); } else { console.log(`UID为${UID}的帖子未到启动时间:当前时间${now.toDate()},出发时间${TimestampDeparture?.toDate()},状态${PostStatus}`); res.status(200).send("Post not ready to start yet."); } } catch (error) { console.error(`taskCallback执行错误:${error.message}`, error); res.status(500).send("Internal server error"); } }); exports.scheduledTask = functions.firestore.document("ADSGHANA/{UID}") .onCreate(async (snapshot, context) => { try { const data = snapshot.data(); const {UID, TimestampDeparture} = data; if (!UID || !TimestampDeparture) { console.log(`文档${context.params.UID}缺少必填字段:UID=${UID}, TimestampDeparture=${TimestampDeparture}`); return null; } const now = admin.firestore.Timestamp.now(); // 修复Timestamp值比较逻辑 if (now.isEqual(TimestampDeparture)) { console.log(`UID为${UID}的帖子应已启动`); return null; } const project = JSON.parse(process.env.FIREBASE_CONFIG).projectId; const location = "us-central1"; const queue = "scheduleAds"; const task = { httpRequest: { httpMethod: "POST", url: `https://${location}/${project}.cloudfunctions.net/taskCallback`, body: Buffer.from(JSON.stringify({UID})).toString("base64"), headers: { "Content-Type": "application/json", }, }, scheduleTime: TimestampDeparture, }; const parent = client.queuePath(project, location, queue); const [response] = await client.createTask({parent, task}); console.log(`为UID${UID}创建任务${response.name},计划执行时间${TimestampDeparture.toDate()}`); return null; } catch (error) { console.error(`scheduledTask执行错误(UID:${context.params.UID}):${error.message}`, error); return null; } });
内容的提问来源于stack exchange,提问作者Eben Oasis
相关产品推荐
相关产品推荐

