Ssh – Tail log file on multiple machines over ssh

linuxsshtail

I'm trying to tail a log file on multiple remote machines and forward the output to my local workstation. I want connections to close when pressing CtrlC.

At the moment I have the following function that almost works as intended.

function dogfight_tail() {
 logfile=/var/log/server.log
 pids=""
 for box in 02 03; do
   ssh server-$box tail -f $logfile | grep $1 &
   pids="$pids $!"
 done
 trap 'kill -9 $pids' SIGINT
 trap  wait
}

The connections close and I receive the output from tail. BUT, there is some kind of buffering going on because the output come in batches.

And here's the fun part…

I can see the same buffering behaviour when executing the following and append "test" to the file /var/log/server.log on the remote machines 4-5 times…

ssh server-01 "tail -f /var/log/server.log | grep test"

…and found two ways of disabling it…

  1. Add -t flag to ssh.

    ssh -t server-01 "tail -f /var/log/server.log | grep test"
    
  2. Remove quotation from the remote command.

    ssh server-01 tail -f /var/log/server.log | grep test
    

However, neither of these approaches work for the function that execute on multiple machines mentioned above.

I have tried dsh, which have the same buffering behaviour when executing.

dsh -m server-01,server-02 -c "tail -f /var/log/server.log | grep test"

Same here, if I remove the quotation, the buffering goes away and everything works fine.

dsh -m server-01,server-02 -c tail -f /var/log/server.log | grep test

Also tried parallel-ssh which works exactly the same as dsh. Can somebody explain what's going on here?

How do I fix this problem? Would be ideal to go with straight ssh if possible.

P.S. I do not want to use multitail or similar since I want to be able to execute arbitrary commands.

Best Answer

What you see is effect of a standard stdout buffer in grep provided by Glibc. The best solution is to disable it by using --line-buffered (GNU grep, I'm not sure what other implementations might support it or something similar).

As for why this only happens in some cases:

ssh server "tail -f /var/log/server.log | grep test"

runs the whole command in the quotes on the server - thus grep waits to fill its buffer.

ssh server tail -f /var/log/server.log | grep test

runs grep on your local machine on the output tail sent through the ssh channel.

The key part here is, that grep adjusts its behaviour depending on whether its stdin is a terminal or not. When you run ssh -t, the remote command is running with a controlling terminal and thus the remote grep behaves like your local one.

Related Question