rack-insight 0.5.16 → 0.5.17

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,10 +1,36 @@
1
- == 0.5.16 / 2012-09-11
1
+ == HEAD
2
+
3
+ == 0.5.17 / 2012-09-13 - Peter Boling
4
+
5
+ * New Features
6
+
7
+ * MagicInsight! WARNING: Magic is dangerous.
8
+
9
+ * MagicInsight is a new mixin that can be used by any 'stat' type class built for Rack::Bug / LogicalInsight / Rack::Insight.
10
+ Just include Rack::Insight::MagicInsight in your stat class and then to render call:
11
+
12
+ render_template 'magic_panel', :magic_insights => your_stat_object, :name => 'panel name'
13
+
14
+ Read the source for Rack::Insight::MagicInsight and heed the warnings.
15
+ MagicInsight is used internally by Rack::Insight for magic panels and the templates panel.
16
+
17
+ * Bug Fixes
18
+
19
+ * Fixed the hardly working TemplatesPanel (Issue 1)
20
+ * Correct logging/debug statements
21
+ * Better tracking of which panels are probing
22
+
23
+ * Other
24
+
25
+ * TemplatesPanel is now more aligned with the Rack::Insight Panel API.
26
+
27
+ == 0.5.16 / 2012-09-11 - Peter Boling
2
28
 
3
29
  * Other
4
30
 
5
31
  * Improved handling of no content for a panel.
6
32
 
7
- == 0.5.14-15 / 2012-09-11
33
+ == 0.5.14-15 / 2012-09-11 - Peter Boling
8
34
 
9
35
  * New Features
10
36
 
@@ -15,7 +41,7 @@
15
41
  * Auto-magical table creation (skipped with self.has_table = false in a Panel class definition)
16
42
  * Under construction, or blank, panels have more scaffolding
17
43
 
18
- == 0.5.13 / 2012-09-10
44
+ == 0.5.13 / 2012-09-10 - Peter Boling
19
45
 
20
46
  * Bug Fixes
21
47
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rack-insight (0.5.14)
4
+ rack-insight (0.5.16)
5
5
  rack
6
6
  sqlite3 (>= 1.3.3)
7
7
  uuidtools (>= 2.1.2)
@@ -4,6 +4,8 @@ require "rack/insight/config"
4
4
  require "rack/insight/logging"
5
5
  require "rack/insight/filtered_backtrace"
6
6
  require "rack/insight/options"
7
+ require 'rack/insight/magic_insight'
8
+ require 'rack/insight/default_invocation'
7
9
  require "rack/insight/panel"
8
10
  require "rack/insight/panel_app"
9
11
  require "rack/insight/params_signature"
@@ -1,7 +1,8 @@
1
1
  module Rack::Insight
2
2
  class Config
3
3
  class << self
4
- attr_reader :config, :verbosity, :log_file, :log_level, :rails_log_copy, :filtered_backtrace
4
+ attr_reader :config, :verbosity, :log_file, :log_level, :rails_log_copy,
5
+ :filtered_backtrace, :panel_configs, :silence_magic_insight_warnings
5
6
  end
6
7
  @log_file = STDOUT
7
8
  @log_level = ::Logger::DEBUG
@@ -24,6 +25,7 @@ module Rack::Insight
24
25
  end ] },
25
26
  :templates => {:probes => {'ActionView::Template' => [:instance, :render]}}
26
27
  }
28
+ @silence_magic_insight_warnings = false
27
29
 
28
30
  DEFAULTS = {
29
31
  # You can augment or replace the default set of panel load paths.
@@ -42,7 +44,8 @@ module Rack::Insight
42
44
  # Can set a specific verbosity: Rack::Insight::Logging::VERBOSITY[:debug]
43
45
  :verbosity => @verbosity, # true is equivalent to relying soley on the log level of each logged message
44
46
  :filtered_backtrace => @filtered_backtrace, # Full backtraces, or filtered ones?
45
- :panel_configs => @panel_configs # Allow specific panels to have their own configurations, and make it extensible
47
+ :panel_configs => @panel_configs, # Allow specific panels to have their own configurations, and make it extensible
48
+ :silence_magic_insight_warnings => @silence_magic_insight_warnings # Should Rack::Insight warn when the MagicInsight is used?
46
49
  }
47
50
 
48
51
  @config ||= DEFAULTS
@@ -54,6 +57,7 @@ module Rack::Insight
54
57
  @log_file = config[:log_file]
55
58
  @verbosity = config[:verbosity]
