Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js: Capture STDOUT of `child_process.spawn`

I need to capture in a custom stream outputs of a spawned child process.

child_process.spawn(command[, args][, options])

For example,

var s = fs.createWriteStream('/tmp/test.txt');
child_process.spawn('ifconfig', [], {stdio: [null, s, null]})

Now how do I read from the /tmp/test.txt in real time?

It looks like child_process.spawn is not using stream.Writable.prototype.write nor stream.Writable.prototype._write for its execution.

For example,

s.write = function() { console.log("this will never get printed"); };

As well as,

s.__proto__._write = function() { console.log("this will never get printed"); };

It looks like it uses file descriptors under-the-hood to write from child_process.spawn to a file.

Doing this does not work:

var s2 = fs.createReadStream('/tmp/test.txt');
s2.on("data", function() { console.log("this will never get printed either"); });

So, how can I get the STDOUT contents of a child process?

What I want to achieve is to stream STDOUT of a child process to a socket. If I provide the socket directly to the child_process.spawn as a stdio parameter it closes the socket when it finishes, but I want to keep it open.

Update:

The solution is to use default {stdio: ['pipe', 'pipe', 'pipe']} options and listen to the created .stdout of the child process.

var cmd = child_process.spaw('ifconfig');
cmd.stdout.on("data", (data) => { ... });

Now, to up the ante, a more challenging question:

-- How do you read the STDOUT of the child process and still preserve the colors?

For example, if you send STDOUT to process.stdout like so:

child_process.spawn('ifconfig', [], {stdio: [null, process.stdout, null]});

it will keep the colors and print colored output to the console, because the .isTTY property is set to true on process.stdout.

process.stdout.isTTY // true

Now if you use the default {stdio: ['pipe', 'pipe', 'pipe']}, the data you will read will be stripped of console colors. How do you get the colors?

One way to do that would be creating your own custom stream with fs.createWriteStream, because child_process.spawn requires your streams to have a file descriptor.

Then setting .isTTY of that stream to true, to preserve colors.

And finally you would need to capture the data what child_process.spawn writes to that stream, but since child_process.spawn does not use .prototype.write nor .prototype._write of the stream, you would need to capture its contents in some other hacky way.

That's probably why child_process.spawn requires your stream to have a file descriptor because it bypasses the .prototype.write call and writes directly to the file under-the-hood.

Any ideas how to implement this?

like image 228
Vad Avatar asked Jun 03 '15 09:06

Vad


People also ask

How to create a child process in NodeJS?

The following are the four different ways to create a child process in Node.js: 1 spawn () method 2 fork () method 3 exec () method 4 execFile () method

How to spawn a new process from command line arguments?

spawn () method: This method spawns a new process using the given command and the command line arguments in args. The ChildProcess instance implements EventEmitterAPI which enables us to register handlers for events on child object directly.

How to add stdout output to a child process?

Call the process and once stdout arrives add your additional output in an event handler. If you still wan't to do it synchronously, the stdio array just takes streams. This means you could create a wrapper stream for stdout and tell the child-process to use that.

How to capture stdout and/or stderr from a process?

You might consider capturing the processes stdout and/or stderr to one or more files using shell output redirection (i.e. using bash: COMMAND 1>stdout.txt 2>stderr.log) which you would do by running your command in the bash shell.


1 Answers

You can do it without using a temporary file:

var process = child_process.spawn(command[, args][, options]);
process.stdout.on('data', function (chunk) {
    console.log(chunk);
});
like image 53
Magomogo Avatar answered Nov 11 '22 18:11

Magomogo