From 3ae2e799f15d8de683d59d1dd9c43988b6f189ff Mon Sep 17 00:00:00 2001 From: Jonathan del Strother Date: Wed, 11 May 2011 05:31:39 -0700 Subject: [PATCH] Rack response body should be an array, not a string --- app/metal/scrap.rb | 378 ++++++++++++++++++++++----------------------- 1 file changed, 189 insertions(+), 189 deletions(-) mode change 100755 => 100644 app/metal/scrap.rb diff --git a/app/metal/scrap.rb b/app/metal/scrap.rb old mode 100755 new mode 100644 index 5e39cec..6afe635 --- a/app/metal/scrap.rb +++ b/app/metal/scrap.rb @@ -1,190 +1,190 @@ -class Scrap < Rails::Rack::Metal - PATH = "/stats/scrap".freeze - COMMIFY_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/ - CRLF = "\r\n" - - @@gc_stats = {} - @@last_gc_run = nil - @@last_gc_mem = nil - @@requests_processed = 0 - @@request_list = [] - @@alive_at = nil - @@gc_stats_enabled = nil - @@config = nil - - def self.config - @@config ||= YAML::load open(File.join(Rails.root, "config", "scrap.yml")).read - rescue Errno::ENOENT - @@config = {} - rescue - puts "[scrap] scrap.yml: #{$!.message}" - @@config = {} - end - - def self.call(env) - if !@@gc_stats_enabled then - GC.enable_stats if GC.respond_to? :enable_stats - @@gc_stats_enabled = true - end - @@requests_processed += 1 - @@last_gc_run ||= @@alive_at ||= Time.now.to_f - @@last_gc_mem ||= get_usage - - req = sprintf("

[%-10.2fMB] %s %s

", get_usage, env["REQUEST_METHOD"], env["PATH_INFO"]) - req << "
#{ObjectSpace.statistics}
" if ObjectSpace.respond_to? :statistics - @@request_list.unshift req - @@request_list.pop if @@request_list.length > (config["max_requests"] || 150) - - if env["PATH_INFO"] == PATH - gc_stats - else - NotFoundResponse - end - end - - def self.gc_stats - collected = nil - puts "Respond to? #{ObjectSpace.respond_to? :live_objects}" - if ObjectSpace.respond_to? :live_objects then - live = ObjectSpace.live_objects - GC.start - collected = live - ObjectSpace.live_objects - else - GC.start - end - GC.start - usage = get_usage - - mem_delta = usage - @@last_gc_mem - time_delta = Time.now.to_f - @@last_gc_run - s = '' - s << '' << CRLF - s << '' << CRLF - s << "[#{$$}] Garbage Report" << CRLF - s << '' << CRLF - s << '' << CRLF - - s << "

Scrap - PID #{$$}

" << CRLF - - s << '' << CRLF - s << sprintf('', usage) - s << sprintf('', mem_delta) - s << sprintf('', time_delta) - s << sprintf('', @@requests_processed) - s << sprintf('', Time.now.to_f - @@alive_at) - if GC.respond_to? :time then - s << sprintf('', GC.time / 1000000.0) - end - if collected - s << sprintf('', collected) - s << sprintf('', ObjectSpace.live_objects) - end - s << '
Memory usage:%2.2fMB
Delta:%2.2fMB
Last Scrap req:%2.2f seconds ago
Requests processed:%s
Alive for:%2.2f seconds
Time spent in GC:%2.2f seconds
Collected objects:%2d
Live objects:%2d
' << CRLF - - s << "

Top #{config["max_objects"]} deltas since last request

" - s << '' - memcheck(config["max_objects"], Object, :deltas).each do |v| - next if v.last == 0 - s << "" - end - s << '
#{v.first}#{sprintf("%s%s", v.last >= 0 ? "+" : "-", commify(v.last))}
' - - s << "

Top #{config["max_objects"]} objects

" - s << '' - memcheck(config["max_objects"]).each do |v| - s << "" - end - s << '
#{v.first}#{commify v.last}
' - - (config["classes"] || {}).each do |klass, val| - puts val.inspect - opts = val === true ? {"print_objects" => true} : val - add_os(klass.constantize, s, opts) - end - - s << '

Request history

' - @@request_list.each do |req| - s << req - end - s << '' - - @@last_gc_run = Time.now.to_f - @@last_gc_mem = usage - @@requests_processed = 0 - [200, {"Content-Type" => "text/html"}, s] - end - - def self.get_usage - usage = 0 - begin - usage = `cat /proc/#{$$}/stat`.split(" ")[22].to_i / (1024 * 1024).to_f - rescue - # pass - end - return usage - end - - def self.add_os(c, s, options = {}) - print_objects = options["print_objects"] - small = options["small"] - min = options["min"] - show_fields = options["show_fields"] - - ct = ObjectSpace.each_object(c) {} - return if min and ct < min - - if small - s << "#{c} (#{ct})
" - else - s << "

#{c} (#{ct})

" - end - - return if !print_objects or ct == 0 - s << CRLF - s << '' - val = ObjectSpace.each_object(c) do |m| - s << '" - if show_fields then - show_fields.each do |field| - v = m.attributes[field.to_s] - if v.blank? - s << '' - else - s << "" - end - end - end - s << '' - end - s << '
' << "<#{m.class.to_s}:#{sprintf("0x%.8x", m.object_id)}> #{field}: #{v}
' << CRLF - end - - def self.memcheck(top, klass = Object, mode = :normal) - top ||= 50 - os = Hash.new(0) - ObjectSpace.each_object(klass) do |o| - begin; - # If this is true, it's an association proxy, and we don't want to invoke method_missing on it, - # as it will result in a load of the association proxy from the DB, doing extra DB work and - # potentially creating a lot of AR objects. Hackalicious. - next if o.respond_to? :proxy_respond_to? - os[o.class.to_s] += 1 if o.respond_to? :class - rescue; end - end - if mode == :deltas then - os2 = Hash.new(0) - os.each do |k, v| - os2[k] = v - (@@gc_stats[k] || 0) - @@gc_stats[k] = v - end - sorted = os2.sort_by{|k,v| -v }.first(top) - else - sorted = os.sort_by{|k,v| -v }.first(top) - end - end - - def self.commify(i) - i.to_s.gsub(COMMIFY_REGEX, "\\1,") - end +class Scrap < Rails::Rack::Metal + PATH = "/stats/scrap".freeze + COMMIFY_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/ + CRLF = "\r\n" + + @@gc_stats = {} + @@last_gc_run = nil + @@last_gc_mem = nil + @@requests_processed = 0 + @@request_list = [] + @@alive_at = nil + @@gc_stats_enabled = nil + @@config = nil + + def self.config + @@config ||= YAML::load open(File.join(Rails.root, "config", "scrap.yml")).read + rescue Errno::ENOENT + @@config = {} + rescue + puts "[scrap] scrap.yml: #{$!.message}" + @@config = {} + end + + def self.call(env) + if !@@gc_stats_enabled then + GC.enable_stats if GC.respond_to? :enable_stats + @@gc_stats_enabled = true + end + @@requests_processed += 1 + @@last_gc_run ||= @@alive_at ||= Time.now.to_f + @@last_gc_mem ||= get_usage + + req = sprintf("

[%-10.2fMB] %s %s

", get_usage, env["REQUEST_METHOD"], env["PATH_INFO"]) + req << "
#{ObjectSpace.statistics}
" if ObjectSpace.respond_to? :statistics + @@request_list.unshift req + @@request_list.pop if @@request_list.length > (config["max_requests"] || 150) + + if env["PATH_INFO"] == PATH + gc_stats + else + NotFoundResponse + end + end + + def self.gc_stats + collected = nil + puts "Respond to? #{ObjectSpace.respond_to? :live_objects}" + if ObjectSpace.respond_to? :live_objects then + live = ObjectSpace.live_objects + GC.start + collected = live - ObjectSpace.live_objects + else + GC.start + end + GC.start + usage = get_usage + + mem_delta = usage - @@last_gc_mem + time_delta = Time.now.to_f - @@last_gc_run + s = [] + s << '' << CRLF + s << '' << CRLF + s << "[#{$$}] Garbage Report" << CRLF + s << '' << CRLF + s << '' << CRLF + + s << "

Scrap - PID #{$$}

" << CRLF + + s << '' << CRLF + s << sprintf('', usage) + s << sprintf('', mem_delta) + s << sprintf('', time_delta) + s << sprintf('', @@requests_processed) + s << sprintf('', Time.now.to_f - @@alive_at) + if GC.respond_to? :time then + s << sprintf('', GC.time / 1000000.0) + end + if collected + s << sprintf('', collected) + s << sprintf('', ObjectSpace.live_objects) + end + s << '
Memory usage:%2.2fMB
Delta:%2.2fMB
Last Scrap req:%2.2f seconds ago
Requests processed:%s
Alive for:%2.2f seconds
Time spent in GC:%2.2f seconds
Collected objects:%2d
Live objects:%2d
' << CRLF + + s << "

Top #{config["max_objects"]} deltas since last request

" + s << '' + memcheck(config["max_objects"], Object, :deltas).each do |v| + next if v.last == 0 + s << "" + end + s << '
#{v.first}#{sprintf("%s%s", v.last >= 0 ? "+" : "-", commify(v.last))}
' + + s << "

Top #{config["max_objects"]} objects

" + s << '' + memcheck(config["max_objects"]).each do |v| + s << "" + end + s << '
#{v.first}#{commify v.last}
' + + (config["classes"] || {}).each do |klass, val| + puts val.inspect + opts = val === true ? {"print_objects" => true} : val + add_os(klass.constantize, s, opts) + end + + s << '

Request history

' + @@request_list.each do |req| + s << req + end + s << '' + + @@last_gc_run = Time.now.to_f + @@last_gc_mem = usage + @@requests_processed = 0 + [200, {"Content-Type" => "text/html"}, s] + end + + def self.get_usage + usage = 0 + begin + usage = `cat /proc/#{$$}/stat`.split(" ")[22].to_i / (1024 * 1024).to_f + rescue + # pass + end + return usage + end + + def self.add_os(c, s, options = {}) + print_objects = options["print_objects"] + small = options["small"] + min = options["min"] + show_fields = options["show_fields"] + + ct = ObjectSpace.each_object(c) {} + return if min and ct < min + + if small + s << "#{c} (#{ct})
" + else + s << "

#{c} (#{ct})

" + end + + return if !print_objects or ct == 0 + s << CRLF + s << '' + val = ObjectSpace.each_object(c) do |m| + s << '" + if show_fields then + show_fields.each do |field| + v = m.attributes[field.to_s] + if v.blank? + s << '' + else + s << "" + end + end + end + s << '' + end + s << '
' << "<#{m.class.to_s}:#{sprintf("0x%.8x", m.object_id)}> #{field}: #{v}
' << CRLF + end + + def self.memcheck(top, klass = Object, mode = :normal) + top ||= 50 + os = Hash.new(0) + ObjectSpace.each_object(klass) do |o| + begin; + # If this is true, it's an association proxy, and we don't want to invoke method_missing on it, + # as it will result in a load of the association proxy from the DB, doing extra DB work and + # potentially creating a lot of AR objects. Hackalicious. + next if o.respond_to? :proxy_respond_to? + os[o.class.to_s] += 1 if o.respond_to? :class + rescue; end + end + if mode == :deltas then + os2 = Hash.new(0) + os.each do |k, v| + os2[k] = v - (@@gc_stats[k] || 0) + @@gc_stats[k] = v + end + sorted = os2.sort_by{|k,v| -v }.first(top) + else + sorted = os.sort_by{|k,v| -v }.first(top) + end + end + + def self.commify(i) + i.to_s.gsub(COMMIFY_REGEX, "\\1,") + end end \ No newline at end of file