我已根据前一个问题Redirect logger output for a specific controller in Rails 3为Rails 3的答案构建了一个解决方案。但是现在我正在努力将相同的基于中间件的解决方案应用于Rails 4项目但是那里是一些差异,保持相同的解决方案不起作用。
Rails 3解决方案:
module MyApp
class LoggerMiddleware
REPORTS_API_CONTROLLER_PATH = %r|\A/api/v.*/reports.*|
REPORTS_API_CONTROLLER_LOGFILE = "reports_controller.log"
def initialize(app)
@app = app
@logger = 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
在上面:
Rails 3 getter for Rails.logger = Rails::logger.instance_variable_get(:@logger).instance_variable_get(:@log)
Rails 3 setter (设置为@my_logger)= Rails::logger.instance_variable_get(:@logger).instance_variable_set(:@log,@my_logger)
我立即注意到的一件事是,在Rails 4中,上面的Rails::logger.instance_variable_get(:@logger).instance_variable_get(:@log)
返回nil。
检查Rails 4控制台,我确实看到Rails.instance_variable_get(:@logger)
返回#<ActiveSupport::Logger:0x007f84ff503a08 ....>
我已尝试将{em> getter 替换为Rails.instance_variable_get(:@logger)
,将设置器替换为Rails.instance_variable_set(:@logger,my_logger)
,它几乎可以正常工作。活动的第一部分,&#34;开始......&#34;转到新的日志文件,但之后的所有内容都转到默认日志文件(中间件更改之前的Rails.logger)。
对于获取/设置 Rails.logger,Rails.instance_variable_get(:@logger)
不是Rails 4中Rails 3 Rails::logger.instance_variable_get(:@logger).instance_variable_get(:@log)
中的最低等级,或者稍后会有其他内容在我设置它之后覆盖它的中间件之后的过程。
任何线索?
更新
为了澄清,上面发布的解决方案在Rails 3中按预期工作。在特殊环境中可能会或可能不会有任何限制(例如,如果解决方案可能无法在线程服务器环境中工作,如果是这种情况)可以这一点并没有在此时遇到障碍,因此在这个问题的Rails 4解决方案中,这些相同的限制也是可以的。
答案 0 :(得分:6)
在攻击Rails代码一天后,我想我找到了一个 hack-ish 解决方案来解决你的问题。
您需要修改call
方法和initialize
方法,如下所示:
def initialize(app)
@app = app
@logger = Rails.instance_variable_get(:@logger)
@reports_api_controller_logger = Logger.new(
Rails.root.join('log', REPORTS_API_CONTROLLER_LOGFILE),
10, 1000000)
end
def call(env)
if env['PATH_INFO'] =~ /api\/v.*\/reports.*/
Rails.instance_variable_set(:@logger, @reports_api_controller_logger)
ActionController::Base.logger = @reports_api_controller_logger
ActiveRecord::Base.logger = @reports_api_controller_logger
ActionView::Base.logger = @reports_api_controller_logger
else
Rails.instance_variable_set(:@logger, @logger)
ActionController::Base.logger = @logger
ActiveRecord::Base.logger = @logger
ActionView::Base.logger = @logger
end
@app.call(env)
end
这实际上是 hack-ish 解决方案,并根据您的需要修改正则表达式。
告诉我这是否适合你。
答案 1 :(得分:0)
我不确定您是否需要以与在Rails 3中相同的方式处理解决方案。似乎可能有其他方法可以实现您的最终目标。你有没有考虑过这些方法或宝石?
https://github.com/TwP/logging
How to log something in Rails in an independent log file?
有时候尝试与你已经完成的事情完全不同的事情会有所帮助恕我直言。
这有点猜测,但这可能就是为什么你的getter setter没有按预期工作的原因:https://github.com/rails/rails/commit/6329d9fa8b2f86a178151be264cccdb805bfaaac
关于Jagjot的解决方案并且需要为每个MVC Action Classes设置基本日志,Rails 4默认单独设置它们,这似乎提供了开箱即用的更多灵活性。 http://guides.rubyonrails.org/configuring.html#initializers
答案 2 :(得分:-1)
对于1个控制器使用不同的日志记录类的方法有一个缺点,它不能在线程服务器上工作,现在不仅仅是使用JRuby,而是MRI thanks to Heroku
在给予它一周思考之后,我想到的只有想法是将日志传递给syslog并使用syslog的工具将它们拆分成单独的文件。
仍然需要修补Logger
以包含允许拆分的字符串(例如将#caller
跟踪的格式化内容添加到日志文件中。)
计划B将引入我自己的记录器并简单地记录我在该控制器中需要的内容。例如,如果足够
,您可以轻松地转储参数和响应