Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read everything from child_process.spawn's stderr in nodejs

Trying to run fping from nodejs via child_process.spawn() is and capturing output via cp.stderr.on('data') sometimes results in incomplete data in the buffer. Here's my sample snippet:

const ChildProcess = require('child_process');

const args = [
                '-A','-c10','-b1472','-B1',
                '-r0','-O0','-q', '-p100',
                'google.com', 'slack.com', 'github.com'
            ];

function runChildProcess() {
    const child = ChildProcess.spawn('fping', args);

    child.on('exit', (code) => 
        console.log('Process exited with code', code)
    );

    child.stdout.on('data', (data) => {
        console.log('stdout:', data.toString().length, 'chars');
    });
    child.stderr.on('data', (data) => {
        console.log('stderr:', data.toString().length, 'chars');
    });

}

setInterval(runChildProcess, 1500);

This produces output like so:

stderr: 219 chars
Process exited with code 0
stderr: 208 chars
stderr: 11 chars
Process exited with code 0
stderr: 218 chars
stderr: 1 chars
Process exited with code 0
stderr: 219 chars
Process exited with code 0
stderr: 219 chars
Process exited with code 0
stderr: 219 chars
Process exited with code 0
stderr: 218 chars
stderr: 1 chars
Process exited with code 0

As you can see, sometimes it invokes the callback two times, sometimes one, I had times where it was invoked 3 or 4 times with small reads. Is there a way to ensure all available data is read and not just some of it?

like image 649
Iskren Avatar asked Oct 18 '25 22:10

Iskren


1 Answers

You should listen for the end event. The data event may be called multiple times - it's called for each received chunk. All chunks should be collected together, for example in an array. The end event signals that there is no more data to consume in that readable stream (child.stderr).

See below a slightly changed version of your code (with setTimeout and ping instead) using the end event:

const ChildProcess = require('child_process');

const args = [
                'google.com'
            ];

function runChildProcess() {
    var stdoutChunks = [], stderrChunks = [];
    const child = ChildProcess.spawn('ping', args);

    child.on('exit', (code) =>
        console.log('Process exited with code', code)
    );

    child.stdout.on('data', (data) => {
        stdoutChunks = stdoutChunks.concat(data);
    });
    child.stdout.on('end', () => {
        var stdoutContent = Buffer.concat(stdoutChunks).toString();
        console.log('stdout chars:', stdoutContent.length);
        console.log(stdoutContent);
    });

    child.stderr.on('data', (data) => {
        stderrChunks = stderrChunks.concat(data);
    });
    child.stderr.on('end', () => {
        var stderrContent = Buffer.concat(stderrChunks).toString();
        console.log('stderr chars:', stderrContent.length);
        console.log(stderrContent);
    });

}

setTimeout(runChildProcess, 0);
like image 101
mar10 Avatar answered Oct 20 '25 15:10

mar10



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!