Express+Winston+Events配置异常:报错时日志无法写入文件
问题原因及修复方案
你的代码里错误日志无法写入文件的核心原因是:
handleDoSomethingHeavy是异步函数,它抛出的错误属于未处理的Promise拒绝,而Winston的handleExceptions配置仅负责捕获同步代码中未捕获的异常,对异步Promise的未处理拒绝无效。- 你通过
setImmediate调用异步函数时,没有捕获其抛出的错误,也没有主动调用Winston的日志方法来记录这个错误,导致只有Node.js默认的控制台错误输出,没有触发Winston的文件传输器。
具体修复方式
方式一:在异步函数内部捕获错误并记录
修改handleDoSomethingHeavy函数,用try/catch捕获错误,主动调用logger.error记录:
async function handleDoSomethingHeavy(payload) { try { console.log('alok', payload) throw new Error('Something went wrong') } catch (err) { logger.error('处理任务时出错: %s', err.message, { stack: err.stack }) } }
方式二:在事件监听中处理异步函数的Promise拒绝
修改事件监听器,使用async/await配合try/catch捕获错误:
eventEmitter.on('doSomethingHeavy', async (payload) => { try { await handleDoSomethingHeavy(payload) } catch (err) { logger.error('处理任务时出错: %s', err.message, { stack: err.stack }) } });
额外:全局捕获未处理的Promise拒绝(可选)
如果想覆盖所有未被捕获的Promise拒绝,在代码中添加全局监听:
process.on('unhandledRejection', (reason, promise) => { logger.error('未处理的Promise拒绝: %s', reason.message, { stack: reason.stack, promise }); });
修改后的完整代码示例
const winston = require('winston'); const express = require('express') var events = require('events'); async function handleDoSomethingHeavy(payload) { console.log('alok', payload) throw new Error('Something went wrong') } var eventEmitter = new events.EventEmitter(); // 修改事件监听器,处理异步错误 eventEmitter.on('doSomethingHeavy', async (payload) => { try { await handleDoSomethingHeavy(payload) } catch (err) { logger.error('处理任务时出错: %s', err.message, { stack: err.stack }) } }); const app = express() const port = 3000 var options = { file: { level: 'debug', filename: `mylogs-${Date.now()}.log`, handleExceptions: true, format: winston.format.combine( winston.format.splat(), winston.format.timestamp(), winston.format.json() // 建议添加格式,让日志更易读 ), maxsize: 100 * 1024 * 1024, maxFiles: 10, }, console: { level: 'debug', handleExceptions: true, format: winston.format.combine( winston.format.splat(), winston.format.timestamp(), winston.format.colorize(), winston.format.simple() ), } } var logger = winston.createLogger({ levels: winston.config.syslog.levels, transports: [ new winston.transports.File(options.file), new winston.transports.Console(options.console) ], exitOnError: false, }) // 全局监听未处理的Promise拒绝 process.on('unhandledRejection', (reason, promise) => { logger.error('未处理的Promise拒绝: %s', reason.message, { stack: reason.stack, promise }); }); app.get('/', (req, res) => { logger.info('Got get request') let payload = { name: 'Alok' } eventEmitter.emit('doSomethingHeavy', payload); res.send('Task queued') }) app.listen(port, () => { logger.info(`Example app listening on port ${port}`) })
内容的提问来源于stack exchange,提问作者Alok
相关产品推荐
相关产品推荐

