How to split up rails 3.x logger by unicorn workers

January 11, 2013 Ryan Ong

TLDR: Put this in your unicorn config. Make sure not to have duplicate after_fork calls

after_fork do |server, worker|
  if defined?(ActiveSupport::TaggedLogging) && Rails.logger.kind_of?(ActiveSupport::TaggedLogging)
    Rails.logger.instance_eval do
      level = @logger.level
      # flush and close logger to make sure we don't cut off any potential logging before this
      @logger && @logger.flush && @logger.close
      @logger = ActiveSupport::BufferedLogger.new(Rails.root.join("log", "rails_#{Rails.env}.#{worker.nr}.log").to_s, level)
    end
  elsif Rails.logger.kind_of?(ActiveSupport::BufferedLogger)
    Rails.logger.instance_eval do
      @log && @log.flush && @log.close
      @log_path = Rails.root.join("log", "rails_#{Rails.env}.#{worker.nr}.log").to_s
      if respond_to?(:open_logfile, true)
        @log = open_logfile(@log_path)
      elsif respond_to?(:open_log, true)
        if File.exist?(@log_path)
          @log = open_log(@log_path, (File::WRONLY | File::APPEND))
        else
          FileUtils.mkdir_p(File.dirname(@log_path))
          @log = open_log(l@log_path, (File::WRONLY | File::APPEND | File::CREAT))
        end
      end
    end
  end
end

How this works!

There is no easy way to change the path of a log or swap out the logger. When rails is instantiated ActionController and ActiveRecord assigns their local logger from Rails.logger. So if you reassign Rails.logger to a new one ActionController and ActiveRecord will continue to use the old rails logger.

There are no methods to change or swap out the log path in the Logging class. In order to change the log path we have to change instance variables to either a new logger or a new file handler.

In Rails 3.2 ActiveSupport::TaggedLogging was added!
If you look here you can see how Rails.logger is assigned! (source)
As you can see TaggedLogging basically just wraps a buffered logger. So when we open up Rails.logger we can patch what TaggedLogging wraps by modifying the @logger variable.
If TaggedLogging isn’t used we can use the open_logfile command and just insert a path.

In Rails 3.0 and Rails 3.1 TaggedLogging isn’t used and by default uses BufferedLogger.
We have to create a new file handler using the open_log method and reassign the @log variable.

About the Author

Biography

More Content by Ryan Ong
Previous
How Do TV Viewers Tweet? Depends.
How Do TV Viewers Tweet? Depends.

Twitter is a veritable gold mine of real-time social data for advertisers, brands, and entertainment studio...

Next
How to render jade templates on the server
How to render jade templates on the server

The best way for Google and friends to crawl and index a page is by finding static content. With applicatio...

Enter curious. Exit smarter.

Learn More