lrd_rack_bug 0.3.0.4 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/lrd_rack_bug.rb +1 -1
 - data/lib/rack/bug.rb +18 -3
 - data/lib/rack/bug/autoloading.rb +1 -0
 - data/lib/rack/bug/panels/log_panel.rb +9 -0
 - data/lib/rack/bug/panels/log_panel/logger_extension.rb +1 -1
 - data/lib/rack/bug/panels/speedtracer_panel.rb +113 -0
 - data/lib/rack/bug/panels/speedtracer_panel/database.rb +64 -0
 - data/lib/rack/bug/panels/speedtracer_panel/instrument.rb +31 -0
 - data/lib/rack/bug/panels/speedtracer_panel/instrumentation.rb +102 -0
 - data/lib/rack/bug/panels/speedtracer_panel/profiling.rb +29 -0
 - data/lib/rack/bug/panels/speedtracer_panel/render.rb +9 -0
 - data/lib/rack/bug/panels/speedtracer_panel/trace-app.rb +56 -0
 - data/lib/rack/bug/panels/speedtracer_panel/tracer.rb +214 -0
 - data/lib/rack/bug/panels/sql_panel.rb +7 -4
 - data/lib/rack/bug/panels/sql_panel/panel_app.rb +8 -6
 - data/lib/rack/bug/panels/sql_panel/query.rb +55 -23
 - data/lib/rack/bug/panels/sql_panel/sql_extension.rb +6 -17
 - data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +6 -15
 - data/lib/rack/bug/public/__rack_bug__/bug.css +5 -1
 - data/lib/rack/bug/views/panels/execute_sql.html.erb +5 -5
 - data/lib/rack/bug/views/panels/explain_sql.html.erb +5 -5
 - data/lib/rack/bug/views/panels/speedtracer/serverevent.html.erb +10 -0
 - data/lib/rack/bug/views/panels/speedtracer/servertrace.html.erb +12 -0
 - data/lib/rack/bug/views/panels/speedtracer/traces.html.erb +16 -0
 - data/lrd_rack_bug.gemspec +11 -10
 - metadata +99 -90
 
| 
         @@ -0,0 +1,214 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Rack::Bug
         
     | 
| 
      
 2 
     | 
    
         
            +
              module SpeedTrace
         
     | 
| 
      
 3 
     | 
    
         
            +
                class TraceRecord
         
     | 
| 
      
 4 
     | 
    
         
            +
                  include Render
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize(id)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @id = id
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @start = Time.now
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @children = []
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  attr_reader :start
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def finish
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @finish ||= Time.now
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def time_in_children
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @children.inject(0) do |time, child|
         
     | 
| 
      
 19 
     | 
    
         
            +
                      time + child.duration
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def duration
         
     | 
| 
      
 24 
     | 
    
         
            +
                    ((@finish - @start) * 1000).to_i
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def to_json
         
     | 
| 
      
 28 
     | 
    
         
            +
                    Yajl::Encoder.encode(hash_representation, :pretty => true, :indent => '  ')
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  private
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # all timestamps in SpeedTracer are in milliseconds
         
     | 
| 
      
 33 
     | 
    
         
            +
                  def range(start, finish)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    {
         
     | 
| 
      
 35 
     | 
    
         
            +
                      'duration'  =>  ((finish - start) * 1000).to_i,
         
     | 
| 
      
 36 
     | 
    
         
            +
                      'start'     =>  [start.to_i,  start.usec/1000].join(''),
         
     | 
| 
      
 37 
     | 
    
         
            +
                      #'end'       =>  [finish.to_i, finish.usec/1000].join('')
         
     | 
| 
      
 38 
     | 
    
         
            +
                    }
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def symbolize_hash(hash)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    hash.each_key do |key|
         
     | 
| 
      
 43 
     | 
    
         
            +
                      if String === key
         
     | 
| 
      
 44 
     | 
    
         
            +
                        next if hash.has_key?(key.to_sym)
         
     | 
| 
      
 45 
     | 
    
         
            +
                        hash[key.to_sym] = hash[key]
         
     | 
| 
      
 46 
     | 
    
         
            +
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                class ServerEvent < TraceRecord
         
     | 
