Read node.js by line from endless stream - node.js

I have an endless command line stream - namely logs from my heroku app - and want to parse it by line into node.js.
I have tried various approaches, like with the readline interface (does nothing):
var command = 'heroku logs --app myapp --tail';
var heroku = Npm.require('child_process').exec(command);
var readline = Npm.require('readline');
var rl = readline.createInterface({
input: heroku.stdin,
output: process.stdout
});
rl.on('line', function(log) {
console.log(log);
});
Or with just raw exec, that does return an initial buffer, but does not read continously from the process:
var command = 'heroku logs --app myapp --tail';
var heroku = Npm.require('child_process').exec(command);
heroku.stdout.setEncoding('utf8');
heroku.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
I did not get it to work with spawn - even though I think it may be correct.
What would be a better approach (I'm using meteor, hence the added Npm).

Related

How can process.stdin be used as the start point for a gulp task?

I'm using gulp to convert SCSS into CSS code with the gulp-sass plugin. This is all working fine, but I also want to use gulp to receive input (SCSS code) from a Unix pipe (i.e. read process.stdin) and consume this and stream the output to process.stdout.
From reading around process.stdin is a ReadableStream and vinyl seems like it could wrap stdin and then be used onwards in a gulp task, e.g.
gulp.task('stdin-sass', function () {
process.stdin.setEncoding('utf8');
var file = new File({contents: process.stdin, path: './test.scss'});
file.pipe(convert_sass_to_css())
.pipe(gulp.dest('.'));
});
However, when I do this I get an error:
TypeError: file.isNull is not a function
This makes me think that stdin is somehow special, but the official documentation for node.js states that it is a true ReadableStream.
So I got this to work by processing process.stdin and writing to process.stdout:
var buffer = require('vinyl-buffer');
var source = require('vinyl-source-stream');
var through = require('through2');
gulp.task('stdio-sass', function () {
process.stdin.setEncoding('utf8');
process.stdin.pipe(source('input.scss'))
.pipe(buffer())
.pipe(convert_sass_to_css())
.pipe(stdout_stream());
});
var stdout_stream = function () {
process.stdout.setEncoding('utf8');
return through.obj(function (file, enc, complete) {
process.stdout.write(file.contents.toString());
this.push(file);
complete();
});
};

nodejs : how to log to screen AND to file?

I use console.log in my node.js: that way I can log to screen
ex:
node myscript.js
If I use
node myscript.js>log.txt then I log to file log.txt
How can I log to screen AND to file ?
Use tee.
node myscript.js | tee log.txt
If you want this behavior to be persistent within your app, you could create a through stream and pipe it to both a writeStream and stdout.
var util = require('util');
var fs = require('fs');
// Use the 'a' flag to append to the file instead of overwrite it.
var ws = fs.createWriteStream('/path/to/log', {flags: 'a'});
var through = require('through2');
// Create through stream.
var t = new through();
// Pipe its data to both stdout and our file write stream.
t.pipe(process.stdout);
t.pipe(ws);
// Monkey patch the console.log function to write to our through
// stream instead of stdout like default.
console.log = function () {
t.write(util.format.apply(this, arguments) + '\n');
};
Now this will write to both stdout (terminal display) and to your log file.
You can also omit the through stream and just write to both streams in the monkey patched function.
console.log = function () {
var text = util.format.apply(this, arguments) + '\n';
ws.write(text);
process.stdout.write(text);
};
The through stream just gives you a single stream you could utilize in other ways around your app and you'd always know that it was piped to both output streams. But if all you want is to monkey patch console.log then the latter example is sufficient :)
If you only want to do this for a single run of your app from the terminal, see #andars' answer and the tee command :)
PS - This is all that console.log actually does in node, in case you were wondering.
Console.prototype.log = function() {
this._stdout.write(util.format.apply(this, arguments) + '\n');
};

Node JS: Executing command lines and getting outputs asynchronously

How can I run a command line and get the outputs as soon as available to show them somewhere.
For example if a run ping command on a linux system, it will never stop, now is it possible to get the responses while the command is still processing ?
Or let's take apt-get install command, what if i want to show the progress of the installation as it is running ?
Actually i'm using this function to execute command line and get outputs, but the function will not return until the command line ends, so if i run a ping command it will never return!
var sys = require('sys'),
exec = require('child_process').exec;
function getOutput(command,callback){
exec(
command,
(
function(){
return function(err,data,stderr){
callback(data);
}
}
)(callback)
);
}
Try using spawn instead of exec, then you can tap into the stream and listen to the data and end events.
var process = require('child_process');
var cmd = process.spawn(command);
cmd.stdout.on('data', function(output){
console.log(output.toString()):
});
cmd.on('close', function(){
console.log('Finished');
});
//Error handling
cmd.stderr.on('data', function(err){
console.log(err);
});
See the Node.js documentation for spawn here: https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

How to interact with multiple console windows?

how can interact with multiple console windows, from one node.js script?
so far i have researched a bit, and not have found anything that covers my case.
What i want to accomplish is to have one main console window, which it reads my input,
1. action#1
2. action#2
> do 1 // select action
and it would redirect its output to another console window named as Logger which shows the stdout of the action that the user selected, but keeps the main "select action" console window clean.
well i manage to find a way around it, since i wanted to stay with node.js all the way.
start.js
var cp = require("child_process");
cp.exec('start "Logger" cmd /K node logger.js',[],{});
cp.exec("start cmd /K node startAdminInterface.js",[],{});
setTimeout(function(){process.exit(0);},2000);
logger.js
var net = require('net');
net.createServer(function (socket) {
socket.on('data',function(d){
console.log(": "+d.toString("utf8"));
});
socket.on('error',function(err){
console.log("- An error occured : "+err.message);
});
}).listen(9999);
startAdminInterface.js
var net = require("net");
var logger = net.connect(9999);
var readline = require('readline'),
rl = readline.createInterface(process.stdin,process.stdout);
rl.setPrompt('> ');
rl.prompt();
rl.on('line', function(line) {
logger.write(line);
rl.prompt();
}).on('close', function() {
process.exit(0);
});
bottom, line its a workaround not exactly what i was after, put i saw potential, on logger.js it could listen from multiple sources, which is an enormous plus in the application that i'm building.

Dynamic arguments for ZINTERSTORE with node_redis

I'm trying to use the ZINTERSTORE command of redis from node.js using node_redis:
//node.js server code
var redis = require("redis");
var client = redis.createClient();
// ... omitted code ...
exports.searchImages = function(tags, page, callback){
//tags = ["red", "round"]
client.ZINTERSTORE("tmp", tags.length, tags.join(' '), function(err, replies){
//do something
});
}
But the call client.ZINTERSTORE throws the error: [Error: ERR syntax error]. Passing in tags as an array (instead of using tags.join(' ')) throws the same error.
Where can I find the correct syntax for this command? The source code for node_redis has it buried in the javascript parser, but it's tricky to see what's going on without 'stepping through' the code. Is there a good way to do step through debugging with node.js?
There are multiple ways to debug a Redis client with node.js.
First you can rely on the Redis monitor feature to log every commands received by the Redis server:
> src/redis-cli monitor
OK
1371134499.182304 [0 172.16.222.72:51510] "info"
1371134499.185190 [0 172.16.222.72:51510] "zinterstore" "tmp" "2" "red,round"
You can see the zinterstore command received by Redis is ill-formed.
Then, you can activate the debugging mode of node_redis by adding the following line in your script:
redis.debug_mode = true;
It will output the Redis protocol at runtime:
Sending offline command: zinterstore
send ncegcolnx243:6379 id 1: *4
$11
zinterstore
$3
tmp
$1
2
$9
red,round
send_command buffered_writes: 0 should_buffer: false
net read ncegcolnx243:6379 id 1: -ERR syntax error
Then, you can use node.js debugger. Put a debugger breakpoint in the code in the following way:
function search(tags, page, callback) {
debugger; // breakpoint is here
client.ZINTERSTORE("tmp", tags.length, tags, function(err, replies){
console.log(err);
console.log(replies);
callback('ok')
});
}
You can then launch the script with node in debug mode:
$ node debug test.js
< debugger listening on port 5858
connecting... ok
break in D:\Data\NodeTest\test.js:1
1 var redis = require("redis");
2 var client = redis.createClient( 6379, "ncegcolnx243" );
3
debug> help
Commands: run (r), cont (c), next (n), step (s), out (o), backtrace (bt), setBreakpoint (sb), clearBreakpoint (cb),
watch, unwatch, watchers, repl, restart, kill, list, scripts, breakOnException, breakpoints, version
debug> cont
break in D:\Data\NodeTest\test.js:8
6 function search(tags, page, callback) {
7
8 debugger;
9 client.ZINTERSTORE("tmp", tags.length, tags, function(err, replies){
10 console.log(err);
... use n(ext) and s(tep) commands ...
By stepping through the code, you will realize that the command array is not correct because the tags are serialized and processed as a unique parameter.
Changing the code as follows will fix the problem:
var cmd = [ "tmp", tags.length ];
client.zinterstore( cmd.concat(tags), function(err, replies) {
...
});

Resources