56
59
  @filtered_backtrace = config[:filtered_backtrace]
60
+ @silence_magic_insight_warnings = config[:silence_magic_insight_warnings]
57
61
 
58
62
  config[:panel_configs].each do |panel_name_sym, config|
59
63
  set_panel_config(panel_name_sym, config)
@@ -0,0 +1,22 @@
1
+ # For Magic Panels
2
+ module Rack::Insight
3
+ class DefaultInvocation < Struct.new :method, :time, :arguments, :result, :backtrace
4
+ attr_accessor :method, :time, :arguments, :result, :backtrace
5
+
6
+ include Rack::Insight::FilteredBacktrace
7
+ include Rack::Insight::MagicInsight
8
+
9
+ def initialize(*args)
10
+ @method = args[0]
11
+ @time = [args[1].duration, args[1].delta_t]
12
+ @arguments = args[2]
13
+ @result = args[3]
14
+ @backtrace = args[4]
15
+ end
16
+
17
+ def human_time
18
+ "%.2fms" % (self.time * 1_000)
19
+ end
20
+
21
+ end
22
+ end
@@ -2,7 +2,7 @@ require 'rack/insight/instrumentation/package-definition'
2
2
  module Rack::Insight::Instrumentation
3
3
  module Client
4
4
  def probe(collector, &block)
5
- self.class.is_probed = true
5
+ collector.class.is_probing = true
6
6
  ::Rack::Insight::Instrumentation::PackageDefinition::probe(collector, &block)
7
7
  end
8
8
 
