Configure mongrel, rails logger per-port
Courtenay : November 14th, 2006
If you run a pack of mongrels you'll probably want to log per-listener, rather than dumping them into one file. This makes it more difficult to find one particular request, but easier because you can be sure that log lines are in order and consecutive.
Previously the accepted (and easy way) to do this was to use the pid.
config/environments/production.rb
config.logger = Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}.#{Process.pid}.log")
.. creating files like log/production.23321.log. Assuming your mongrels are also logging their pid files as with cluster::start (mongrel.3000.log with the pid embedded) you can tail the log for a particular port by
tail -f production.`cat mongrel.3000.pid`.log
This works well enough but if you have some leaky processes, you'll be killing them and thereby it'll be difficult to find log files. Also, it's a little difficult to type :).
There are two ways to get around this. We need to find the mongrel port number somehow. Since I couldn't immediately discover the way to do this, we hacked at it until it worked.
1. Introspect the object space. Turns out there's a few Mongrel::HttpServer objects floating around.
config/environments/production.rb
ObjectSpace.each_object(Mongrel::HttpServer) { |i| @port = i.port }
raise "Port could not be introspected!" unless @port and @port.to_i > 0
config.logger = Logger.new File.expand_path(RAILS_ROOT+"/log/#{ENV['RAILS_ENV']}.#{@port}.log")
On my app this took <5ms to run, and it only gets run once on startup.
2. Modify mongrel/rails so it exposes the port. Ezra suggested this one. (I haven't tested it) The last line is the new one. You'd add the @_port in the config string above rather than calling ObjectSpace
mongrel/lib/mongrel/rails
# Attempts to resolve the request as follows:
#
# * If the requested exact PATH_INFO exists as a file then serve it.
# * If it exists at PATH_INFO+".html" exists then serve that.
# * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispatch to have Rails go.
def process(request, response)
if response.socket.closed?
return
end
request.instance_variable_set "@_port", @port
(Thanks to Evan Webb, Ezra Zygmuntowicz and Wilson Bilkovich for help with this one)
5 Responses to “Configure mongrel, rails logger per-port”
Leave a Reply
Remember: escape your underscores \_ and indent code at least 4 spaces or incur the wrath of smartypants.
November 14th, 2006 at 04:51 PM
Another approach to consider – I recently released a plugin called custom_benchmarks that allows you to inject arbitrary content into the log file. With the plugin install, adding the PID to the summary line of production.log is as simple as adding one line to your application.rb:
class ApplicationController < ActionController::Base custom_benchmark {|runtime| ” | PID: #{$$}” } ... end
(where the process ID is available through $$)
The resulting log line would look something like this:
Finished JsonController#index in 0.40306 (2 reqs/sec) | Rendering: 0.05003 (12%) | DB: 0.04571 (11%) | Search: 0.16429,1 (40%) | Time: 1163542055 | memcache: 0.00023 (0%) | PID: 22426 | 200 OK [http://www.zvents.com/welcome/index]
As you can see, I’m using the plugin to record other info like search and memcache latency.
Check it out here if you’re interested: http://blog.zvents.com/2006/10/31/rails-plugin-custom-benchmarks
November 15th, 2006 at 06:24 AM
Why don’t you just ask Zed nicely ;-)
May 23rd, 2007 at 08:12 PM
I’m a bit late to the party, but just a quick note to say thanks for this, I was looking for a way to add the port number to the filename and you solved it quite nicely.
One thing though, the object-space solution will break script/console unless you change it to something like
May 23rd, 2007 at 08:41 PM
Oops, spoke too soon… Mongrel isn’t defined in that scope.
March 24th, 2008 at 12:20 PM
Yeah, this will make migrations and console asplode. Here's what I'm using: http://pastie.caboo.se/169850
This includes rotation.