将process.stdout设置为每个node.js核心集群工作者的文件

时间:2012-05-25 22:06:06

标签: node.js multiprocessing stdout cluster-computing

我正在尝试使用节点核心的群集功能。

我希望stdoutstderr个流输出到一个文件,每个工作者ID一个。

类似于以下内容:

var fs          = require('fs'), 
    env         = process.env,
    workerId    = env.NODE_WORKER_ID || env.NODE_UNIQUE_ID;

process.stdout =  fs.createWriteStream(__dirname + '/app#' + workerId + '.log', {
    encoding: 'utf8'
});

不幸的是,似乎没有像这样重写process.stdout。

有没有办法实现这一目标,还是应该采取不同的方式?目前,当我运行我的集群时,我将从一个控制台中获取所有进程的所有输出,这非常混乱。

2 个答案:

答案 0 :(得分:2)

我最终做了以下事情:

    //create a new stdout file stream
    var stdoutFS = fs.createWriteStream(stdoutFile, {
        encoding: 'utf8',
        flags   : 'a+'
    });

    //create a new stderr file stream
    var stderrFS = fs.createWriteStream(stderrFile, {
        encoding: 'utf8',
        flags   : 'a+'
    });

    //pipe stdout to a worker file
    var unhookStdout = hookWriteStream(stdout, function(string, encoding, fd) {
        stdoutFS.write(string, encoding || 'utf8');
    });
    console.log('\n\nPrepared new stdout hook to worker file.');

    //pipe stderr to a worker file
    var unhookStderr = hookWriteStream(stderr, function(string, encoding, fd) {
        stderrFS.write(string, encoding || 'utf8');
    });
    console.log('Prepared new stderr hook to worker file.');

    //unhook when things go wrong
    stdoutFS.once('close', function() {
        unhookStdout();
        console.log('Unhooked stdout.');
    });
    stdoutFS.once('error', function(err) {
        unhookStdout();
        console.error('Error: Unhooked stdout due to error %j.', err);
    });
    stderrFS.once('close', function() {
        unhookStderr();
        console.log('Unhooked stderr.');
    });
    stderrFS.once('error', function(err) {
        unhookStderr();
        console.error('Error: Unhooked stderr due to error %j.', err);
    });

});

function hookWriteStream(stream, callback) {
    var oldWrite = stream.write;

    stream.write = (function(write) {
        return function(string, encoding, fd) {
            write.apply(stream, arguments);
            callback(string, encoding, fd);
        };
    })(stream.write);

    return function() {
        stream.write = oldWrite;
    };
}

它可能不是很优雅,但到目前为止这是我找到的最佳解决方案。

答案 1 :(得分:0)

看起来我的想法在某种程度上起作用。只要大多数日志记录使用console.log完成而不是直接写入stdout,你就会很好。

就像我在下面的评论中所说,使用这样的脚本:

fs = require 'fs'
{exec} = require 'child_process'

execAndPipe = (execString) ->
    piper = exec execString

    piper.stdout.on 'data', (data) ->
        if data[0...'PROCESS'.length] == 'PROCESS'
            # extract the worker ID and output 
            # to a corresponding file
    piper.stderr.on 'data', (data) ->
        if data[0...'PROCESS'.length] == 'PROCESS'
            # extract the worker ID and output 
            # to a corresponding file


task 'run', 'Run the server', ->
    execAndPipe 'node blah.js'

运行您的服务器。然后重新定义console.log,如:

console.log = function (d) {
    process.stdout.write('PROCESS' + WORKERID + d + '\n');
};

我有点怀疑你是否能够直接重新加入stdout,所以这可能是你最好的选择之一。

如果您不想在ALL处输出任何内容,您可以重新绑定console.log,如:

console.log = function (d) {
    var str = fs.createWriteStream(__dirname + '/app#' + workerId + '.log', {
        encoding: 'utf8'
    });
    process.stdout.pipe(str);
};

忘了外部脚本。