@@ -0,0 +1,114 @@
1
+ # See the WARNING constant defined below for explanation
2
+ module Rack::Insight
3
+ module MagicInsight
4
+
5
+ # A modicum of sanity
6
+ SAFETY_REGEX_FILTER = (/(^_)|[=\?!~<>]|save|record|persist|delete|destroy|add|remove|child|parent/).freeze
7
+
8
+ WARNING = [
9
+ " # PROCEED CAREFULLY!",
10
+ " #",
11
+ " # Regarding classes which include this module:",
12
+ " #",
13
+ " # 1. Classes should be built specifically to be rendered by rack-insight,",
14
+ " # and not have destructive methods.",
15
+ " # 2. ALL instance methods on the class (generally not from ancestors) will be called,",
16
+ " # so if any are destructive you will cry.",
17
+ " # 3. Define ALL: Any instance methods that get past the safety regex filter.",
18
+ " # 4. Define safety regex filter: Rack::Insight::MagicInsight::SAFETY_REGEX_FILTER is",
19
+ " #",
20
+ " # #{SAFETY_REGEX_FILTER.inspect}",
21
+ " #",
22
+ " # 5. To reiterate: all methods that do not match the above will be called.",
23
+ " #",
24
+ " # Classes that desire to be renderable by the magic_panel templates must:",
25
+ " #",
26
+ " # include Rack::Insight::MagicInsight.",
27
+ " #",
28
+ " # 6. This gives explicit approval for rack-insight to call all the instance methods on your class,",
29
+ " # including the kill_server method (if you have one)."
30
+ ].freeze
31
+
32
+ # Regex explanation:
33
+ # Rack::Insight - We want to keep methods that come from Rack::Insight included modules
34
+ # #<Class: - An ancestor matching this is probably from a class definition like this:
35
+ # class FooStats < Struct.new :foo, :bar
36
+ # We need to keep :foo and :bar from the anonymous Struct ancestor
37
+ ANCESTORS_FILTER = /^Rack::Insight|#<Class:/.freeze
38
+
39
+ IDIOMS = %w( backtrace time duration timing )
40
+
41
+ def self.included(base)
42
+ # Make sure people want to eat their lunch before we serve it to them.
43
+ # Allows Rack::Insight namespaced classes to use MagicInsight without warnings.
44
+ if Rack::Insight::Config.config[:silence_magic_insight_warnings] || base.to_s =~ /^Rack::Insight/
45
+ # crickets...
46
+ else
47
+ warn "Rack::Insight::MagicInsight has been included in #{base}.\n#{WARNING.join("\n")}"
48
+ raise 'Checking for dupes impossible.' if base.instance_methods.include?(:dirty_ancestors)
49
+ end
50
+ end
51
+
52
+ def _dirty_ancestors
53
+ self.class.ancestors[1..-1]
54
+ end
55
+
56
+ def _filtered_ancestors
57
+ _dirty_ancestors.select {|c| !(c.to_s =~ ANCESTORS_FILTER)}
58
+ end
59
+
60
+ def _dirty_methods
61
+ self.class.instance_methods - (_filtered_ancestors.map &:instance_methods).flatten
62
+ end
63
+
64
+ def _filtered_methods
65
+ _dirty_methods.select {|x| !(x =~ Rack::Insight::MagicInsight::SAFETY_REGEX_FILTER)}.sort
66
+ end
67
+
68
+ def _sorted_methods
69
+ _filtered_methods.sort {|a,b| a.to_s.length <=> b.to_s.length }
70
+ end
71
+
72
+ # If there are two methods matching an idiom, then we only want to render one of the two.
73
+ # If there are more than two, then make no assumptions
74
+ def _idiomatic_methods
75
+ IDIOMS.select {|idiom| _sorted_methods.select { |meth| meth.to_s =~ /#{idiom}/ }.length == 2 }
76
+ end
77
+
78
+ def _has_idioms?
79
+ !_idiomatic_methods.empty?
80
+ end
81
+
82
+ def _idiomatic_method(method)
83
+ if self._has_idioms? && method = self._idiomatic_methods.select {|idiom| method.to_s =~ /#{idiom}/}.first
84
+ method
85
+ else
86
+ false
87
+ end
88
+ end
89
+
90
+ def _my_children
91
+ "#{!children.empty? ? " (#{children.length} children)" : ''}" if self.respond_to?(:children)
92
+ end
93
+
94
+ # called by the templates
95
+ def _magic_insight_methods
96
+ # We want to keep the longer of the methods by num chars in the method name, because these are the ones meant for
97
+ # humans to see (e.g. human_time, filtered_backtrace, display_time)
98
+ sorted = _sorted_methods
99
+ idiomatic = _idiomatic_methods
100
+ # So we delete the shorter of the two
101
+ idiomatic.each do |idiom|
102
+ sorted.each_with_index do |meth, index|
103
+ # first one found will be the shortest, so delete and move to next idiom
104
+ if meth.to_s =~ /#{idiom}/
105
+ sorted.delete_at(index)
106
+ break # to idiomatic loop
107
+ end
108
+ end
109
+ end
110
+ sorted
111
+ end
112
+
113
+ end
114
+ end
@@ -20,8 +20,8 @@ module Rack::Insight
20
20
 
21
21
  include Rack::Insight::Logging
22
22
 
23
- attr_accessor :template_root, :is_probed, :has_table, :is_magic
24
- @is_probed = false # Once a panel is probed this should be set to true
23
+ attr_accessor :template_root, :is_probing, :has_table, :is_magic
24
+ @is_probing = false # Once a panel is probed this should be set to true
25
25
  @has_table = true # default to true. Panels without tables override with self.has_table = false
26
26
  @is_magic = false # check this to wrap any functionality targeted at magic panels.
27
27
 
@@ -37,7 +37,7 @@ module Rack::Insight
37
37
 
38
38
  def from_file(rel_path)
39
39
  old_rel, Thread::current['rack-panel_file'] = Thread::current['rack-panel_file'], rel_path
40
- load_paths_to_check = Rack::Insight::Config.config[:panel_load_paths].length
40
+ num_load_paths_to_check = Rack::Insight::Config.config[:panel_load_paths].length
41
41
  Rack::Insight::Config.config[:panel_load_paths].each_with_index do |load_path, index|
42
42
  begin
43
43
  require File::join(load_path, rel_path)
@@ -45,8 +45,10 @@ module Rack::Insight
45
45
  rescue LoadError => e
46
46
  # TODO: If probes are defined for this panel, instantiate a magic panel
47
47
  # if self.has_custom_probes?
48
- if (index + 1) == load_paths_to_check # You have failed me for the last time!
49
- warn "Rack::Insight #{e.class}: Unable to find panel specified as '#{rel_path}'. Looked in the following :panel_load_paths: #{Rack::Insight::Config.config[:panel_load_paths].inspect}."
48
+ if !verbose(:high) && (index + 1) == num_load_paths_to_check # You have failed me for the last time!
49
+ warn "Rack::Insight #{e.class} while attempting to load '#{rel_path}' from :panel_load_paths #{Rack::Insight::Config.config[:panel_load_paths].inspect}."
50
+ elsif verbose(:high)
51
+ warn "Rack::Insight #{e.class} #{e.message} while attempting to load '#{rel_path}' from :panel_load_paths #{Rack::Insight::Config.config[:panel_load_paths].inspect} (just checked: #{load_path})."
50
52
  end
51
53
  end
52
54
  end
@@ -143,7 +145,14 @@ module Rack::Insight
143
145
  if !has_table?
144
146
  table_setup(self.name)
145
147
  end
146
- #puts "Initalization Complete for #{panel_name}\n1. #{self.is_magic?} && 2. #{self.has_table?} && 3. #{self.is_probed?} 4. #{self.has_custom_probes?}"
148
+ end
149
+
150
+ #def inspect
151
+ # "M:#{self.bool_prop(:is_magic?)} T:#{self.bool_prop(:has_table?)} P:#{self.bool_prop(:is_probing?)} C:#{self.bool_prop(:has_custom_probes?)} Name: #{name}"
152
+ #end
153
+
154
+ def bool_prop(prop)
155
+ self.send(prop) ? 'Y' : 'N'
147
156
  end
148
157
 
149
158
  def call(env)
@@ -178,12 +187,11 @@ module Rack::Insight
178
187
  true
179
188
  end
180
189
 
181
- def is_probed?
182
- !!self.class.is_probed
190
+ def is_probing?
191
+ !!self.class.is_probing
183
192
  end
184
193
 
185
194
  def has_custom_probes?(panel_name = self.underscored_name.to_sym)
186
- #puts "Rack::Insight::Config.config[:panel_configs][#{panel_name.inspect}]: #{Rack::Insight::Config.config[:panel_configs][panel_name].inspect}"
187
195
  Rack::Insight::Config.config[:panel_configs][panel_name].respond_to?(:[]) &&
188
196
  !Rack::Insight::Config.config[:panel_configs][panel_name][:probes].nil?
189
197
  end
@@ -206,6 +214,7 @@ module Rack::Insight
206
214
  if word == 'Panel'
207
215
  word = words[-2] # Panel class is Panel... and this won't do.
208
216
  end
217
+ # This bit from rails probably isn't needed here, and wouldn't work anyways.
209
218
  #word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
210
219
  word.gsub!(/Panel$/,'')
211
220
  word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
@@ -239,13 +248,13 @@ module Rack::Insight
239
248
  if !self.has_table?
240
249
  logger.info("#{self.class} is being used without a table") if verbose(:med)
241
250
  content
242
- elsif self.is_probed?
251
+ elsif self.is_probing? # Checking probed because we only get here when the subclass panel hasn't overridden this method
243
252
  invocations = retrieve(number)
244
- if invocations.length > 0 && invocations.first.is_a?(Rack::Insight::Panel::DefaultInvocation)
245
- logger.info("Rack::Insight is using magic content for #{self.class}, which is probed")# if verbose(:med)
246
- render_template 'default_invocation', :invocations => invocations, :name => self.camelized_name
253
+ if invocations.length > 0
254
+ logger.info("Rack::Insight is using #{self.is_magic? ? 'magic' : 'default'} content for #{self.class}, which is probed")# if verbose(:med)
255
+ render_template 'magic_panel', :magic_insights => invocations, :name => self.camelized_name
247
256
  else
248
- logger.info("Rack::Insight has no data for magic content for #{self.class}, which is probed")# if verbose(:med)
257
+ logger.info("Rack::Insight has no data for #{self.is_magic? ? 'magic' : 'default'} content for #{self.class}, which is probed")
249
258
  render_template 'no_data', :name => self.camelized_name
250
259
  end
251
260
  else
@@ -266,9 +275,8 @@ module Rack::Insight
266
275
  # Override in subclasses.
267
276
  # This is to make magic classes work.
268
277
  def after_detect(method_call, timing, args, result)
269
- #puts "Default After Detect for #{self.underscored_name}: 1. #{self.is_magic?} && 2. #{self.has_table?} && 3. #{self.is_probed?}"
270
- if self.is_magic? && self.has_table? && self.is_probed?
271
- store(@env, DefaultInvocation.new(method_call.method.to_s, timing, args, result, method_call.backtrace[2..-1]))
278
+ if self.is_magic? && self.has_table? && self.is_probing?
279
+ store(@env, Rack::Insight::DefaultInvocation.new(method_call.method.to_s, timing, args, result, method_call.backtrace[2..-1]))
272
280
  end
273
281
  end
274
282
 
@@ -281,26 +289,6 @@ module Rack::Insight
281
289
  def render(template)
282
290
  end
283
291
 
284
- # For Magic Panels
285
- class DefaultInvocation < Struct.new :method, :time, :arguments, :result, :backtrace
286
- attr_accessor :method, :time, :arguments, :result, :backtrace
287
-
288
- include Rack::Insight::FilteredBacktrace
289
-
290
- def initialize(*args)
291
- @method = args[0]
292
- @time = [args[1].duration, args[1].delta_t]
293
- @arguments = args[2]
294
- @result = args[3]
295
- @backtrace = args[4]
296
- end
297
-
298
- def human_time
299
- "%.2fms" % (self.time * 1_000)
300
- end
301
-
302
- end
303
-
304
292
  end
305
293
 
306
294
  end
@@ -26,7 +26,7 @@ module Rack::Insight
26
26
  # Call super before setting up probes in case there are any custom probes configured
27
27
  super # will setup custom probes
28
28
 
29
- unless is_probed?
29
+ unless is_probing?
30
30
  probe(self) do
31
31
  # Trying to be smart...
32
32
  if defined?(ActiveSupport)
@@ -1,45 +1,49 @@
1
1
  module Rack::Insight
2
-
3
2
  class TemplatesPanel < Panel
4
- require "rack/insight/panels/templates_panel/rendering"
5
-
6
- def initialize(app)
7
- super
8
-
9
- @current = nil
10
- end
11
-
3
+ require "rack/insight/panels/templates_panel/stats"
12
4
 
13
5
  def request_start(env, start)
14
- @current = Rendering.new("root")
6
+ @stats = Rack::Insight::TemplatesPanel::Stats.new("root")
15
7
  end
16
8
 
17
9
  def request_finish(env, status, headers, body, timing)
18
- store(env, @current)
19
- @current = nil
10
+ @stats.finish!
11
+ store(env, @stats)
12
+ @stats = nil
20
13
  end
21
14
 
22
15
  def before_detect(method_call, args)
23
16
  template_name = method_call.object.virtual_path
24
-
25
17
  rendering = Rendering.new(template_name)
26
- @current.add(rendering)
27
- @current = rendering
18
+ @stats.begin_record!(rendering)
28
19
  end
29
20
 
30
21
  def after_detect(method_call, timing, args, result)
31
- @current.timing = timing
32
- @current = @current.parent
22
+ @stats.finish_record!(timing.duration)
33
23
  end
34
24
 
35
25
  def heading_for_request(number)
36
- "Templates: %.2fms" % (retrieve(number).inject(0.0){|memo, rendering| memo + rendering.duration})
26
+ "Templates: #{heading_time(number)}"
27
+ end
28
+
29
+ def heading_time(number)
30
+ stat = retrieve(number).first
31
+ if stat.respond_to?(:root)
32
+ if stat.root.respond_to?(:_human_time)
33
+ stat.root._human_time
34
+ end
35
+ end
37
36
  end
38
37
 
39
38
  def content_for_request(number)
40
- render_template "panels/templates", :root_rendering => retrieve(number).first
39
+ stat = retrieve(number).first
40
+ rendering_root = stat.root if stat.respond_to?(:root)
41
+ if rendering_root
42
+ render_template 'magic_panel', :magic_insights => rendering_root.children, :name => "Templates: #{(rendering_root._human_time)}"
43
+ else
44
+ render_template 'no_data', :name => self.camelized_name
45
+ end
41
46
  end
42
47
 
43
48
  end
44
-
45
49
  end
@@ -2,79 +2,69 @@ module Rack::Insight
2
2
  class TemplatesPanel
3
3
 
4
4
  class Rendering
5
- attr_accessor :name
5
+
6
+ include Rack::Insight::MagicInsight
7
+
8
+ attr_accessor :template
9
+ attr_accessor :partial
6
10
  attr_accessor :parent
7
- attr_accessor :timing
8
11
  attr_reader :children
9
12
 
10
- def initialize(name, timing = nil)
11
- @name = name
12
- @timing = timing
13
- @children = []
14
- end
13
+ # '_' prevents MagicInsight template from calling the method
14
+ # Time tracking
15
+ attr_accessor :_time, :_exclusive_time, :_child_time
15
16
 
16
- def start_time
17
- @timing.start
18
- end
19
- alias_method :time, :start_time
20
-
21
- def end_time
22
- @timing.end
17
+ def initialize(template)
18
+ @template = template.to_s
19
+ @partial = template.partial ? 'yes' : 'no' if template.respond_to?(:partial)
20
+ @_time = 0
21
+ @_exclusive_time = 0
22
+ @_child_time = 0
23
+ @children = []
24
+ @parent = nil
23
25
  end
24
26
 
25
- def add(rendering)
27
+ # called from Stats#begin_record
28
+ def add!(rendering)
26
29
  @children << rendering
27
30
  rendering.parent = self
28
31
  end
29
32
 
30
- def delete(rendering)
31
- @children.delete(rendering)
33
+ # LOL what?
34
+ #def delete(rendering)
35
+ # @children.delete(rendering)
36
+ #end
37
+
38
+ def finish!(timing)
39
+ self._time = timing || 0
40
+ self._child_time = _calculate_child_time
41
+ self._exclusive_time = _calculate_exclusive_time
32
42
  end
33
43
 
34
- def duration
35
- if @timing
36
- @timing.duration
37
- else
38
- child_duration
39
- end
44
+ def _calculate_exclusive_time
45
+ _time - _child_time
40
46
  end
41
47
 
42
- def exclusive_duration
43
- duration - child_duration
48
+ def _calculate_child_time
49
+ children.inject(0.0) { |memo, c| memo + c._time } || 0
44
50
  end
45
51
 
46
- def child_duration
47
- children.inject(0.0) { |memo, c| memo + c.duration }
52
+ def _human_time(t = self._time)
53
+ "%.2fms" % t
48
54
  end
49
55
 
50
- def duration_summary
56
+ def time_summary
51
57
  if children.any?
52
- "%.2fms, %.2f exclusive" % [duration, exclusive_duration]
58
+ "#{_human_time}, (exclusive: #{_human_time(_exclusive_time)}, child: #{_human_time(_child_time)}"
53
59
  else
54
- "%.2fms" % (duration)
60
+ _human_time
55
61
  end
56
62
  end
57
- def html
58
- <<-HTML
59
- <li>
60
- <p>#{name} (#{duration_summary})</p>
61
63
 
62
- #{children_html}
63
- </li>
64
- HTML
64
+ def to_s
65
+ "#{template} (#{time_summary})#{!children.empty? ? " (#{children.length} children)\n#{children.map {|x| x.to_s}.join("\n")}" : ''}"
65
66
  end
66
67
 
67
- def children_html
68
- return "" unless children.any?
69
-
70
- <<-HTML
71
- <ul>#{joined_children_html}</ul>
72
- HTML
73
- end
74
-
75
- def joined_children_html
76
- children.map { |c| c.html }.join
77
- end
78
68
  end
79
69
 
80
70
  end
@@ -0,0 +1,40 @@
1
+ module Rack::Insight
2
+ class TemplatesPanel
3
+ class Stats
4
+ require 'rack/insight/panels/templates_panel/rendering'
5
+
6
+ include Rack::Insight::Logging
7
+
8
+ attr_reader :root, :current
9
+
10
+ def initialize(*args)
11
+ @root = Rack::Insight::TemplatesPanel::Rendering.new(*args)
12
+ @current = @root
13
+ end
14
+
15
+ # Track when each template starts being rendered
16
+ def begin_record!(rendering)
17
+ @current.add!(rendering) # Add the rendering as a child of the current and make rendering the new current
18
+ @current = rendering
19
+ end
20
+
21
+ # Track when each template finishes being rendered, move current back up the rendering chain
22
+ def finish_record!(timing)
23
+ # This is the one being completed now, and for which we now know the timing duration
24
+ @current.finish!(timing)
25
+ # Prepare for the next template to finish
26
+ @current = @current.parent
27
+ end
28
+
29
+ def finish!
30
+ @root.finish!(root._calculate_child_time)
31
+ @current = nil
32
+ end
33
+
34
+ def to_s
35
+ "#{self.root.to_s}"
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -23,12 +23,18 @@
23
23
  cursor: pointer;
24
24
  }
25
25
  .rack-insight_bottom #rack-insight_toolbar {
26
- bottom:0;
27
26
  border-top: 2px solid #234f32;
27
+ height: auto;
28
+ clear: both;
29
+ position: relative;
30
+ z-index: 10;
31
+ margin-top: -3em;
28
32
  }
33
+
29
34
  .rack-insight_top #rack-insight_toolbar {
30
35
  top:0;
31
36
  border-bottom: 2px solid #234f32;
37
+ height: auto;
32
38
  }
33
39
 
34
40
  .rack-insight_error #rack-insight_toolbar {
@@ -105,11 +111,11 @@
105
111
  }
106
112
 
107
113
  #rack-insight.rack-insight_top .panel_content {
108
- top: 32px;
114
+ top: auto;
109
115
  }
