问题:使用node里的log4js,生成了大量的文件句柄且没有释放(too many open file),最总导致服务宕机。

需求:按用户和日期级别生成多个log文件。一天有n个用户请求,生成n份log。

最初的实现:log4js配置,type:file

const app = express()
const log4js = require('log4js')
app.post('/userTest', function(req, res) {
  let expressData = []
  let reqData
  req.on('data', function(data){
    expressData.push(data)    
  })    
  req.on('end', function() {
    reqData = Json.parse(Buffer.concat(expressData).toString())
  })
  // 配置log4js
  log4js.configure({
        appenders: {
            console: {
                type: 'console'
            },
            userLog: {
                type: 'File',
                filename: `logs/${userId}_${(new Date()).format('yyyyMMdd')}.log`,
                maxLogSize: 1024 * 1024 * 1024, //单个log最大size 1GB
                alwaysIncludePattern: true,
                layout: {
                    type: 'pattern',
                    pattern: '%d %p %c %X{userId} %m%n'
                }
            }
        },
        categories: {
            default: {appenders: ['console','userLog'], level: 'info'}
        },
        replaceConsole: true
    })
  let logger = log4js.getLogger('userLog')
  logger.addContext(
'userId', reqData.userId)
  // 记录log   
  logger.info('just a test')
})

每当执行到log4js.configure时,会生成一个文件句柄,且不会释放。

看起来写的很烂,当初自己为什么不把type设成multiFile?

改成multiFile,如下

const app = express()
const log4js = require('log4js')
// 配置log4js
log4js.configure({
    appenders: {
        console: {
            type: 'console'
          },
          multi: {
            type: 'multiFile',
            base: 'logs/',
            property: 'label',
            extension: '.log',
            maxLogSize: 1024*1024*1024 // backup 1GB
          }
        },
    categories: { default: { appenders: ['console','multi'], level: 'info'} }
})
app.post('/userTest', function(req, res) {
  let expressData = []
  let reqData
  req.on('data', function(data){
    expressData.push(data)    
  })    
  req.on('end', function() {
    reqData = Json.parse(Buffer.concat(expressData).toString())
  })
  let logger =log4js.getLogger(`default`)
            logger.addContext('label',`${reqData.userId}_${new Date().format('yyyyMMdd')}`)
  // 记录log   
  logger.info('just a test')
})

但是,还是会产生文件句柄,长时间之后还是会宕机。

so。。。上github 啊

how to close multiFile appender file handle #691

https://github.com/log4js-node/log4js-node/issues/691

added timeout support to multiFile appender

https://github.com/log4js-node/log4js-node/commit/13909b6fe39e75f5b83e3019bde685bd19af8a1e

原来只要在配置里面加上timeout,即可

log4js.configure({
        appenders: {
            console: {
                type: 'console'
            },
            multi: {
                type: 'multiFile',
                base: 'log/',
                property: 'label',
                extension: '.log',
                timeout:20, // optional activity timeout in ms after which the file will be closed.
                maxLogSize: 100*1024*1024 // Backup every 100mb
            }
        },
        categories: { default: { appenders: ['console','multi'], level: loggerLevel } }
    })

另外一点需要注意,这个bug是 3 May 2018 修复的,有些版本不支持

所以用最新的吧!!! 

生成的文件句柄可以用 ProcessExplorer.exe 查看

02-12 06:27