2015-12-14 61 views
4

的NodeJS如何寫大量的日誌與log4j的或溫斯頓?內存

的NodeJS作爲一個begginner的記錄中,我寫測試代碼一樣緊隨其後。但內存越來越大,有時甚至沒有輸出(通過多種方式改變它)。

有是2名記錄模塊,log4jswinston。以log4js爲例。

1 main.js

(function(){ 
    "use strict"; 

    let log4js = require("./log4js-config.js"); 
    let logger = log4js.getLogger("log4js_main"); 

    for(let i = 0; i < 10000000 ; i++){ 

      logger.log("info", "info message " + i + "."); 

    } 

})(); 

2. log4js-config.js

module.exports = (function(){ 
    "use strict"; 
    let Log4js = require("log4js"); 
    Log4js.configure(
     { 
      "appenders" : [ 
       { "type" : "logLevelFilter" 
        ,"level" : "ALL" 
        ,"appender" : { 
         "type" : "console" 
        } 
       } 
       ,{ "type" : "logLevelFilter" 
        ,"level" : "ALL" 
        ,"appender" : { 
         "type" : "dateFile" 
         ,"filename" : "./logs/log4js_date" 
         ,"pattern" : "-yyyyMMdd.log" 
         ,"alwaysIncludePattern" : false 
         ,"maxLogSize" : 209715200 
         ,"_maxLogSize" : "200M = 200 * 1024 * 1024 = 209715200" 
         ,"category" : "log4js.dateFile" 
        } 
       } 
       ,{ "type" : "logLevelFilter" 
        ,"level" : "ALL" 
        ,"appender" : { 
         "type" : "file" 
         ,"filename" : "./logs/log4js_size.log" 
         ,"maxLogSize" : 209715200 
         ,"_maxLogSize" : "200M = 200 * 1024 * 1024 = 209715200" 
         ,"alwaysIncludePattern" : false 
         ,"backups" : 10 
         ,"category" : "log4js.file" 
        } 
       } 
      ] 
      ,"replaceConsole" : true 
     } 
    ); 

    return Log4js; 
})(); 

當循環次數很小,雖然內存增加和 不會下跌下來,它運作良好。但是,當時間被設定爲多 超過10,000,000,它會失敗,並提示如下:

... 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525074. 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525075. 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525076. 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525077. 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525078. 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525079. 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525080. 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525081. 
[2015-12-14 11:23:12.480] [INFO] log4js_main - info message 2525082. 

<--- Last few GCs ---> 

    420299 ms: Scavenge 1399.0 (1457.4) -> 1399.0 (1457.4) MB, 2.3/0 ms (+ 0.0 ms in 1 steps since l 
ast GC) [allocation failure] [incremental marking delaying mark-sweep]. 
    421110 ms: Mark-sweep 1399.0 (1457.4) -> 1399.0 (1457.4) MB, 814.3/0 ms (+ 15.0 ms in 2 steps si 
nce start of marking, biggest step 15.0 ms) [last resort gc]. 
    421937 ms: Mark-sweep 1399.0 (1457.4) -> 1399.0 (1457.4) MB, 828.6/0 ms [last resort gc]. 


<--- JS stacktrace ---> 

==== JS stack trace ========================================= 

