重定向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) 

在控制器的顶部,但只有在操作中专门使用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"}} 

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

基本上我希望报告控制器的所有日志记录都在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 

不是所有的东西都被控制器filter重定向的原因是这些“Started ……”等是由机架中间件编写的,这是控制器被实例化之前执行的。

因此,要抓住并重定向与某些条件相关的所有内容 ,应该更深入地干涉。 以下是关于如何入侵管道的[可能不完整]示例。

定义中间件以切换记录器

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

config/initializers/my_logger.rb某处添加config/initializers/my_logger.rb

 Rails.application.middleware.insert_before \ Rails::Rack::Logger, MyApp::MyMiddleware 

请注意,Rails的记录器是嵌套的野兽:

 Rails::logger #⇒ # 

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

你有没有尝试过pre_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 

要添加@ messanjah的答案,您可以覆盖这些记录器: Rails::logger, ActionView::Base.logger, ActionController::Base.logger, ActiveRecord::Base.logger

通过抑制这些记录器,您可以摆脱大多数消息。 但正如@mudasobwa指出的那样……消息是在控制器之前写的。

如果您不想使用中间件,您可以随时使用锤子和monkeypatch Rails::Rack::Logger来使用您的记录器应用程序。 或者您可以检查路径并拒绝某些消息。