| 
      
 52 
     | 
    
         
            +
                  attr_accessor :children
         
     | 
| 
      
 53 
     | 
    
         
            +
                  attr_reader :name
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  def initialize(id, file, line, method, context, arguments)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    super(id)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                    @file = file
         
     | 
| 
      
 59 
     | 
    
         
            +
                    @line = line
         
     | 
| 
      
 60 
     | 
    
         
            +
                    @method = method
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @context = context
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @arguments = arguments
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @name = [context, method, "(", arguments, ")"].join("")
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  def hash_representation
         
     | 
| 
      
 67 
     | 
    
         
            +
                    {
         
     | 
| 
      
 68 
     | 
    
         
            +
                      'range' => range(@start, @finish),
         
     | 
| 
      
 69 
     | 
    
         
            +
                      #'id' =>  @id,
         
     | 
| 
      
 70 
     | 
    
         
            +
                      'operation' =>  {
         
     | 
| 
      
 71 
     | 
    
         
            +
                      #          'sourceCodeLocation' =>  {
         
     | 
| 
      
 72 
     | 
    
         
            +
                      #          'className'   =>  @file,
         
     | 
| 
      
 73 
     | 
    
         
            +
                      #          'methodName'  =>  @method,
         
     | 
| 
      
 74 
     | 
    
         
            +
                      #          'lineNumber'  =>  @line
         
     | 
| 
      
 75 
     | 
    
         
            +
                      #        },
         
     | 
| 
      
 76 
     | 
    
         
            +
                      'type' =>  'METHOD',
         
     | 
| 
      
 77 
     | 
    
         
            +
                      'label' =>  @name
         
     | 
| 
      
 78 
     | 
    
         
            +
                    },
         
     | 
| 
      
 79 
     | 
    
         
            +
                      'children' =>  @children
         
     | 
| 
      
 80 
     | 
    
         
            +
                    }
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  def to_html
         
     | 
| 
      
 84 
     | 
    
         
            +
                    render_template('panels/speedtracer/serverevent', 
         
     | 
| 
      
 85 
     | 
    
         
            +
                                    {:self_time => duration - time_in_children}.merge(symbolize_hash(hash_representation)))
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                class Tracer < TraceRecord
         
     | 
| 
      
 90 
     | 
    
         
            +
                  def initialize(id, method, uri)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    super(id)
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                    @method = method
         
     | 
| 
      
 94 
     | 
    
         
            +
                    @uri = uri
         
     | 
| 
      
 95 
     | 
    
         
            +
                    @event_id = 0
         
     | 
| 
      
 96 
     | 
    
         
            +
                    @pstack = []
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  #TODO: Threadsafe
         
     | 
| 
      
 100 
     | 
    
         
            +
                  def run(context="::", called_at = caller[0], args=[], &blk)
         
     | 
| 
      
 101 
     | 
    
         
            +
                    file, line, method = called_at.split(':')
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    method = method.gsub(/^in|[^\w]+/, '') if method
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                    start_event(file, line, method, context, args)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    blk.call      # execute the provided code block
         
     | 
| 
      
 107 
     | 
    
         
            +
                    finish_event
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  def short_string(item, max_per_elem = 50)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 112 
     | 
    
         
            +
                      string = item.inspect
         
     | 
| 
      
 113 
     | 
    
         
            +
                      if string.length > max_per_elem
         
     | 
| 
      
 114 
     | 
    
         
            +
                        case item
         
     | 
| 
      
 115 
     | 
    
         
            +
                        when NilClass
         
     | 
| 
      
 116 
     | 
    
         
            +
                          "nil"
         
     | 
| 
      
 117 
     | 
    
         
            +
                        when Hash
         
     | 
| 
      
 118 
     | 
    
         
            +
                          "{ " + item.map do |key, value|
         
     | 
| 
      
 119 
     | 
    
         
            +
                            short_string(key, 15) + "=>" + short_string(value, 30)
         
     | 
| 
      
 120 
     | 
    
         
            +
                          end.join(", ") + " }"
         
     | 
| 
      
 121 
     | 
    
         
            +
                        when find_constant("ActionView::Base")
         
     | 
| 
      
 122 
     | 
    
         
            +
                          tmpl = item.template
         
     | 
