【问题标题】:Does Rails overwrite ruby's default logger?Rails 会覆盖 ruby​​ 的默认记录器吗?
【发布时间】:2026-01-16 19:50:01
【问题描述】:

我正在编写一个多记录器实现,以使我的应用程序能够记录到多个后端。实现如下:

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

基本上,我只是将发给MultiLogger#add 的调用转发给实例化期间关联的所有记录器。问题是我需要将该记录器设置为 Rails 的默认记录器,但我不能这样做。

我正在将config.logger = MultiLogger.new([Logger1.new, Logger2.new]) 添加到我的application.rb 文件中,但是当我调用logger.info 时,我收到了与add 方法的数量相关的错误。

最奇怪的是,我的自定义 add 从未被调用,并且该错误是从 ActiveSupport::LogerThreadSafeLevel#add 引发的,如下所示:.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'

我认为我遗漏了有关 Rails 日志记录机制内部工作原理的一些重要内容……但是什么? ActiveSupport 是否覆盖了我的 add 方法?我该怎么做才能避免这种情况?

【问题讨论】:

    标签: ruby logging ruby-on-rails-6 ruby-2.6


    【解决方案1】:

    使用 ActiveSupport::Logger 或修改应用程序配置文件

    默认情况下,Rails 期望记录器是 ActiveSupport::Logger 的一个实例。但是,您可以修改 application.rb 以使用其他兼容的内容。 Rails documentation 说:

    2.1 什么是记录器?

    Rails 使用 ActiveSupport::Logger 类来编写日志 信息。也可以替换其他记录器,例如 Log4r。

    您可以在 config/application.rb 或任何 其他环境文件[.]

    【讨论】:

      【解决方案2】:

      Rails 期望 Logger#add 方法遵循 Ruby 记录器的接口,即一个强制参数(severity),后跟两个可选参数(messageprogname)以及一个可选的块。

      在这里,Rails 还假设了非常具体的语义,记录器实现如何使用这些参数来构建最终消息(当传递 messageprogname、块或它们的任意组合时。

      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
      

      在您的原始代码中,您在add 方法(即_attributes_environment)中定义了额外的强制参数,这些参数在调用该方法时未提供,因此是一个异常。一旦你修复了你的参数列表(并实现了缺少的快捷方法和访问器),一切都应该正常工作。

      【讨论】: