title: Continuously read from STDOUT and STDERR in real time
body: <p>Say we have a small application (<code>example.rb</code>) which behave like the following ruby code:</p>
  
  <pre><code>#!/usr/bin/env ruby
  
  done = false
  
  out =Thread.new do
      cnt = 0
      while !done
          STDOUT.puts "out #{cnt}"
          cnt += 1
          sleep 1
      end
  end
  
  err = Thread.new do
      cnt = 0
      while !done
          STDERR.puts "err #{cnt}"
          cnt += 1
          sleep 1
      end
  end
  
  
  while true
      i = STDIN.gets
      if i == "q\n"
          puts "Quiting"
          done = true
          break
      end
  end
  
  out.join
  err.join
  
  exit 42
  </code></pre>
  
  <p>It print something to stdout and to stderr, it must be quited by writing "q\n" to stdin, and when it exit a value is returned in the return code.</p>
  
  <p>Now, I would like to write a small ruby script which can run this program in an external process, where stdout and stdin are captured, and when the external process should be terminated this is done by writing "q\n" to its stdin. This program is called <code>monitor.rb</code>.</p>
  
  <p>This is what I have tried here:</p>
  
  <pre><code>#!/usr/bin/env ruby
  
  require 'open3'
  
  class Monitor
      @cmd
      attr_accessor :return_code
  
      def initialize cmd
          @cmd = cmd
      end
  
      def run
          @runner_thread = Thread.new do
              Open3::popen3(@cmd) do |stdin, stdout, stderr, thread|
                  puts "#{Time.now} #{@cmd} is running as pid: #{thread.pid}"
  
                  stdin.sync = true;
                  stdout.sync = true;
                  stderr.sync = true;
                  @stdin = stdin
  
                  t_out = Thread.new do
                      stdout.readlines do |l|
                          puts "#{Time.now} STDOUT&gt; #{l}"
                      end
                  end
  
                  t_err = Thread.new do
                      stderr.readlines do |l|
                          puts "#{Time.now} STDERR&gt; #{l}"
                      end
                  end
  
                  thread.join
                  t_err.join
                  t_out.join
                  @return_code = thread.value
              end
          end
      end
  
      def quit
          puts "Quiting"
          @stdin.puts "q"
          @stdin.close
          @runner_thread.join
      end
  end
  
  mon = Monitor.new "./example.rb"
  mon.run
  sleep 5
  mon.quit
  puts "Return code: #{mon.return_code}"
  </code></pre>
  
  <p>Question 1: What is wrong with my code since the output of the external process is not being printed?</p>
  
  <p>Question 2: Can this be done in a more elegant way, and what would that look like?</p>
  
  <p>The code must be able to run on Linux and portability is not a priority, I uses ruby 2.0.</p>
  
  <p>When run <code>example.rb</code> in a terminal I get:</p>
  
  <pre><code>$ ./example.rb 
  out 0
  err 0
  out 1
  err 1
  out 2
  err 2
  q
  Quiting
  </code></pre>
  
  <p>When I run the monitor application I get:</p>
  
  <pre><code>$ ./monitor.rb 
  2013-11-19 14:39:20 +0100 ./example.rb is running as pid: 7228
  Quiting
  Return code: pid 7228 exit 42
  </code></pre>
  
  <p>I expected the <code>monitor.rb</code> to print the output from <code>example.rb</code></p>