Ruby on Rails on FastCGI on Apache is a pretty fast and robust combination. Unfortunately FastCGI do doesn’t like output on “standard out”, i.e. $stdout in Ruby. Brian Pontarelli has an article concerning the problem. His suggestion is to simply have no puts
in your code. The standard lib of Ruby however sometimes prints exceptions to the console – REXML is one popular example.
Brian also mentions the idea to redirect anything printed to $stdout to a logger. That means however, that all output given by web servers like Webrick would also end up in some log file – which isn’t the best thing for your development and debugging sessions.
Eric Hodel on the other hand found a pretty nice way to redirect $stdout for only some Ruby threads.
Using those two techniques I came up with a solution that turns on $stdout redirection with the beginning of an HTTP request and turns it off once the Rails controller finished its work. Problem solved 😉 – everything printed to $stdout in your controllers will end up in your development/production/test.log.
Here’s the code:
# in app/controllers/application.rb class ApplicationController < ActionController::Base # ... class StdOutLogger def write(s) if Thread.current[:stdout_to_logger] RAILS_DEFAULT_LOGGER.info s else $stdout_default.write s end end end before_filter do unless $stdout_logger $stdout_default = $stdout.clone $stdout_logger = StdOutLogger.new end $stdout = $stderr = $stdout_logger Thread.current[:stdout_to_logger] = true end after_filter { !(Thread.current[:stdout_to_logger] = false) } # ... end
One thing that may be a problem: I don't know on which semaphore to synchronize - the beast may not be thread safe. This depends on your FastCGI stack. I didn't experience any problems up to now.