repl.info

Rubyでstdoutl/errを標準出力/エラーとファイルの両方に出力する

stdout/stderrをファイルにも出力したくていろいろ調べて、いい感じの解決方法を見つけたのでメモしておく。

ruby-listにmatzが投稿していた(Re: puts,printの出力をファイルにも出力するには)。

これを実行すると、こうなる。

defout = Object.new

defout.instance_eval{@ofile=open("/tmp/test.log", "w")}

class <<defout

  def write(str)

    STDOUT.write(str)

    @ofile.write(str)

  end

end

$stdout = defout



puts 'aaa'

$ ruby ./test.rb

aaa

$ cat ./test.log

aaa

なるほど、標準出力と標準エラーにputsされている。便利。

これができると、次はstdoutとstderrの両方をファイルにも出力したくなる。その場合はこうしちゃえばいい。

defout = Object.new

defout.instance_eval{@ofile=open("/tmp/test.log", "a")}

class <<defout

  def write(str)

    STDOUT.write(str)

    @ofile.write(str)

    @ofile.flush

  end

end

$stdout = defout



deferr = Object.new

deferr.instance_eval{@ofile=open("/tmp/test.log", "a")}

class <<deferr

  def write(str)

    STDERR.write(str)

    @ofile.write(str)

    @ofile.flush

  end

end

$stderr = deferr



puts 'aaa'

warn 'bbb'

puts 'ccc'

$ ruby ./test.rb

aaa

bbb

ccc

$ cat ./test.log

aaa

bbb

ccc

flushしないとtest.logにstdoutが先に全て出力され、その後にstderrが出力されてしまうようだ。また、この方法だとsystemのような子プロセスの出力はteeされないので注意しないといけない。