如何使用using关键字实现自动写入文件的单子式日志函数
GCP云函数本地日志自动写入实现方案(基于using上下文管理器)
需求背景
- 为GCP云函数实现本地日志功能,将日志写入
.log文件用于本地调试 - 现有
wrapLogs函数需手动调用done()完成日志写入,易因遗忘导致日志丢失,需通过using上下文管理器+Symbol.dispose实现自动写入
解决方案实现
1. 实现支持自动释放的本地日志类
利用Symbol.dispose钩子,在代码块结束时自动触发日志写入:
import fs from 'fs'; import path from 'path'; class LocalLogger { #logEntries = []; #logFilePath; constructor(logFileName = 'cloud-function.log') { this.#logFilePath = path.resolve(process.cwd(), logFileName); // 初始化日志文件(不存在则创建) if (!fs.existsSync(this.#logFilePath)) { fs.writeFileSync(this.#logFilePath, '', 'utf8'); } } // 模拟GCP日志info方法 info(message, metadata = {}) { this.#logEntries.push({ level: 'INFO', timestamp: new Date().toISOString(), message, metadata }); } // 模拟GCP日志error方法 error(message, metadata = {}) { this.#logEntries.push({ level: 'ERROR', timestamp: new Date().toISOString(), message, metadata }); } // 自动触发的释放钩子,完成日志写入 [Symbol.dispose]() { if (this.#logEntries.length === 0) return; // 将缓存的日志条目追加写入文件 const logContent = this.#logEntries.map(entry => JSON.stringify(entry)).join('\n') + '\n'; fs.appendFileSync(this.#logFilePath, logContent, 'utf8'); this.#logEntries = []; } }
2. 在云函数中使用using关键字
代码块执行完毕(无论正常结束还是异常抛出),会自动调用Symbol.dispose完成日志写入:
// 云函数入口示例 export const myCloudFunction = async (req, res) => { using logger = new LocalLogger(); try { logger.info('云函数启动', { path: req.path, method: req.method }); // 业务逻辑代码 const result = await someBusinessLogic(); logger.info('业务执行成功', { result }); res.status(200).send('Success'); } catch (err) { logger.error('业务执行失败', { error: err.message, stack: err.stack }); res.status(500).send('Error'); } };
3. 异步写入优化(针对大日志量场景)
如果日志量较大,建议使用异步写入,此时需替换为Symbol.asyncDispose并配合await using:
// 修改日志类的释放钩子 [Symbol.asyncDispose]() { if (this.#logEntries.length === 0) return Promise.resolve(); const logContent = this.#logEntries.map(entry => JSON.stringify(entry)).join('\n') + '\n'; return fs.promises.appendFile(this.#logFilePath, logContent, 'utf8') .then(() => { this.#logEntries = []; }); } // 云函数中使用方式 export const myCloudFunction = async (req, res) => { await using logger = new LocalLogger(); // 后续业务逻辑不变 };
关键注意事项
- 确保Node.js版本支持
using语法(Node.js 18.11+ 或 16.17+),低版本可通过Babel转译兼容 - 日志类封装了GCP日志常用方法,原有业务代码的日志调用逻辑无需修改
内容的提问来源于stack exchange,提问作者liminor
相关产品推荐
相关产品推荐