| 
      
 123 
     | 
    
         
            +
                          if tmpl.nil?
         
     | 
| 
      
 124 
     | 
    
         
            +
                            item.path.inspect
         
     | 
| 
      
 125 
     | 
    
         
            +
                          else
         
     | 
| 
      
 126 
     | 
    
         
            +
                            [tmpl.base_path, tmpl.name].join("/")
         
     | 
| 
      
 127 
     | 
    
         
            +
                          end
         
     | 
| 
      
 128 
     | 
    
         
            +
                        when find_constant("ActiveRecord::Base")
         
     | 
| 
      
 129 
     | 
    
         
            +
                          string = "#{item.class.name}(#{item.id})" 
         
     | 
| 
      
 130 
     | 
    
         
            +
                        else
         
     | 
| 
      
 131 
     | 
    
         
            +
                          string = item.class.name
         
     | 
| 
      
 132 
     | 
    
         
            +
                        end
         
     | 
| 
      
 133 
     | 
    
         
            +
                      else
         
     | 
| 
      
 134 
     | 
    
         
            +
                        string
         
     | 
| 
      
 135 
     | 
    
         
            +
                      end
         
     | 
| 
      
 136 
     | 
    
         
            +
                    rescue Exception => ex
         
     | 
| 
      
 137 
     | 
    
         
            +
                      "..."
         
     | 
| 
      
 138 
     | 
    
         
            +
                    end
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                  def make_string_of(array)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    array.map do |item|
         
     | 
| 
      
 143 
     | 
    
         
            +
                      short_string(item)
         
     | 
| 
      
 144 
     | 
    
         
            +
                    end.join(",")
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                  def start_event(file, line, method, context, arguments)
         
     | 
| 
      
 148 
     | 
    
         
            +
                    @event_id += 1
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                    arguments_string = make_string_of(arguments)
         
     | 
| 
      
 151 
     | 
    
         
            +
                    event = ServerEvent.new(@event_id, file, line, method, context, arguments_string)
         
     | 
| 
      
 152 
     | 
    
         
            +
                    @pstack.push event
         
     | 
| 
      
 153 
     | 
    
         
            +
                  end
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                  def finish_event
         
     | 
| 
      
 156 
     | 
    
         
            +
                    event = @pstack.pop
         
     | 
| 
      
 157 
     | 
    
         
            +
                    if event.nil?
         
     | 
| 
      
 158 
     | 
    
         
            +
                    else
         
     | 
| 
      
 159 
     | 
    
         
            +
                      event.finish
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                      unless (parent = @pstack.last).nil?
         
     | 
| 
      
 163 
     | 
    
         
            +
                        parent.children.push event
         
     | 
| 
      
 164 
     | 
    
         
            +
                      else
         
     | 
| 
      
 165 
     | 
    
         
            +
                        @children.push event
         
     | 
| 
      
 166 
     | 
    
         
            +
                      end
         
     | 
| 
      
 167 
     | 
    
         
            +
                    end
         
     | 
| 
      
 168 
     | 
    
         
            +
                  end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                  def hash_representation
         
     | 
| 
      
 171 
     | 
    
         
            +
                    finish
         
     | 
| 
      
 172 
     | 
    
         
            +
                    { 'trace' =>  {
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                      'url' => "/speedtracer?id=#@id",
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                      'frameStack' => {
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                        'range' => range(@start, @finish),
         
     | 
| 
      
 179 
     | 
    
         
            +
                        'operation' =>  {
         
     | 
| 
      
 180 
     | 
    
         
            +
                        'type' =>  'HTTP',
         
     | 
| 
      
 181 
     | 
    
         
            +
                        'label' =>  [@method, @uri].join(' ')
         
     | 
| 
      
 182 
     | 
    
         
            +
                      },
         
     | 
| 
      
 183 
     | 
    
         
            +
                        'children' =>  @children
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                      }, #end frameStack
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                        'resources' => {
         
     | 
| 
      
 188 
     | 
    
         
            +
                        'Application' => '/', #Should get the Rails app name...
         
     | 
| 
      
 189 
     | 
    
         
            +
                        'Application.endpoint' => '/' #Should get the env path thing
         
     | 
| 
      
 190 
     | 
    
         
            +
                      }, #From what I can tell, Speed Tracer treats this whole hash as optional
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                        'range' =>  range(@start, @finish)
         
     | 
| 
      
 193 
     | 
    
         
            +
                    }
         
     | 
| 
      
 194 
     | 
    
         
            +
                    }
         
     | 