110
116
 
111
117
  #rack-insight.rack-insight_bottom .panel_content {
112
- bottom: 32px;
118
+ bottom: auto;
113
119
  }
114
120
 
115
121
  #rack-insight .panel_content p a,
@@ -1,7 +1,7 @@
1
1
  module Rack
2
2
  module Insight
3
3
 
4
- VERSION = '0.5.16'
4
+ VERSION = '0.5.17'
5
5
 
6
6
  end
7
7
  end
@@ -0,0 +1,22 @@
1
+ <tr class="<%=row_class%>">
2
+ <%- magic_insight._magic_insight_methods.each do |method| %>
3
+ <%- result = magic_insight.send(method) %>
4
+ <%- if result.respond_to?(:each) %>
5
+ <td>
6
+ <%- result.each do |line| %>
7
+ <%= line.inspect %><br/>
8
+ <%- end %>
9
+ </td>
10
+ <%- else %>
11
+ <td>
12
+ <%= result %>
13
+ </td>
14
+ <%- end %>
15
+ </td>
16
+ <%- end %>
17
+ <%- if details %>
18
+ <td>
19
+ <a class="reveal_backtrace" href="javascript:void(0);"><%= magic_insight._my_children %></a>
20
+ </td>
21
+ <%- end %>
22
+ </tr>
@@ -0,0 +1,67 @@
1
+ <%- if magic_insights.kind_of?(Array) %>
2
+ <%- magic_insight = magic_insights.last %>
3
+ <%- else %>
4
+ <%- magic_insight = magic_insights %>
5
+ <%- end %>
6
+ <%- if magic_insight.class.ancestors.include?(Rack::Insight::MagicInsight) %>
7
+ <table class="sortable">
8
+ <thead>
9
+ <tr>
10
+ <%- magic_insight._magic_insight_methods.each do |method| %>
11
+ <%- if idiomatic_method = magic_insight._idiomatic_method(method) %>
12
+ <th><%= idiomatic_method %></th>
13
+ <%- else %>
14
+ <th><%= method %></th>
15
+ <%- end %>
16
+ <%- end %>
17
+ <th></th>
18
+ </tr>
19
+ </thead>
20
+ <tbody>
21
+ <%- if magic_insights.respond_to?(:each) %>
22
+ <%- i = 1 %>
23
+ <%- magic_insights.each do |an_object| %>
24
+ <%- row_class = i % 2 == 0 ? 'even' : 'odd'
25
+ details = an_object.respond_to?(:children) && !an_object.children.empty?
26
+ %>
27
+ <%= render_template 'magic_insight', :magic_insight => an_object, :row_class => row_class, :details => details %>
28
+ <%- if details %>
29
+ <tr style="display:none">
30
+ <td colspan="<%= magic_insight._magic_insight_methods.length + 1%>">
31
+ <%= render_template 'magic_insights', :magic_insights => an_object.children %>
32
+ </td>
33
+ </tr>
34
+ <%- end %>
35
+ <%- i += 1 %>
36
+ <%- end %>
37
+ <%- else %>
38
+ <%- details = magic_insights.respond_to?(:children) && !magic_insights.children.empty? %>
39
+ <%= render_template 'magic_insight', :magic_insight => magic_insights, :row_class => 'odd', :details => details %>
40
+ <%- if details %>
41
+ <tr style="display:none">
42
+ <td colspan="<%= magic_insights._magic_insight_methods.length + 1%>">
43
+ <%= render_template 'magic_insights', :magic_insights => magic_insights.children %>
44
+ </td>
45
+ </tr>
46
+ <%- end %>
47
+ <%- end %>
48
+ </tbody>
49
+ </table>
50
+ <%- elsif !magic_insight.nil? %>
51
+ <h3>Magic Panel Template for <%= magic_insight.class %></h3>
52
+ <p>If you want to have the magic panel template render your data first <strong>read the warning below</strong></p>
53
+ <h3>WARNING</h3>
54
+ <p>
55
+ <pre>
56
+ <%= Rack::Insight::MagicInsight::WARNING.join('<br/>').gsub(/\s/,'&nbsp;') %>
57
+ </pre>
58
+ </p>
59
+ <p>If you are sure, do the following in your class to be rendered by this template:</p>
60
+ <p>
61
+ <pre>
62
+ include Rack::Insight::MagicInsight
63
+ </pre>
64
+ </p>
65
+ <%- else %>
66
+ <p>nil is non-magical</p>
67
+ <%- end %>
@@ -0,0 +1,2 @@
1
+ <h3><%= name %></h3>
2
+ <%= render_template 'magic_insights', :magic_insights => magic_insights %>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-insight
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.16
4
+ version: 0.5.17
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-09-11 00:00:00.000000000 Z
15
+ date: 2012-09-13 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rack
@@ -220,6 +220,7 @@ files:
220
220
  - lib/rack/insight/app.rb
