1

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

我希望stdoutandstderr流输出到一个文件,每个工作人员 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。

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

4

2 回答 2

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;
    };
}

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

于 2012-05-27T20:08:09.030 回答
0

看起来我的想法在某种程度上有效。只要大部分日志记录是使用 console.log 完成的,而不是直接写入标准输出,你就会很好。

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

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');
};

我有点怀疑你能否直接重新绑定标准输出,所以这可能是你最好的选择之一。

如果您根本不想将任何内容输出到控制台,则可以重新绑定 console.log,例如:

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

忘记外部脚本。

于 2012-05-25T22:13:50.127 回答