预运行环境变量检查时Winston日志文件未生成问题排查
我有一个使用Winston和winston-daily-rotate-file的TypeScript项目,日志器和环境变量检查函数来自自定义npm模块node_modules/my-custom-project/util/logger.ts。项目启动时会检查环境变量是否存在,若缺失则通过logger.error()记录错误,但错误日志文件始终未生成,仅能在控制台看到日志输出;而当环境变量齐全时,检查函数执行后调用logger.info()则日志文件生成正常。
控制台输出如下:
yarn run v1.22.19 $ ts-node src/index.ts Debugger attached. info: Starting project Test {"timestamp":"2023-01-19T07:49:53.342Z","type":"start-project"} error: Missing environment variable DEFAULT_REQUIRED_VARIABLE {"timestamp":"2023-01-19T07:49:53.348Z"} error: Exiting because of missing environment variables {"data":["DEFAULT_REQUIRED_VARIABLE"],"timestamp":"2023-01-19T07:50:05.447Z"}
我已尝试:
- 将自定义模块中的
logger.ts和requireEnvironmentVariables.ts移至本地项目; - 在检查变量前调用
logger.info(),仍未生成日志文件; - 尝试使用Winston的
logger.on('finish')监听事件,但日志仍未生成,且info参数为undefined。
核心问题是进程退出速度过快,Winston的文件传输器尚未完成异步写入操作,进程就已终止。当环境变量缺失时,程序会直接执行退出逻辑,而Winston的文件日志写入是异步的,此时写入任务还没来得及完成,导致日志文件无法生成;而环境变量齐全时,程序会继续运行,给了Winston足够的时间完成文件写入。
1. 等待Winston完成日志写入后再退出进程
Winston 3.x提供了logger.close()方法,会关闭所有传输器并等待所有待处理的日志写入完成。你可以在触发退出前调用该方法,并在其回调中执行进程退出:
// 在环境变量检查失败的逻辑中 logger.error('Exiting because of missing environment variables', { data: missingVars }); // 等待日志写入完成后退出 logger.close(() => { process.exit(1); });
如果使用Winston 2.x,对应方法为logger.end(),用法一致。
2. 监听finish事件并在事件触发后退出
需要先调用logger.end()触发finish事件,再在事件回调中执行退出:
logger.error('Exiting because of missing environment variables', { data: missingVars }); logger.on('finish', () => { process.exit(1); }); // 触发finish事件,通知Winston结束日志流 logger.end();
注意:仅监听finish而不调用logger.end()的话,事件不会触发,因为Winston默认不会主动结束日志流。
3. 临时启用同步写入(不推荐生产环境)
如果异步方案仍有问题,可以临时在Winston文件传输器配置中开启同步写入,确保日志在进程退出前完成写入:
// logger.ts中的文件传输器配置 new DailyRotateFile({ // 其他原有配置 sync: true // 开启同步写入 })
该方案会影响性能,仅建议用于调试或启动阶段的关键错误日志,不适合生产环境长期使用。
4. 确认logger初始化时机
确保logger在环境变量检查前已经完全初始化完成。比如避免在logger初始化的异步操作完成前调用日志方法,可以将logger初始化改为同步逻辑,或者用Promise包裹初始化流程,等待初始化完成后再执行环境变量检查。
内容的提问来源于stack exchange,提问作者HotFix

