Logging stdout/stderr/stdin of an spawn process (Open4::spawn)

Hi dear rubyists,

I apologize for reposting this message, but I’m not sure if the
previous one did get to the mailing list.

I need to log all the input (typed by the user) and the stdout/stderr
of a process. The #script method below should behave pretty much like
the Unix script application. This way, my application can issue
several commands, show their output to the user an let them whatever
is needed.

def script cmd, log
# prepare $stdin to save its content into log
# prepare $stdout to save its content into log
# prepare $stderr to save its content into log
status = Open4::spawn cmd, ‘stdin’ => $stdin, ‘stdout’ =>
$stdout, ‘stderr’ => $stderr
end

I’ve seen some implementations of a #tee function or Tee class, but
they don’t seem to work with spawn. What would you suggest?

Thanks in advance,
Ed

On Apr 29, 12:05 pm, Edgardo H. [email protected] wrote:

    # prepare $stderr to save its content into log
    status = Open4::spawn cmd, 'stdin' => $stdin, 'stdout' =>

$stdout, ‘stderr’ => $stderr
end

I finally managed to do it. Open4::spawn allows any object to be used
as stdin/stdout/stderr as long as they support ‘each’, ‘read’, or
‘to_s’ or ‘<<’. So I just created a wrapper class that encapsulates
two descriptors logging al I/O operations.

Best regards,
Edgardo

BEGIN SCRIPT

require ‘rubygems’
require ‘open4’

class LoggingIO
def initialize io, log
@io = io
@log = log
end

    def gets(sep_string=$/)
            res = @io.gets(sep_string)
            log res
            res
    end

    def << obj
            res = @io << obj
            log obj
            res
    end

    def log obj
            str = obj ? obj.to_s : "(nil)\n"
            @log << str
    end
    private :log

end

def execute cmd, logfile = nil
log = nil
stdin = $stdin
stdout = $stdout
stderr = $stderr

    if (logfile)
            log = File.open(logfile, 'a+')
            stdin  = LoggingIO.new($stdin, log)
            stdout = LoggingIO.new($stdout, log)
            stderr = LoggingIO.new($stderr, log)
    end

    status = Open4::spawn cmd, 'stdin' => stdin, 'stdout' =>

stdout, ‘stderr’ => stderr
log.close if log
status
end

END SCRIPT

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs