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

Pocket

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されないので注意しないといけない。

1 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *