Search code examples
node.jscmdspawn

Node spawn cant pipe cmd commands


Hello I'm creating a plugin which uses some command line commands in order to get the process memory and cpu usage how ever altho the command works in terminal it does not when running with node.

Furthermore when running with node the findstr part doesnt work at all, and because of that I get all the process list from stdout. Normally I should have had one 1 line:

Here is the source:

var spawn = require('child_process').spawn;
var readline = require('readline');

function Pstats() {
    this.os = /^win/.test(process.platform) === true ? 'win' : 'nix';
    this.win_cmd_arr = ['/C', 'wmic', 'path', 'Win32_PerfFormattedData_PerfProc_Process', 'get', 'IDProcess,WorkingSet,PercentProcessorTime', '|', 'findstr', '/R', '"^' + process.pid + '"'];

};

// this for example will list all processes with starting pid of 4
// wmic path Win32_PerfFormattedData_PerfProc_Process get IDProcess,WorkingSet,PercentProcessorTime | findstr /R "^4"          

Object.defineProperties(Pstats.prototype, {

    constructor: Pstats,

    usage: {
        enumerable: false,
        value: function(callback) {

            if (this.os === 'win') {

                var proc = spawn('cmd.exe', this.win_cmd_arr);

                proc.stdout.on('data', function(data) {
                    console.log(data.toString());
                });


                // readline.createInterface({
                //     input: proc.stdout,
                //     terminal: false
                // }).on('line', function(line) {
                //     console.log(line);
                // });

                // readline.createInterface({
                //     input: proc.stderr,
                //     terminal: false
                // }).on('line', function(line) {
                //     console.error(line);
                // });

            } else {
                throw new TypeError('unsupported operatin system');
            }

        }

    }

});

exports = module.exports = (function() {
    return new Pstats();
})();

Solution

  • You can use the SQL-like where clause to limit the results from wmic. For example:

    var exec = require('child_process').exec;
    
    // ...
    
    function Pstats() {
      this.winCmd = [
        'wmic', 
        'path',
        'Win32_PerfFormattedData_PerfProc_Process',
        'where "IDProcess = ' + process.pid + '"',
        'get',
        ['WorkingSet',
         'PercentProcessorTime'
        ].join(','),
        '/format:csv'
      ].join(' ');
    }
    
    Object.defineProperties(Pstats.prototype, {
      constructor: Pstats,
      usage: {
        enumerable: false,
        value: function(callback) {
          if (process.platform === 'win32') {
            exec(this.winCmd, { encoding: 'utf8' }, function(err, stdout, stderr) {
              if (err)
                return callback(err);
    
              stdout = stdout.split(/\r?\n/g);
              if (stdout.length < 2)
                return callback(new Error('Missing WMIc output'));
    
              var values = stdout[1].split(',');
              if (values.length !== 3)
                return callback(new Error('Bad WMIc output'));
    
              // Node (Computer) name is always the first column with CSV output
              var percentCPU = parseInt(values[1], 10);
              var workingSet = parseInt(values[2], 10);
    
              if (isNaN(percentCPU) || isNaN(workingSet))
                return callback(new Error('Bad WMIc values'));
    
              // `PercentProcessorTime` is uint64 and may not fit in a JS double, so
              // we check for that here and leave it as a string if it does not fit
              if (percentCPU > 9007199254740991)
                percentCPU = values[1];
    
              callback(null, workingSet, percentCPU);
            });
          } else
            callback(new Error('Unsupported platform'));
        }
      }
    });