How can I have ruby logger log output to stdout as well as file? How can I have ruby logger log output to stdout as well as file? ruby ruby

How can I have ruby logger log output to stdout as well as file?


You can write a pseudo IO class that will write to multiple IO objects. Something like:

class MultiIO  def initialize(*targets)     @targets = targets  end  def write(*args)    @targets.each {|t| t.write(*args)}  end  def close    @targets.each(&:close)  endend

Then set that as your log file:

log_file = File.open("log/debug.log", "a")Logger.new MultiIO.new(STDOUT, log_file)

Every time Logger calls puts on your MultiIO object, it will write to both STDOUT and your log file.

Edit: I went ahead and figured out the rest of the interface. A log device must respond to write and close (not puts). As long as MultiIO responds to those and proxies them to the real IO objects, this should work.


@David's solution is very good. I've made a generic delegator class for multiple targets based on his code.

require 'logger'class MultiDelegator  def initialize(*targets)    @targets = targets  end  def self.delegate(*methods)    methods.each do |m|      define_method(m) do |*args|        @targets.map { |t| t.send(m, *args) }      end    end    self  end  class <<self    alias to new  endendlog_file = File.open("debug.log", "a")log = Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file)


If you're in Rails 3 or 4, as this blog post points out, Rails 4 has this functionality built in. So you can do:

# config/environment/production.rbfile_logger = Logger.new(Rails.root.join("log/alternative-output.log"))config.logger.extend(ActiveSupport::Logger.broadcast(file_logger))

Or if you're on Rails 3, you can backport it:

# config/initializers/alternative_output_log.rb# backported from rails4module ActiveSupport  class Logger < ::Logger    # Broadcasts logs to multiple loggers. Returns a module to be    # `extended`'ed into other logger instances.    def self.broadcast(logger)      Module.new do        define_method(:add) do |*args, &block|          logger.add(*args, &block)          super(*args, &block)        end        define_method(:<<) do |x|          logger << x          super(x)        end        define_method(:close) do          logger.close          super()        end        define_method(:progname=) do |name|          logger.progname = name          super(name)        end        define_method(:formatter=) do |formatter|          logger.formatter = formatter          super(formatter)        end        define_method(:level=) do |level|          logger.level = level          super(level)        end      end    end  endendfile_logger = Logger.new(Rails.root.join("log/alternative-output.log"))Rails.logger.extend(ActiveSupport::Logger.broadcast(file_logger))