You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 09:43:15