rack-insight 0.5.16 → 0.5.17

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/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>