Security context: 0000019446CE3AD1 <JS Object> 
    1: nextTick [node.js:~491] [pc=0000037DBBD17738] (this=0000012811B14929 <a process with map 0000 
02F23C011991>,callback=0000017AB4E49C01 <JS Function afterWrite (SharedFunctionInfo 000002DC70230AF1 
)>) 
    2: arguments adaptor frame: 5->1 
    3: onwrite(aka onwrite) [_stream_writable.js:~315] [pc=0000037DBB93CC17] (this=0000019446C04189 
<undefined>,stream=000000727BB2BEE1 <a WriteStream wit... 

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory 

PS

正如我在stackoverflow.com第一個問題,我想分享的東西 困擾我很長一段時間。所以來到這個問題。

回答

2

TL;博士

因此,有必要給記錄器有機會通過 setImmediate(做I/O工作),並使用事件,而不是「爲」做循環,否則 會將內容保留在內存中並因內存不足而死亡。

根源

這是由the event loop mechanisms of nodejs引起的,布爾ev_run(循環,詮釋標誌),它通過這個命令每次接受一個任務 從觀察:

idle -> I/O -> check

的「「和」 process.nextTick()'被閒置的觀察家,所以 記錄器沒有機會做底層的I/O工作。它會導致內存不足。

解決方案

所以,我們需要給記錄器一個機會做基礎工作。

main.js爲log4js

(function(){ 
    "use strict"; 

    const WORK_DONE_EVENT_NAME = "work-done"; 
    const WORK_TIMES = 100 * 1000 * 1000; 

    let evem = new (require("events").EventEmitter)(); 

    // Explicitly listening on the event. 
    evem.on(WORK_DONE_EVENT_NAME, function(){ 
     // setImmediate: after I/O operations 
     setImmediate(doWork); 
    }); 

    let log4js = require("./log4js-config.js"); 
    let logger = log4js.getLogger("log4js_main"); 

    let idx = 0; 
    function doWork(){ 
     idx++; 
     if(idx >= WORK_TIMES){ 
      console.timeEnd(WORK_DONE_EVENT_NAME); 
      return; 
     } 
     logger.info(idx); 
     setImmediate(function(){ 
      evem.emit(WORK_DONE_EVENT_NAME); 
     }); 
    } 

    console.time(WORK_DONE_EVENT_NAME); 
    doWork(); 
})(); 

log4js-config.js(保持相同)

主。溫斯頓爵士

(function(){ 
    "use strict"; 

    const WORK_DONE_EVENT_NAME = "work-done"; 
    const WORK_TIMES = 100 * 1000 * 1000; 

    let evem = new (require("events").EventEmitter)(); 
    let logger = require("./winston-config"); 

    // Explicitly listening on the event. 
    evem.on(WORK_DONE_EVENT_NAME, function(){ 
     // setImmediate: after I/O operations 
     setImmediate(doWork); 
    }); 

    let idx = 0; 
    function doWork(){ 
     idx++; 
     if(idx >= WORK_TIMES){ 
      console.timeEnd(WORK_TIMES); 
      return; 
     } 
     logger.silly(idx, function(err, level, msg, meta){ 
      if(err){ 
       throw err; 
      } 
      evem.emit(WORK_DONE_EVENT_NAME); 
     }); 
    } 

    console.time(WORK_TIMES); 
    doWork(); 
})(); 

溫斯頓 - config.js

module.exports = (function(){ 
    "use strict"; 
    let Winston = require("winston"); 
    let WinstonDailyRotateFile = require("winston-daily-rotate-file"); 
    let transports = [ 
      new (Winston.transports.Console)({ 
       "colorize" : true 
       ,"timestamp" : true 
       ,"showLevel": true 
       ,"level" : "silly" 
      }) 
      ,new (Winston.transports.File)({ 
       "name" : "winston-file" 
       ,"filename" : "./logs/winston_size.log" 
       ,"maxsize" : 209715200 
       , "_maxsize" : "200M = 200 * 1024 * 1024 = 209715200" 
       ,"maxFiles" : 1024 
       ,"timestamp" : true 
       ,"showLevel": true 
       ,"level": "silly" 
      }) 
      ,new (WinstonDailyRotateFile)({ 
       "name" : "winston-daily-file" 
       ,"filename" : "./logs/winston_date" 
       ,"datePattern" : "-yyyyMMdd.log" 
       ,"maxsize" : 209715200 
       , "_maxsize" : "200M = 200 * 1024 * 1024 = 209715200" 
       ,"maxFiles" : 10 
       ,"timestamp" : true 
       ,"level": "silly" 
      }) 
     ]; 
    let logger = new (Winston.Logger)({ 
     "transports" : transports 
    }); 
    return logger; 
})();