如何在不停止使用Ruby显示屏幕的情况下将STDOUT复制到文件中

Con*_*ner 11 ruby

我正在尝试将stdout复制到文件以进行日志记录.我还希望它显示在我正在使用的IDE的Ruby控制台中.

我将此代码插入到我的脚本中,然后重定向$stdout到my.log文件:

$stdout.reopen("my.log", "w")
Run Code Online (Sandbox Code Playgroud)

有没有人知道将内容复制$stdout到文件而不是将其重定向到文件的gem或技术?另外,我没有使用Rails只是Ruby.

mat*_*att 9

这样的事情可能对你有所帮助:

class TeeIO < IO

  def initialize orig, file
    @orig = orig
    @file = file
  end

  def write string
    @file.write string
    @orig.write string
  end

end
Run Code Online (Sandbox Code Playgroud)

输出中的大多数方法IO最终都会使用write,所以你只需要覆盖这一个方法.你可以像这样使用它:

#setup
tee = TeeIO.new $stdout, File.new('out.txt', 'w')
$stdout = tee

# Now lots of example uses:
puts "Hello"
$stdout.puts "Extending IO allows us to expicitly use $stdout"
print "heres", :an, :example, "using", 'print', "\n"
48.upto(57) do |i|
  putc i
end
putc 10 #newline
printf "%s works as well - %d\n", "printf", 42
$stdout.write "Goodbye\n"
Run Code Online (Sandbox Code Playgroud)

这个例子之后,下面是相同的写入双方的控制台和文件:

Hello
Extending IO allows us to expicitly use $stdout
heresanexampleusingprint
0123456789
printf works as well - 42
Goodbye
Run Code Online (Sandbox Code Playgroud)

我不会声称这种技术是失败证明,但它应该适用于stdout的简单使用.测试它供您使用.

请注意,除非要从子进程或不合作的扩展名重定向输出,否则不必使用reopenon $stdout.简单IO地为其分配不同的对象将适用于大多数用途.


RSpec的

RSpec命令行在您可以运行任何代码以重新分配$stdout 之前接受引用,因此这不起作用.reopen在这种情况下仍然可以正常工作,因为你正在更改两者指向的实际对象$stdout和RSpec具有的引用,但是这不会给你两者输出.

一个解决方案是$stdout像这样的猴子补丁:

$out_file = File.new('out.txt', 'w')

def $stdout.write string
  $out_file.write string
  super
end
Run Code Online (Sandbox Code Playgroud)

这有效,但与所有猴子修补一样,要小心.使用操作系统的tee命令会更安全.