重定向Rails 3中特定控制器的记录器输出

Str*_*ine 6 ruby logging ruby-on-rails ruby-on-rails-3

我们希望有一组控制器,我们将记录器输出从所有操作和下游方法路由到单独的日志文件.这是一个Rails 3项目.在Rails 2中,我们通过重新定义"logger"方法来实现这一点,但在Rails 3中,记录的方式是使用"Rails.logger".我尝试过

Rails::logger = Logger.new(File.join(Rails.root, 'log', "reports_controller.log"), 10, 1000000) 
Run Code Online (Sandbox Code Playgroud)

在控制器的顶部,但只有在操作中专门使用Rails.logger的特定情况才会发送到指定的日志文件,控制器的所有默认日志输出仍然路由到主日志文件.

我们如何将特定控制器的所有日志输出路由到特定日志文件以包含所有默认控制器输出?

默认情况下,控制器输出,我指的是从入站请求的最开始处开始的所有消息

Started POST "/api/v1/reports.json" for 10.XXX.XX.XX at 2015-03-07 01:30:22 +0000
Processing by Api::V1::ReportsController#create as JSON
  Parameters: {"report"=>{"cloud_file_path"=>"report.zip", "company_id"=>nil, "created_at"=>"2015-03-07T01:30:17Z", "type_id"=>"2", "updated_at"=>"2015-03-07T01:30:17Z", "master"=>"1"}}
Run Code Online (Sandbox Code Playgroud)

以及控制器中的入站请求和出站响应可能跟随的所有日志输出.

基本上我希望报告控制器的所有日志记录都在reports_controller.log中,我不希望报告控制器的任何消息显示在主日志中(即生产中的production.log)

更新:

感谢@ mudasobwa对他的回答和聊天的帮助,我能够使用中间件解决这个问题,因为他的答案描述了(尽管我必须将我的insert_before更改为Rails :: Rack :: Logger之前)

他为我解决了这个问题的修改后的答案就在下面而且它还存在 config/initializers/logger_middleware.rb

module MyApp
  class LoggerMiddleware

    REPORTS_API_CONTROLLER_PATH = %r|\A/api/v.*/reports/.*|
    REPORTS_API_CONTROLLER_LOGFILE = "reports_controller.log"

    def initialize(app)
      @app, @logger = app, Rails::logger.instance_variable_get(:@logger).instance_variable_get(:@log)
      @reports_api_controller_logger = Logger.new(Rails.root.join('log', REPORTS_API_CONTROLLER_LOGFILE), 10, 1000000)
    end

    def call(env)
      Rails::logger
           .instance_variable_get(:@logger)
           .instance_variable_set(:@log,
               case env['PATH_INFO']
               when REPORTS_API_CONTROLLER_PATH then
                 @reports_api_controller_logger
               else
                 @logger
               end
           )
      @app.call(env)
    end
  end
end

Rails.application.middleware.insert_before Rails::Rack::Logger, MyApp::LoggerMiddleware
Run Code Online (Sandbox Code Playgroud)

mes*_*jah 5

您是否尝试过使用around_filter?

class MyController < ApplicationController
  prepend_around_filter :set_logger

  private

  def set_logger
    old_logger = Rails::logger
    Rails::logger = Logger.new(Rails.root.join('log', "reports_controller.log"), 10, 1000000) 
    yield
    Rails.logger = old_logger
  end
end
Run Code Online (Sandbox Code Playgroud)


Ale*_*kin 3

并非所有内容都由控制器过滤器重定向的原因是这些 \xe2\x80\x9cStarted...\xe2\x80\x9d 等是由机架中间件编写的,在控制器实例化之前执行。

\n\n

因此,为了抓住并重定向与某种情况相关的所有内容,人们应该进行更深入的干预。下面是一个关于如何侵入管道的[可能不完整]示例。

\n\n

定义切换记录器的中间件

\n\n
module MyApp\n  class MyMiddleware\n\n    def initialize(app)\n      @app, @logger = app, Rails.logger\n                                .instance_variable_get(:@logger)\n                                .instance_variable_get(:@log)\n      @my_logger = Logger.new(\'reports_controller.log\', ...)\n    end\n\n    def call(env)\n      # env[\'action_dispatch.logger\'].inspect\n      #\xe2\x87\x92 <TaggedLogging... @logger=#<BufferedLogger...> @log_dest=...>\n\n      # here we do not have a controller name\n      Rails.logger\n           .instance_variable_get(:@logger)\n           .instance_variable_set(:@log,\n               case env[\'PATH_INFO\'] # or PATH_INFO, or whatever\n               when %r|\\A/api/v1/| then @my_logger\n               else @logger\n               end\n           )\n\n      @app.call(env)\n    end\n  end\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

在某处添加初始化程序config/initializers/my_logger.rb

\n\n
Rails.application.middleware.insert_before \\\n    Rails::Rack::Logger, MyApp::MyMiddleware\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,Rails\xe2\x80\x99 记录器是一个嵌套的野兽:

\n\n
Rails::logger\n#\xe2\x87\x92 #<ActiveSupport::TaggedLogging:0x000000020f5ad0 @logger=...\nRails::logger.instance_variable_get(:@logger)\n#\xe2\x87\x92 #<ActiveSupport::BufferedLogger:0x000000020f6188 @log_dest=...\nRails::logger.instance_variable_get(:@logger)\n             .instance_variable_get(:@log)\n#\xe2\x87\x92 #<Logger:0x000000020f6138 @progname=nil, @level=0, @default_formatter=...\n
Run Code Online (Sandbox Code Playgroud)\n\n

人们可能想在记录器上设置特定的格式化程序,甚至使用正则表达式过滤消息(尽管这不应该被视为一种好的做法。)

\n