Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect logger output for a specific controller in Rails 4

I've built a solution based on the answer in my previous question Redirect logger output for a specific controller in Rails 3 for Rails 3. It works great however now I am trying to apply the same middleware based solution to a Rails 4 project but there are some differences keeping the same solution from working.

The Rails 3 solution:

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

in the above:

Rails 3 getter for Rails.logger = Rails::logger.instance_variable_get(:@logger).instance_variable_get(:@log)

Rails 3 setter for Rails.logger (setting to @my_logger) = Rails::logger.instance_variable_get(:@logger).instance_variable_set(:@log,@my_logger)

One thing I've noticed right away is that in Rails 4 the above Rails::logger.instance_variable_get(:@logger).instance_variable_get(:@log) returns nil.

Checking in Rails 4 console, I do see that Rails.instance_variable_get(:@logger) returns #<ActiveSupport::Logger:0x007f84ff503a08 ....>

I've tried replacing the getter with Rails.instance_variable_get(:@logger) and the setter with Rails.instance_variable_set(:@logger,my_logger) and it almost seems to work. The first part of the activity, the "Started..." goes to the new log file but everything after that goes to the default log file (the Rails.logger before the middleware changed it).

Either Rails.instance_variable_get(:@logger) is not the lowest level equivalent in Rails 4 to the Rails 3 Rails::logger.instance_variable_get(:@logger).instance_variable_get(:@log) for getting/setting the Rails.logger or there is something else later on in the process after my middleware that is overwriting this after I set it.

Any clues?

Update:

To clarify, the solution posted above works as expected in Rails 3. Any limitations it may or may not have in special environments (such as if the solution may not work in threading server environments if that is the case) are ok at this point and not experienced as obstacles at this time therefore these same limitations are also ok in a Rails 4 solution for this question.

like image 323
Streamline Avatar asked Jan 21 '16 23:01

Streamline


1 Answers

After hacking around the Rails code for a day, I think I have found a hack-ish solution to your problem.

You need to edit the call method and initialize method as follow:

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

This is really a hack-ish solution and modify the regex according to your needs.

Tell me if this doesn't work for you.

like image 112
Jagjot Avatar answered Nov 05 '22 18:11

Jagjot