| 
      
 195 
     | 
    
         
            +
                  end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                  def to_html
         
     | 
| 
      
 198 
     | 
    
         
            +
                    hash = hash_representation
         
     | 
| 
      
 199 
     | 
    
         
            +
                    extra = {:self_time => duration - time_in_children}
         
     | 
| 
      
 200 
     | 
    
         
            +
                    "<a href='#{hash['trace']['url']}'>Raw JSON</a>\n" + 
         
     | 
| 
      
 201 
     | 
    
         
            +
                      render_template('panels/speedtracer/serverevent', extra.merge(symbolize_hash(hash['trace']['frameStack'])))
         
     | 
| 
      
 202 
     | 
    
         
            +
                  end
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
                  def finish
         
     | 
| 
      
 205 
     | 
    
         
            +
                    super()
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                    until @pstack.empty?
         
     | 
| 
      
 208 
     | 
    
         
            +
                      finish_event
         
     | 
| 
      
 209 
     | 
    
         
            +
                    end
         
     | 
| 
      
 210 
     | 
    
         
            +
                    self
         
     | 
| 
      
 211 
     | 
    
         
            +
                  end
         
     | 
| 
      
 212 
     | 
    
         
            +
                end
         
     | 
| 
      
 213 
     | 
    
         
            +
              end
         
     | 
| 
      
 214 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -7,7 +7,7 @@ module Rack 
     | 
|
| 
       7 
7 
     | 
    
         
             
                  require "rack/bug/panels/sql_panel/sql_extension"
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
                  autoload :PanelApp, "rack/bug/panels/sql_panel/panel_app"
         
     | 
| 
       10 
     | 
    
         
            -
                  autoload : 
     | 
| 
      
 10 
     | 
    
         
            +
                  autoload :QueryResult,    "rack/bug/panels/sql_panel/query"
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                  def panel_app
         
     | 
| 
       13 
13 
     | 
    
         
             
                    PanelApp.new
         
     | 
| 
         @@ -18,14 +18,14 @@ module Rack 
     | 
|
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                    start_time = Time.now
         
     | 
| 
       20 
20 
     | 
    
         
             
                    result = block.call
         
     | 
| 
       21 
     | 
    
         
            -
                    queries <<  
     | 
| 
      
 21 
     | 
    
         
            +
                    queries << QueryResult.new(sql, Time.now - start_time, backtrace)
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                    return result
         
     | 
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                  def self.record_event(sql, duration, backtrace = [])
         
     | 
| 
       27 
27 
     | 
    
         
             
                    return unless Rack::Bug.enabled?
         
     | 
| 
       28 
     | 
    
         
            -
                    queries <<  
     | 
| 
      
 28 
     | 
    
         
            +
                    queries << QueryResult.new(sql, duration, backtrace)
         
     | 
| 
       29 
29 
     | 
    
         
             
                  end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                  def self.reset
         
     | 
| 
         @@ -37,7 +37,10 @@ module Rack 
     | 
|
| 
       37 
37 
     | 
    
         
             
                  end
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
39 
     | 
    
         
             
                  def self.total_time
         
     | 
