Does Rails overwrite ruby's default logger?

972 Views Asked by At

I'm writing a multilogger implementation in order to enable my application to log to multiple back ends. The implementation looks like:

class MultiLogger < Logger
  def initialize(loggers = [])
    @loggers = []
  end

  def add(severity, message, _attributes, _environment, progname)
    @loggers.each do |logger|
      logger.add(severity, message, progname)
    end
  end

  def info(message, attributes, environment, progname)
    add(Logger::INFO, message, attributes, environment, progname)
  end

  ...
end

Basically I'm only forwarding calls issued to MultiLogger#add to all the loggers associated during the instantiation. The problem is that I need to set that logger as the Rails' default one, but I can't do that.

I'm adding config.logger = MultiLogger.new([Logger1.new, Logger2.new]) to my application.rb file, but when I call logger.info, I'm getting an error related to the arity of the add method.

The strangest thing is that my custom add is never called, and that error is raised from ActiveSupport::LogerThreadSafeLevel#add, like this: .rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activesupport-6.0.3.2/lib/active_support/logger_thread_safe_level.rb:51:in 'add'.

I think I'm missing something important about the inner workings of the Rails logging mechanism... but what? Is ActiveSupport overwriting my add method? What can I do in order to avoid that?

2

There are 2 best solutions below

0
On

Rails expects the Logger#add method to follow the interface of the Ruby logger, that is one mandatory argument (the severity), followed by two optional arguments (the message and the progname) as well as an optional block.

Here, Rails also assumed very specific semantics how these arguments are used by a logger implementation to build the final message (when passing either a message, a progname, a block or any combination of it.

class MultiLogger
  def add(severity, message = nil, progname = nil, &block)
    @loggers.each do |logger|
      logger.add(severity, message, progname, &block)
    end
    true
  end

  def info(message = nil, &block)
    add(Logger::INFO, message, &block)
  end

  # ...
end

In your original code, you have defined additional mandatory parameters in your add method (namely _attributes and _environment) which are not provided when calling the method thus an Exception. Once you fix your parameter list (and implement the missing shortcut methods and accessors), everything should work.

0
On

Use ActiveSupport::Logger or Modify Application Configuration File

By default, Rails expects the logger to be an instance of ActiveSupport::Logger. However, you can modify application.rb to use something else that's compatible. The Rails documentation says:

2.1 What is the Logger?

Rails makes use of the ActiveSupport::Logger class to write log information. Other loggers, such as Log4r, may also be substituted.

You can specify an alternative logger in config/application.rb or any other environment file[.]