Reputation: 4650
I want to read and parse (with awk
) my nginx logs in realtime. So I wrote this shell command to do this, it works if I run it in shell:
tail -f -n +1 /var/log/nginx/access.log | awk '{print $1, $7, $9}'
But I can't run it in node. I wrote this code to run my command (this is taken from the example in node.js docs), but it displays nothing:
const tail = childProcess.spawn('tail',['-f', '-n', '+1', nginxAccessLog]);
const awk = childProcess.spawn('awk', ['{print $1, $7, $9}'], { stdio: [tail.stdout, 'pipe', 'pipe'] })
tail.stdout.on('data', (data) => {
console.log('tail output', data.toString());
})
awk.stdout.on('data', (data) => {
console.log('awk output', data.toString());
})
tail.on('error', () => 'tail error')
awk.on('error', () => 'awk error')
tail.on('close', () => console.log('tail end', result));
awk.on('close', () => console.log('awk end', result));
I can see that my process are spawned (they are in the htop
output), but I have no output.
How can I fix this?
Upvotes: 0
Views: 1218
Reputation: 203304
Not quite sure why passing tail.stdout
to the Awk process doesn't work (I'm guessing that at the time the Awk process is created, tail.stdout
might not yet have a valid file descriptor attached to it), but this does:
const tail = childProcess.spawn('tail',['-f', '-n', '+1', nginxAccessLog]);
const awk = childProcess.spawn('awk', ['{print $1, $7, $9}'], { stdio: [ 'pipe', process.stdout ] });
tail.stdout.pipe(awk.stdin);
Note that because you're using tail -f
, the pipeline will keep running.
EDIT: if it's not your intention to just log the output, but also process it, the situation becomes a bit more involved because Awk buffers its output (up to 4K, I believe).
You need to force a flush in Awk, which I found can be triggered using fflush("")
or system("")
. So the code becomes:
const tail = childProcess.spawn('tail',['-f', '-n', '+1', nginxAccessLog]);
const awk = childProcess.spawn('awk', [ '{print $1, $7, $9; fflush(""); }']);
tail.stdout.pipe(awk.stdin);
awk.stdout.on('data', data => {
console.log('awk output:', data.toString());
});
This does seem to add empty lines to the output, but those can be filtered out I guess.
Upvotes: 1