diff options
Diffstat (limited to 'lib/mongrel')
-rw-r--r-- | lib/mongrel/debug.rb | 144 | ||||
-rw-r--r-- | lib/mongrel/handlers.rb | 23 | ||||
-rw-r--r-- | lib/mongrel/rails.rb | 74 |
3 files changed, 241 insertions, 0 deletions
diff --git a/lib/mongrel/debug.rb b/lib/mongrel/debug.rb new file mode 100644 index 0000000..8b2dd5c --- /dev/null +++ b/lib/mongrel/debug.rb @@ -0,0 +1,144 @@ +require 'logger' +require 'set' + + +$mongrel_debugging=true + +module MongrelDbg + SETTINGS = { :tracing => {}} + LOGGING = { } + + def MongrelDbg::configure(log_dir = "mongrel_debug") + Dir.mkdir(log_dir) if not File.exist?(log_dir) + @log_dir = log_dir + end + + + def MongrelDbg::trace(target, message) + if SETTINGS[:tracing][target] + LOGGING[target].log(Logger::DEBUG, message) + end + end + + def MongrelDbg::begin_trace(target) + SETTINGS[:tracing][target] = true + if not LOGGING[target] + LOGGING[target] = Logger.new(File.join(@log_dir, "#{target.to_s}.log")) + end + MongrelDbg::trace(target, "TRACING ON #{Time.now}") + end + + def MongrelDbg::end_trace(target) + SETTINGS[:tracing][target] = false + MongrelDbg::trace(target, "TRACING OFF #{Time.now}") + LOGGING[target].close + LOGGING[target] = nil + end +end + + +module ObjectTracker + @active_objects = nil + @live_object_tracking = false + + def ObjectTracker.configure + @active_objects = Set.new + ObjectSpace.each_object do |obj| + @active_objects << obj.object_id + end + srand @active_objects.object_id + @sample_thread = Thread.new do + loop do + sleep(rand(3) + (rand(100)/100.0)) + ObjectTracker.sample + end + end + @sample_thread.priority = 20 + end + + def ObjectTracker.start + @stopit = true + @live_object_tracking = true + @stopit = false + end + + def ObjectTracker.stop + @live_object_tracking = false + end + + def ObjectTracker.sample + ospace = Set.new + ObjectSpace.each_object do |obj| + ospace << obj.object_id + end + + dead_objects = @active_objects - ospace + new_objects = ospace - @active_objects + live_objects = ospace & @active_objects + + STDERR.puts "#{dead_objects.length},#{new_objects.length},#{live_objects.length}" + + @active_objects = live_objects + new_objects + end + +end + +class Class + alias_method :orig_new, :new + + @@count = 0 + @@stoppit = false + @@class_caller_count = Hash.new{|hash,key| hash[key] = Hash.new(0)} + + def new(*arg,&blk) + unless @@stoppit + @@stoppit = true + @@count += 1 + @@class_caller_count[self][caller[0]] += 1 + @@stoppit = false + end + orig_new(*arg,&blk) + end + + + def Class.report_object_creations + @@stoppit = true + puts "Number of objects created = #{@@count}" + + total = Hash.new(0) + + @@class_caller_count.each_key do |klass| + caller_count = @@class_caller_count[klass] + caller_count.each_value do |count| + total[klass] += count + end + end + + klass_list = total.keys.sort{|klass_a, klass_b| + a = total[klass_a] + b = total[klass_b] + if a != b + -1* (a <=> b) + else + klass_a.to_s <=> klass_b.to_s + end + } + klass_list.each do |klass| + puts "#{total[klass]}\t#{klass} objects created." + caller_count = @@class_caller_count[ klass] + caller_count.keys.sort_by{|call| -1*caller_count[call]}.each do |call| + puts "\t#{call}\tCreated #{caller_count[call]} #{klass} objects." + end + puts + end + end + + def Class.reset_object_creations + @@stopit = true + @@count = 0 + @@class_caller_count = Hash.new{|hash,key| hash[key] = Hash.new(0)} + @@stoppit = false + end +end + + diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb index 609a252..7d817bb 100644 --- a/lib/mongrel/handlers.rb +++ b/lib/mongrel/handlers.rb @@ -5,9 +5,32 @@ module Mongrel # just the minimum necessary for you to handle a request and shoot back # a response. Look at the HttpRequest and HttpResponse objects for how # to use them. + # + # This is used for very simple handlers that don't require much to operate. + # More extensive plugins or those you intend to distribute as GemPlugins + # should be implemented using the HttpHandlerPlugin mixin. + # class HttpHandler + + def process(request, response) + end + end + + + # This is used when your handler is implemented as a GemPlugin. + # The plugin always takes an options hash which you can modify + # and then access later. They are stored by default for + # the process method later. + module HttpHandlerPlugin + attr_reader :options + + def initialize(options={}) + @options = options + end + def process(request, response) end + end diff --git a/lib/mongrel/rails.rb b/lib/mongrel/rails.rb index fb4e172..808d7d3 100644 --- a/lib/mongrel/rails.rb +++ b/lib/mongrel/rails.rb @@ -1,6 +1,62 @@ require 'mongrel' require 'cgi' +# Creates Rails specific configuration options for people to use +# instead of the base Configurator. +class RailsConfigurator < Mongrel::Configurator + + # Used instead of Mongrel::Configurator.uri to setup + # a rails application at a particular URI. Requires + # the following options: + # + # * :docroot => The public dir to serve from. + # * :environment => Rails environment to use. + # + # And understands the following optional settings: + # + # * :mime => A map of mime types. + # + # Because of how Rails is designed you can only have + # one installed per Ruby interpreter (talk to them + # about thread safety). This function will abort + # with an exception if called more than once. + def rails(location, options={}) + ops = resolve_defaults(options) + + # fix up some defaults + ops[:environment] ||= "development" + ops[:docroot] ||= "public" + ops[:mime] ||= {} + + if @rails_handler + raise "You can only register one RailsHandler for the whole Ruby interpreter. Complain to the ordained Rails core about thread safety." + end + + $orig_dollar_quote = $".clone + ENV['RAILS_ENV'] = ops[:environment] + require 'config/environment' + require 'dispatcher' + require 'mongrel/rails' + + @rails_handler = RailsHandler.new(ops[:docroot], ops[:mime]) + end + + + # Reloads rails. This isn't too reliable really, but + # should work for most minimal reload purposes. Only reliable + # way it so stop then start the process. + def reload! + if not @rails_handler + raise "Rails was not configured. Read the docs for RailsConfigurator." + end + + STDERR.puts "Reloading rails..." + @rails_handler.reload! + STDERR.puts "Done reloading rails." + + end +end + # Implements a handler that can run Rails and serve files out of the # Rails application's public directory. This lets you run your Rails # application with Mongrel during development and testing, then use it @@ -83,3 +139,21 @@ class RailsHandler < Mongrel::HttpHandler end end end + + +if $mongrel_debugging + + # Tweak the rails handler to allow for tracing + class RailsHandler + alias :real_process :process + + def process(request, response) + MongrelDbg::trace(:rails, "REQUEST #{Time.now}\n" + request.params.to_yaml) + + real_process(request, response) + + MongrelDbg::trace(:rails, "REQUEST #{Time.now}\n" + request.params.to_yaml) + end + end + +end |