221
221
  - lib/rack/insight/config.rb
222
222
  - lib/rack/insight/database.rb
223
+ - lib/rack/insight/default_invocation.rb
223
224
  - lib/rack/insight/enable-button.rb
224
225
  - lib/rack/insight/filtered_backtrace.rb
225
226
  - lib/rack/insight/instrumentation.rb
@@ -231,6 +232,7 @@ files:
231
232
  - lib/rack/insight/instrumentation/probe.rb
232
233
  - lib/rack/insight/instrumentation/setup.rb
233
234
  - lib/rack/insight/logging.rb
235
+ - lib/rack/insight/magic_insight.rb
234
236
  - lib/rack/insight/options.rb
235
237
  - lib/rack/insight/panel.rb
236
238
  - lib/rack/insight/panel_app.rb
@@ -263,6 +265,7 @@ files:
263
265
  - lib/rack/insight/panels/sql_panel/query.rb
264
266
  - lib/rack/insight/panels/templates_panel.rb
265
267
  - lib/rack/insight/panels/templates_panel/rendering.rb
268
+ - lib/rack/insight/panels/templates_panel/stats.rb
266
269
  - lib/rack/insight/panels/timer_panel.rb
267
270
  - lib/rack/insight/params_signature.rb
268
271
  - lib/rack/insight/path-filter.rb
