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 +29 -3
- data/Gemfile.lock +1 -1
- data/lib/rack/insight/app.rb +2 -0
- data/lib/rack/insight/config.rb +6 -2
- data/lib/rack/insight/default_invocation.rb +22 -0
- data/lib/rack/insight/instrumentation/client.rb +1 -1
- data/lib/rack/insight/magic_insight.rb +114 -0
- data/lib/rack/insight/panel.rb +25 -37
- data/lib/rack/insight/panels/log_panel.rb +1 -1
- data/lib/rack/insight/panels/templates_panel.rb +24 -20
- data/lib/rack/insight/panels/templates_panel/rendering.rb +38 -48
- data/lib/rack/insight/panels/templates_panel/stats.rb +40 -0
- data/lib/rack/insight/public/__insight__/insight.css +9 -3
- data/lib/rack/insight/version.rb +1 -1
- data/lib/rack/insight/views/magic_insight.html.erb +22 -0
- data/lib/rack/insight/views/magic_insights.html.erb +67 -0
- data/lib/rack/insight/views/magic_panel.html.erb +2 -0
- metadata +8 -4
- data/lib/rack/insight/views/default_invocation.html.erb +0 -30
- data/lib/rack/insight/views/panels/templates.html.erb +0 -6
data/CHANGELOG
CHANGED
@@ -1,10 +1,36 @@
|
|
1
|
-
==
|
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
data/lib/rack/insight/app.rb
CHANGED
@@ -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"
|
data/lib/rack/insight/config.rb
CHANGED
@@ -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,
|
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
|
-
|
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
|
data/lib/rack/insight/panel.rb
CHANGED
@@ -20,8 +20,8 @@ module Rack::Insight
|
|
20
20
|
|
21
21
|
include Rack::Insight::Logging
|
22
22
|
|
23
|
-
attr_accessor :template_root, :
|
24
|
-
@
|
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
|
-
|
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) ==
|
49
|
-
warn "Rack::Insight #{e.class}
|
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
|
-
|
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
|
182
|
-
!!self.class.
|
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.
|
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
|
245
|
-
logger.info("Rack::Insight is using magic content for #{self.class}, which is probed")# if verbose(:med)
|
246
|
-
render_template '
|
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")
|
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
|
-
|
270
|
-
|
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
|
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/
|
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
|
-
@
|
6
|
+
@stats = Rack::Insight::TemplatesPanel::Stats.new("root")
|
15
7
|
end
|
16
8
|
|
17
9
|
def request_finish(env, status, headers, body, timing)
|
18
|
-
|
19
|
-
@
|
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
|
-
@
|
27
|
-
@current = rendering
|
18
|
+
@stats.begin_record!(rendering)
|
28
19
|
end
|
29
20
|
|
30
21
|
def after_detect(method_call, timing, args, result)
|
31
|
-
@
|
32
|
-
@current = @current.parent
|
22
|
+
@stats.finish_record!(timing.duration)
|
33
23
|
end
|
34
24
|
|
35
25
|
def heading_for_request(number)
|
36
|
-
"Templates:
|
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
|
-
|
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
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
17
|
-
@
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@
|
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
|
-
|
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
|
-
|
31
|
-
|
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
|
35
|
-
|
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
|
43
|
-
|
48
|
+
def _calculate_child_time
|
49
|
+
children.inject(0.0) { |memo, c| memo + c._time } || 0
|
44
50
|
end
|
45
51
|
|
46
|
-
def
|
47
|
-
|
52
|
+
def _human_time(t = self._time)
|
53
|
+
"%.2fms" % t
|
48
54
|
end
|
49
55
|
|
50
|
-
def
|
56
|
+
def time_summary
|
51
57
|
if children.any?
|
52
|
-
"
|
58
|
+
"#{_human_time}, (exclusive: #{_human_time(_exclusive_time)}, child: #{_human_time(_child_time)}"
|
53
59
|
else
|
54
|
-
|
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
|
-
|
63
|
-
|
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:
|
114
|
+
top: auto;
|
109
115
|
}
|
110
116
|
|
111
117
|
#rack-insight.rack-insight_bottom .panel_content {
|
112
|
-
bottom:
|
118
|
+
bottom: auto;
|
113
119
|
}
|
114
120
|
|
115
121
|
#rack-insight .panel_content p a,
|
data/lib/rack/insight/version.rb
CHANGED
@@ -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/,' ') %>
|
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 %>
|
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.
|
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-
|
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>
|