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