NodeJS winston记录大量写入陷阱

时间:2015-07-21 12:56:20

标签: node.js winston

节点JS - 12.7 温斯顿 - 1.0.1

我正在努力尝试生成代表许多“设备”的“假”日志文件。基本上我将在Kibana中使用数据进行测试和可视化。

我将Winston设置为登录文件:

var winston = require('winston');

var logger = new (winston.Logger)({
transports: [
    new (winston.transports.File)({
        filename: 'logs/dsm.log'
    })
  ]
});

所以我有一个设备数组,它只是一个12字节的列表哈希,如:AB4576D4C6AC等。

我循环遍历设备阵列并组装我的“假”日志条目,如下所示:

for (var i = 0; i < devices.length; i++) {
    var timeStmp = startDateTime.clone().add((i * config.dsmIntervalMinutes), "m");
    dsm = {
        deviceId: devices[i].deviceId,
        msg: "some log entry text",
        timeStmp: timeStmp
    };
    logger.info(dsm);
}

正如您所看到的,在循环中创建每个DSM之后,我将消息记录为info到Winston。

所以这似乎工作正常,除非我有大量的设备。我想要达到1米左右的设备。我目前正努力做100k。

我看到的是节点进程没有将日志写入日志文件。它似乎将它们全部存储在内存中(通过使用top看到),一旦达到10k左右,它就会慢慢爬行并最终停止前进。永远不会写日志文件。

所以我想知道是否有办法做到这一点?我可以以某种方式迫使节点/温斯顿每隔一段时间停止并写入磁盘吗?喜欢刷新缓存?我没有看到winston的选项。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

这是因为您正在使用for循环。 Node.js(JavaScript层)是单线程的。你的for循环阻止了进程实际进入写入阶段。

将其更改为类似的内容,以便循环设备而不会使过程窒息:

function doLog (d, cb) {
    var timeStmp = startDateTime.clone().add((i * config.dsmIntervalMinutes), "m");
    dsm = {
        deviceId: d.deviceId,
        msg: "some log entry text",
        timeStmp: timeStmp
    };
    // Callback is fired once the write is complete
    logger.info(dsm, cb);
}

async.eachSeries(devices, doLog, function () {
  log.info('Finished!')
});

async模块基本上按顺序依次运行每个操作(eachSeries),并在内部使用setImmediate在启动下一个设备doLog调用之前将每个调用推迟到允许I / O.您还可以查看async.parallelLimit以同时执行一些操作以获得更好的性能。

答案 1 :(得分:1)

这里的问题并不是循环是同步的,而是在刷新到磁盘时需要停止写入底层fs.createWriteStream实例。不等待你继续填充内部缓冲区,这就是为什么你的内存使用量不受约束地增加的原因。

因此,考虑到这一点,代码示例变为:

var fs = require('fs');
var winston = require('winston');

var stream = fs.createWriteStream('logs/dsm.log');
var file = new (winston.transports.File)({ stream: stream });
var logger = new (winston.Logger)({ transports: [file] });

//
// We'll store this for our position in all devices across
// `drain` events from the stream.
//
var curr = 0;

//
// function isFlushing()
// Returns a value if the file is flushing
//
function isFlushing() {
  var state = stream._writeableState;
  return state.length < state.highWaterMark;
}

//
// function logDevice()
// Logs a single device and returns a value
// indicating if the underlying filestream is full.
//
function logDevice(d) {
  var timeStmp = startDateTime.clone().add((i * config.dsmIntervalMinutes), 'm');  
  logger.info({
    deviceId: d.deviceId,
    msg: 'some log entry text',
    timeStmp: timeStmp
  });

  return isFlushing();
}

(function logAllDevices() {
  for (; curr < devices.length; curr++) {
    if (!logDevice(devices[curr])) {
      stream.once('drain', logAllDevices);
      break;
    }
  }
})();