@@ -280,10 +283,12 @@ files:
280
283
  - lib/rack/insight/rspec_matchers.rb
281
284
  - lib/rack/insight/toolbar.rb
282
285
  - lib/rack/insight/version.rb
283
- - lib/rack/insight/views/default_invocation.html.erb
284
286
  - lib/rack/insight/views/enable-button.html.erb
285
287
  - lib/rack/insight/views/error.html.erb
286
288
  - lib/rack/insight/views/headers_fragment.html.erb
289
+ - lib/rack/insight/views/magic_insight.html.erb
290
+ - lib/rack/insight/views/magic_insights.html.erb
291
+ - lib/rack/insight/views/magic_panel.html.erb
287
292
  - lib/rack/insight/views/no_content.html.erb
288
293
  - lib/rack/insight/views/no_data.html.erb
289
294
  - lib/rack/insight/views/panels/active_record.html.erb
@@ -302,7 +307,6 @@ files:
302
307
  - lib/rack/insight/views/panels/speedtracer/traces.html.erb
303
308
  - lib/rack/insight/views/panels/sphinx.html.erb
304
309
  - lib/rack/insight/views/panels/sql.html.erb
305
- - lib/rack/insight/views/panels/templates.html.erb
306
310
  - lib/rack/insight/views/panels/timer.html.erb
