线程安全:捕获$ stdout的输出

时间:2013-04-24 04:06:00

标签: ruby multithreading debugging thread-safety sidekiq

我想知道如何在ruby的线程环境中捕获$stdout的输出。

一些细节。我使用捕获进行日志记录,我有sidekiq来处理后台的作业以及线程。我编码:

@previous_stdout, $stdout = $stdout, StringIO.new
self.stdout = $stdout.string

它抛出了我(对于某些线程):

WARN: undefined method `string' for #<IO:<STDOUT>>

1 个答案:

答案 0 :(得分:4)

如果您自己记录内容,请为每个作业保留一个StringIO日志并写入:

@log = StringIO.new
@log.write 'debug message'

Sidekiq还提供日志记录选项:

https://github.com/mperham/sidekiq/wiki/Logging

否则你可以尝试一些真正的hacky,比如在Kernel上覆盖打印方法并同步它,这样你就不会意外地写错了$ stdout。类似的东西:

require 'stringio'

module Kernel
  @@io_semaphore = Mutex.new

  [ :printf, :p, :print, :puts ].each do |io_write|
    hidden_io_write = "__#{io_write}__"

    alias_method hidden_io_write, io_write

    define_method(io_write) do |*args|
      @@io_semaphore.synchronize do
        $stdout = Thread.current[:log] || STDOUT
        self.__send__(hidden_io_write, *args)
        $stdout = STDOUT
      end
    end
  end
end

threads = 3.times.map do
  Thread.new do
    Thread.current[:log] = log = StringIO.new
    sleep(rand)
    puts "testing..."
    log.string
  end
end

logs = threads.map(&:value)
p logs
# => ["testing...\n", "testing...\n", "testing...\n"]