【发布时间】:2016-04-28 10:37:14
【问题描述】:
我已经根据上一个问题 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 用于 Rails.logger(设置为 @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 ....>
我尝试将 getter 替换为 Rails.instance_variable_get(:@logger) 并将 setter 替换为 Rails.instance_variable_set(:@logger,my_logger) 并且它似乎几乎可以工作。活动的第一部分,“已开始...”进入新的日志文件,但之后的所有内容都进入默认日志文件(中间件更改之前的 Rails.logger)。
Rails.instance_variable_get(:@logger) 不是 Rails 4 中与 Rails 3 Rails::logger.instance_variable_get(:@logger).instance_variable_get(:@log) 对应的最低级别,用于获取/设置 Rails.logger,或者在我之后的过程中稍后会有其他东西设置后覆盖它的中间件。
有什么线索吗?
更新:
为了澄清,上面发布的解决方案在 Rails 3 中按预期工作。它在特殊环境中可能存在或不存在的任何限制(例如,如果是这种情况,解决方案可能无法在线程服务器环境中工作)都可以此时并没有遇到障碍,因此这些相同的限制在 Rails 4 解决方案中也可以解决这个问题。
【问题讨论】:
-
Afaik 相同的记录器实例在线程之间共享,因此如果您使用线程服务器,或者希望将来有机会这样做,请确保在处理期间不要切换并行请求的输出的“特殊控制器”(Puma + C Ruby 线程现在是首选 Heroku 部署策略,因此争论不仅仅是学术性的)
-
嗨@bbozo,感谢您的评论。目前我们并没有故意对线程服务器做任何事情。是否有可能默认情况下在某处设置而我不知道?如果我们决定按照您所说的那样实现“线程服务器”,您会建议对这种方法进行哪些修改以便获得相同的结果?
-
嗨@Streamline,Rails 4 应用程序默认是线程化的。这一变化是在 Rails 4 中引入的。在 Rails 3 中,您必须使用
config.threadsafe!显式启用多线程支持。我假设您的 Rails 4 应用程序运行并发线程,这些线程以不确定的方式覆盖 Rails.logger 设置。这可以解释它在一段时间后停止工作。
标签: ruby-on-rails ruby-on-rails-4 logging rack