307
311
  - lib/rack/insight/views/panels/view_cache.html.erb
308
312
  - lib/rack/insight/views/redirect.html.erb
@@ -1,30 +0,0 @@
1
- <h3><%= name %></h3>
2
- <table>
3
- <thead>
4
- <tr>
5
- <%- members = invocations.last.members # is a struct, so we have members, not keys %>
6
- <%- members.each do |member| %>
7
- <td><%= member %></td>
8
- <%- end %>
9
- </tr>
10
- </thead>
11
- <tbody>
12
- <%- invocations.each do |invocation| %>
13
- <tr>
14
- <%- members.each do |member| %>
15
- <td>
16
- <%- if member == :backtrace %>
17
- <%- invocation.filtered_backtrace.each do |line| %>
18
- <%= line %><br/>
19
- <%- end %>
20
- <%- elsif member == :time %>
21
- <%= invocation.human_time %>
22
- <%- else %>
23
- <%= invocation.send(member).inspect %>
24
- <%- end %>
25
- </td>
26
- <%- end %>
27
- </tr>
28
- <%- end %>
29
- </tbody>
30
- </table>
@@ -1,6 +0,0 @@
1
- <h3>Templates</h3>
2
- <ul>
3
- <% root_rendering.children.each do |child| %>
4
- <%= child.html %>
5
- <% end %>
6
- </ul>