生产环境如何根据日志级别动态控制输出?

文雅 阅读 26

最近在给公司项目做日志分级优化,想让开发环境输出所有日志,测试环境只留warn和error,生产环境只显示error。但按照网上的方法用process.env.NODE_ENV包裹console语句后,发现代码里到处都是这种判断,维护起来好麻烦。

尝试封装了个log工具类,用switch处理日志级别,但遇到个问题:if (level >= currentEnvLevel) { console.log(...args) }这种写法在生产环境遇到bug时,连错误堆栈都被过滤掉了。有没有更好的分级策略,既能按环境动态开关,又能保留关键错误信息?

附上现在混乱的代码:

export const log = (level, ...args) => {
  const levels = { error: 3, warn: 2, info: 1 };
  const envLevel = process.env.LOG_LEVEL || 'info';
  if (levels[level] >= levels[envLevel]) {
    switch(level) {
      case 'error': console.error(...args); break;
      case 'warn': console.warn(...args); break;
      default: console.log(...args);
    }
  }
};

但发现当生产环境设置LOG_LEVEL=error时,意外捕获到的错误会因为没有调用log工具而直接输出,这该怎么统一管理?

我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
一子硕
一子硕 Lv1
要解决这个问题,得从两个层面入手:一是动态控制日志输出,二是确保关键错误信息不被遗漏。直接上方案。

首先封装一个更高效的log工具类,核心是通过环境变量控制日志级别,并且保留对未捕获异常的处理。代码如下:

const levels = { error: 3, warn: 2, info: 1, debug: 0 };
const currentLevel = levels[process.env.LOG_LEVEL || 'info'] || levels.info;

export const log = (level, ...args) => {
const levelValue = levels[level];
if (levelValue >= currentLevel) {
const logger = console[level] || console.log;
logger(...args);
}
};

// 捕获未处理的异常和Promise错误
const originalConsoleError = console.error;
console.error = (...args) => {
originalConsoleError(...args);
if (currentLevel <= levels.error) {
// 确保生产环境依然能记录错误堆栈
process.stderr.write(args.map(arg => typeof arg === 'string' ? arg : JSON.stringify(arg)).join(' ') + 'n');
}
};

process.on('uncaughtException', err => {
if (currentLevel <= levels.error) {
console.error('Uncaught Exception:', err.stack || err);
}
});

process.on('unhandledRejection', reason => {
if (currentLevel <= levels.error) {
console.error('Unhandled Rejection:', reason.stack || reason);
}
});


这个方案有几个关键点。第一,log函数会根据当前环境变量LOG_LEVEL动态判断是否输出日志,避免了代码里到处写判断。第二,重写了console.error方法,即使生产环境设置了只输出error级别的日志,也能保证所有错误信息被记录到stderr中。第三,监听了uncaughtExceptionunhandledRejection事件,统一处理未捕获的异常,防止意外错误丢失。

效率更高的是,我们不需要为每个环境单独写一堆配置,只需要在启动服务时设置不同的LOG_LEVEL值即可。比如开发环境用LOG_LEVEL=debug,测试环境用LOG_LEVEL=warn,生产环境用LOG_LEVEL=error

最后吐槽一句,这种日志分级管理确实麻烦,但一次性做好封装后面就省心了。记得测试下各种场景,尤其是生产环境的错误堆栈输出,别踩坑。
点赞
2026-02-18 20:01
南宫秀花
你这个问题很典型,核心是要把日志的调用统一收口,同时保留原生行为。现在的写法有两个问题:一是直接依赖 console 方法没做代理,二是环境判断逻辑耦合在业务代码里。

标准写法是用一个日志适配层把 console 给 wrap 住。关键是利用浏览器和 Node.js 都支持的 globalThis.console 的可配置性,在启动时根据环境替换掉原始方法。

你可以这样改:

const LOG_LEVELS = { error: 0, warn: 1, info: 2, log: 3 };
const CURRENT_LEVEL = LOG_LEVELS[process.env.LOG_LEVEL || 'info'] ?? 3;

const createLogger = (level) => {
return (...args) => {
const method = ['error', 'warn', 'info', 'log'][level];
if (level >= CURRENT_LEVEL && console[method]) {
console[method](...args);
// 关键点:error 必须强制打堆栈
if (method === 'error') {
console.trace?.();
}
}
};
};

// 统一出口
export const logger = {
error: createLogger(0),
warn: createLogger(1),
info: createLogger(2),
log: createLogger(3)
};


然后你在项目入口处比如 app.js 开头加一行:

console.error = (...args) => logger.error(...args)

这一步很重要,能捕获那些没走你 log 工具的裸 console 调用。当然更彻底的做法是在构建时通过 Webpack DefinePlugin 把所有 console.* 替换成 logger 对应方法。

另外提一嘴,生产环境只留 error 没问题,但建议加个临时开关机制,比如通过 URL 参数或 localStorage 强制提升日志级别,方便线上 debug。我们线上就靠 localStorage.debugLogLevel='warn' 救过好多次。
点赞 2
2026-02-12 22:00