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

求支持同步日志写入的日志库?Winston进程退出时日志丢失问题

解决Winston捕获uncaughtException后日志丢失的问题

Winston默认异步写入日志,直接调用process.exit(1)会跳过日志写入流程,导致日志丢失。以下是几种可靠的解决方式,兼顾日志完整性和进程退出效率:

方案1:利用finish事件+超时兜底

Winston的日志实例在所有transport完成写入后会触发finish事件,我们可以先终止日志写入流,等待事件触发后再退出进程,同时加超时防止进程无限挂起:

process.once("uncaughtException", (err) => {
  // 写入异常日志
  logger.error(err);
  // 终止日志实例的写入流,触发后续finish事件
  logger.end();
  // 等待所有日志写入完成后退出
  logger.once("finish", () => {
    process.exit(1);
  });
  // 超时兜底:500ms内未完成则强制退出(可根据实际场景调整时长)
  setTimeout(() => {
    process.exit(1);
  }, 500);
});

方案2:使用日志方法的回调参数

Winston的error()等日志方法支持传入回调函数,回调触发时表示该条日志已完成写入,基于此可以控制进程退出时机:

process.once("uncaughtException", (err) => {
  logger.error(err, () => {
    // 单条日志写入完成后退出
    process.exit(1);
  });
  // 同样添加超时兜底,避免回调因异常未触发
  setTimeout(() => {
    process.exit(1);
  }, 500);
});

方案3:Winston 3.x+ 用close()方法(Promise方式)

Winston 3.x及以上版本提供了logger.close()方法,它会返回一个Promise,等待所有transport关闭完成后resolve,适合用async/await写法:

process.once("uncaughtException", async (err) => {
  try {
    // 写入异常日志
    logger.error(err);
    // 等待所有transport关闭(即日志写入完成)
    await logger.close();
    process.exit(1);
  } catch (closeErr) {
    // 捕获关闭日志实例时的异常,避免进程挂起
    console.error('日志实例关闭失败:', closeErr);
    process.exit(1);
  }
  // 超时兜底
  setTimeout(() => {
    process.exit(1);
  }, 500);
});

关键注意事项

  • 不要省略超时兜底:如果日志transport出现异常(比如远程日志服务不可达),可能导致finish事件或回调永远不触发,超时能保证进程最终退出。
  • 超时时长需根据实际场景调整:本地文件写入可设200-500ms,远程日志服务可能需要1-2s。
  • 优先使用process.once绑定uncaughtException:避免多次绑定导致重复处理异常。

内容的提问来源于stack exchange,提问作者whowhenhow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 15:15:10