| 
       40 
     | 
    
         
            -
                    (queries.inject(0)  
     | 
| 
      
 40 
     | 
    
         
            +
                    (queries.inject(0) do |memo, query| 
         
     | 
| 
      
 41 
     | 
    
         
            +
                      Rails.logger.debug{ "QTime: #{query.time}" }
         
     | 
| 
      
 42 
     | 
    
         
            +
                      memo + query.time
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end) * 1_000
         
     | 
| 
       41 
44 
     | 
    
         
             
                  end
         
     | 
| 
       42 
45 
     | 
    
         | 
| 
       43 
46 
     | 
    
         
             
                  def name
         
     | 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rack/bug/panels/sql_panel/query'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Rack
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Bug
         
     | 
| 
       3 
5 
     | 
    
         
             
                class SQLPanel
         
     | 
| 
         @@ -15,20 +17,20 @@ module Rack 
     | 
|
| 
       15 
17 
     | 
    
         | 
| 
       16 
18 
     | 
    
         
             
                    def explain_sql
         
     | 
| 
       17 
19 
     | 
    
         
             
                      validate_params
         
     | 
| 
       18 
     | 
    
         
            -
                      query =  
     | 
| 
       19 
     | 
    
         
            -
                      render_template "panels/explain_sql", : 
     | 
| 
      
 20 
     | 
    
         
            +
                      query = ExplainResult.new(params["query"], params["time"].to_f)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      render_template "panels/explain_sql", :query => query
         
     | 
| 
       20 
22 
     | 
    
         
             
                    end
         
     | 
| 
       21 
23 
     | 
    
         | 
| 
       22 
24 
     | 
    
         
             
                    def profile_sql
         
     | 
| 
       23 
25 
     | 
    
         
             
                      validate_params
         
     | 
| 
       24 
     | 
    
         
            -
                      query =  
     | 
| 
       25 
     | 
    
         
            -
                      render_template "panels/profile_sql", : 
     | 
| 
      
 26 
     | 
    
         
            +
                      query = ProfileResult.new(params["query"], params["time"].to_f)
         
     | 
| 
      
 27 
     | 
    
         
            +
                      render_template "panels/profile_sql", :query => query
         
     | 
| 
       26 
28 
     | 
    
         
             
                    end
         
     | 
| 
       27 
29 
     | 
    
         | 
| 
       28 
30 
     | 
    
         
             
                    def execute_sql
         
     | 
| 
       29 
31 
     | 
    
         
             
                      validate_params
         
     | 
| 
       30 
     | 
    
         
            -
                      query =  
     | 
| 
       31 
     | 
    
         
            -
                      render_template "panels/execute_sql", : 
     | 
| 
      
 32 
     | 
    
         
            +
                      query = QueryResult.new(params["query"], params["time"].to_f)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      render_template "panels/execute_sql", :query => query
         
     | 
| 
       32 
34 
     | 
    
         
             
                    end
         
     | 
| 
       33 
35 
     | 
    
         | 
| 
       34 
36 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -2,7 +2,7 @@ module Rack 
     | 
|
| 
       2 
2 
     | 
    
         
             
              class Bug
         
     | 
| 
       3 
3 
     | 
    
         
             
                class SQLPanel
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
                  class  
     | 
| 
      
 5 
     | 
    
         
            +
                  class QueryResult
         
     | 
| 
       6 
6 
     | 
    
         
             
                    include Rack::Bug::FilteredBacktrace
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                    attr_reader :sql
         
     | 
| 
         @@ -12,36 +12,43 @@ module Rack 
     | 
|
| 
       12 
12 
     | 
    
         
             
                      @sql = sql
         
     | 
| 
       13 
13 
     | 
    
         
             
                      @time = time
         
     | 
| 
       14 
14 
     | 
    
         
             
                      @backtrace = backtrace
         
     | 
| 
      
 15 
     | 
    
         
            +
                      @results = nil
         
     | 
| 
       15 
16 
     | 
    
         
             
                    end
         
     | 
| 
       16 
17 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
                    def  
     | 
| 
       18 
     | 
    
         
            -
                       
     | 
| 
      
 18 
     | 
    
         
            +
                    def result
         
     | 
| 
      
 19 
     | 
    
         
            +
                      @results ||= execute
         
     | 
| 
      
 20 
     | 
    
         
            +
                      return @results
         
     | 
| 
       19 
21 
     | 
    
         
             
                    end
         
     | 
| 
       20 
22 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                    def  
     | 
| 
       22 
     | 
    
         
            -
                       
     | 
| 
      
 23 
     | 
    
         
            +
                    def column_names
         
     | 
| 
      
 24 
     | 
    
         
            +
                      if result.respond_to?(:fields)
         
     | 
| 
      
 25 
     | 
    
         
            +
                        return result.fields
         
     | 
| 
      
 26 
     | 
    
         
            +
                      else
         
     | 
| 
      
 27 
     | 
    
         
            +
                        return result.fetch_fields.map{|col| col.name}
         
     | 
| 
      
 28 
     | 
    
         
            +
                      end
         
     | 
| 
       23 
29 
     | 
    
         
             
                    end
         
     | 
| 
       24 
30 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                    def  
     | 
| 
       26 
     | 
    
         
            -
                       
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
                       
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 31 
     | 
    
         
            +
                    def rows
         
     | 
| 
      
 32 
     | 
    
         
            +
                      if result.respond_to?(:values)
         
     | 
| 
      
 33 
     | 
    
         
            +
                        result.values
         
     | 
| 
      
 34 
     | 
    
         
            +
                      else
         
     | 
| 
      
 35 
     | 
    
         
            +
                        result.map do |row|
         
     | 
| 
      
 36 
     | 
    
         
            +
                          row
         
     | 
| 
      
 37 
     | 
    
         
            +
                        end
         
     | 
| 
      
 38 
     | 
    
         
            +
                      end
         
     | 
| 
       30 
39 
     | 
    
         
             
                    end
         
     | 
| 
       31 
40 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                    def  
     | 
| 
       33 
     | 
    
         
            -
                       
     | 
| 
      
 41 
     | 
    
         
            +
                    def human_time
         
     | 
| 
      
 42 
     | 
    
         
            +
                      "%.2fms" % (@time * 1_000)
         
     | 
| 
       34 
43 
     | 
    
         
             
                    end
         
     | 
| 
       35 
44 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
                    def  
     | 
| 
       37 
     | 
    
         
            -
                       
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                        SQL
         
     | 
| 
       44 
     | 
    
         
            -
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
                    def inspectable?
         
     | 
| 
      
 46 
     | 
    
         
            +
                      sql.strip =~ /^SELECT /i
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    #Downside is: we re-execute the SQL...
         
     | 
| 
      
 50 
     | 
    
         
            +
                    def self.execute(sql)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      ActiveRecord::Base.connection.execute(sql)
         
     | 
| 
       45 
52 
     | 
    
         
             
                    end
         
     | 
| 
       46 
53 
     | 
    
         | 
| 
       47 
54 
     | 
    
         
             
                    def execute
         
     | 
| 
         @@ -52,12 +59,37 @@ module Rack 
     | 
|
| 
       52 
59 
     | 
    
         
             
                      hash = Digest::SHA1.hexdigest [secret_key, @sql].join(":")
         
     | 
| 
       53 
60 
     | 
    
         
             
                      possible_hash == hash
         
     | 
| 
       54 
61 
     | 
    
         
             
                    end
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
       55 
63 
     | 
    
         | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
      
 64 
     | 
    
         
            +
                  class ExplainResult < QueryResult
         
     | 
| 
      
 65 
     | 
    
         
            +
                    def execute
         
     | 
| 
      
 66 
     | 
    
         
            +
                      self.class.execute "EXPLAIN #{@sql}"
         
     | 
| 
       58 
67 
     | 
    
         
             
                    end
         
     | 
| 
       59 
68 
     | 
    
         
             
                  end
         
     | 
| 
       60 
69 
     | 
    
         | 
| 
      
 70 
     | 
    
         
            +
                  class ProfileResult < QueryResult
         
     | 
| 
      
 71 
     | 
    
         
            +
                    def with_profiling
         
     | 
| 
      
 72 
     | 
    
         
            +
                      result = nil
         
     | 
| 
      
 73 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 74 
     | 
    
         
            +
                        self.class.execute("SET PROFILING=1")
         
     | 
| 
      
 75 
     | 
    
         
            +
                        result = yield
         
     | 
| 
      
 76 
     | 
    
         
            +
                      ensure
         
     | 
| 
      
 77 
     | 
    
         
            +
                        self.class.execute("SET PROFILING=0")
         
     | 
| 
      
 78 
     | 
    
         
            +
                      end
         
     | 
| 
      
 79 
     | 
    
         
            +
                      return result
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    def execute
         
     | 
| 
      
 83 
     | 
    
         
            +
                      with_profiling do
         
     | 
| 
      
 84 
     | 
    
         
            +
                        super
         
     | 
| 
      
 85 
     | 
    
         
            +
                        self.class.execute <<-SQL
         
     | 
| 
      
 86 
     | 
    
         
            +
                          SELECT *
         
     | 
| 
      
 87 
     | 
    
         
            +
                            FROM information_schema.profiling
         
     | 
| 
      
 88 
     | 
    
         
            +
                           WHERE query_id = (SELECT query_id FROM information_schema.profiling ORDER BY query_id DESC LIMIT 1)
         
     | 
| 
      
 89 
     | 
    
         
            +
                        SQL
         
     | 
| 
      
 90 
     | 
    
         
            +
                      end
         
     | 
| 
      
 91 
     | 
    
         
            +
                    end
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
       61 
93 
     | 
    
         
             
                end
         
     | 
| 
       62 
94 
     | 
    
         
             
              end
         
     | 
| 
       63 
95 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,22 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            if defined?(ActiveRecord) && defined?(ActiveRecord::ConnectionAdapters)
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
                  event = ActiveSupport::Notifications::Event.new(*args)
         
     | 
| 
       7 
     | 
    
         
            -
                  Rack::Bug::SQLPanel.record_event(event.payload[:sql], event.duration) # TODO: is there any way to get a backtrace out of here?
         
     | 
| 
       8 
     | 
    
         
            -
                end
         
     | 
| 
       9 
     | 
    
         
            -
              else
         
     | 
| 
       10 
     | 
    
         
            -
              
         
     | 
| 
       11 
     | 
    
         
            -
                ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
         
     | 
| 
       12 
     | 
    
         
            -
                  def log_with_rack_bug(sql, name, &block)
         
     | 
| 
       13 
     | 
    
         
            -
                    Rack::Bug::SQLPanel.record(sql, Kernel.caller) do
         
     | 
| 
       14 
     | 
    
         
            -
                      log_without_rack_bug(sql, name, &block)
         
     | 
| 
       15 
     | 
    
         
            -
                    end
         
     | 
| 
      
 2 
     | 
    
         
            +
              ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
         
     | 
| 
      
 3 
     | 
    
         
            +
                def log_with_rack_bug(sql, name, &block)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  Rack::Bug::SQLPanel.record(sql, Kernel.caller) do
         
     | 
| 
      
 5 
     | 
    
         
            +
                    log_without_rack_bug(sql, name, &block)
         
     | 
| 
       16 
6 
     | 
    
         
             
                  end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                  alias_method_chain :log, :rack_bug
         
     | 
| 
       19 
7 
     | 
    
         
             
                end
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                alias_method_chain :log, :rack_bug
         
     | 
| 
       21 
10 
     | 
    
         
             
              end
         
     | 
| 
       22 
11 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,21 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            if defined?(ActionView) && defined?(ActionView::Template)
         
     | 
| 
       2 
     | 
    
         
            -
               
     | 
| 
      
 2 
     | 
    
         
            +
              ActionView::Template.class_eval do
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
     | 
    
         
            -
                 
     | 
| 
       5 
     | 
    
         
            -
                   
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
                end
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
              else
         
     | 
| 
       10 
     | 
    
         
            -
                ActionView::Template.class_eval do
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
                  def render_template_with_rack_bug(*args, &block)
         
     | 
| 
       13 
     | 
    
         
            -
                    Rack::Bug::TemplatesPanel.record(path_without_format_and_extension) do
         
     | 
| 
       14 
     | 
    
         
            -
                      render_template_without_rack_bug(*args, &block)
         
     | 
| 
       15 
     | 
    
         
            -
                    end
         
     | 
| 
      
 4 
     | 
    
         
            +
                def render_with_rack_bug(*args, &block)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  Rack::Bug::TemplatesPanel.record(virtual_path) do
         
     | 
| 
      
 6 
     | 
    
         
            +
                    render_without_rack_bug(*args, &block)
         
     | 
| 
       16 
7 
     | 
    
         
             
                  end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                  alias_method_chain :render_template, :rack_bug
         
     | 
| 
       19 
8 
     | 
    
         
             
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                alias_method_chain :render, :rack_bug
         
     | 
| 
       20 
11 
     | 
    
         
             
              end
         
     | 
| 
       21 
12 
     | 
    
         
             
            end
         
     |