fiveruns_tuneup 0.8.2
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/History.rdoc +3 -0
- data/Manifest +57 -0
- data/README.rdoc +44 -0
- data/Rakefile +15 -0
- data/assets/images/arrows.gif +0 -0
- data/assets/images/edit.png +0 -0
- data/assets/images/fade.png +0 -0
- data/assets/images/fade_down.png +0 -0
- data/assets/images/head.gif +0 -0
- data/assets/images/logo.gif +0 -0
- data/assets/images/logo_clear.png +0 -0
- data/assets/images/magnify.png +0 -0
- data/assets/images/pip.gif +0 -0
- data/assets/images/pointer.gif +0 -0
- data/assets/images/schema.png +0 -0
- data/assets/images/signin.gif +0 -0
- data/assets/images/spinner.gif +0 -0
- data/assets/images/warning.gif +0 -0
- data/assets/javascripts/prototype.js +2515 -0
- data/assets/javascripts/tuneup.js +30 -0
- data/assets/stylesheets/tuneup.css +204 -0
- data/bin/fiveruns_tuneup +26 -0
- data/fiveruns_tuneup.gemspec +49 -0
- data/init.rb +2 -0
- data/install.rb +18 -0
- data/lib/bumpspark_helper.rb +52 -0
- data/lib/fiveruns/tuneup.rb +103 -0
- data/lib/fiveruns/tuneup/asset_tags.rb +39 -0
- data/lib/fiveruns/tuneup/custom_methods.rb +8 -0
- data/lib/fiveruns/tuneup/environment.rb +29 -0
- data/lib/fiveruns/tuneup/instrumentation/action_controller/base.rb +59 -0
- data/lib/fiveruns/tuneup/instrumentation/action_view/base.rb +77 -0
- data/lib/fiveruns/tuneup/instrumentation/active_record/base.rb +126 -0
- data/lib/fiveruns/tuneup/instrumentation/cgi/session.rb +30 -0
- data/lib/fiveruns/tuneup/instrumentation/utilities.rb +172 -0
- data/lib/fiveruns/tuneup/multipart.rb +75 -0
- data/lib/fiveruns/tuneup/runs.rb +86 -0
- data/lib/fiveruns/tuneup/schema.rb +43 -0
- data/lib/fiveruns/tuneup/step.rb +219 -0
- data/lib/fiveruns/tuneup/urls.rb +23 -0
- data/lib/fiveruns/tuneup/version.rb +80 -0
- data/lib/fiveruns_tuneup.rb +1 -0
- data/lib/tuneup_config.rb +29 -0
- data/lib/tuneup_controller.rb +140 -0
- data/lib/tuneup_helper.rb +185 -0
- data/rails/init.rb +20 -0
- data/tasks/assets.rake +32 -0
- data/test/test_helper.rb +3 -0
- data/test/tuneup_test.rb +0 -0
- data/uninstall.rb +6 -0
- data/views/tuneup/_data.html.erb +15 -0
- data/views/tuneup/_flash.html.erb +6 -0
- data/views/tuneup/_link.html.erb +1 -0
- data/views/tuneup/_schema.html.erb +17 -0
- data/views/tuneup/_sql.html.erb +23 -0
- data/views/tuneup/_step.html.erb +15 -0
- data/views/tuneup/panel/_registered.html.erb +4 -0
- data/views/tuneup/panel/_unregistered.html.erb +14 -0
- metadata +146 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Fiveruns
|
|
2
|
+
module Tuneup
|
|
3
|
+
|
|
4
|
+
module AssetTags
|
|
5
|
+
|
|
6
|
+
def add_asset_tags_to(response)
|
|
7
|
+
return unless show_for?(response)
|
|
8
|
+
before, after = response.body.split(/<\/head>/i, 2)
|
|
9
|
+
if after
|
|
10
|
+
insertion = %(
|
|
11
|
+
<!-- START FIVERUNS TUNEUP ASSETS -->
|
|
12
|
+
<link rel='stylesheet' type='text/css' href='/stylesheets/tuneup/tuneup.css'/>
|
|
13
|
+
#{insert_prototype unless response.body.include?('prototype.js')}
|
|
14
|
+
<script type='text/javascript'>
|
|
15
|
+
var TuneUp = {};
|
|
16
|
+
TuneUp.frontend_url = "#{Fiveruns::Tuneup.frontend_url}";
|
|
17
|
+
</script>
|
|
18
|
+
<script type='text/javascript' src='/javascripts/tuneup/tuneup.js'></script>
|
|
19
|
+
<!-- END FIVERUNS TUNEUP ASSETS -->
|
|
20
|
+
)
|
|
21
|
+
response.headers["Content-Length"] += insertion.size
|
|
22
|
+
response.body.replace(before << insertion << '</head>' << after)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def show_for?(response)
|
|
27
|
+
return false unless response.body
|
|
28
|
+
return false unless response.headers['Status'] && response.headers['Status'].include?('200')
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def insert_prototype
|
|
33
|
+
"<script type='text/javascript' src='/javascripts/tuneup/prototype.js'></script>"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Fiveruns
|
|
2
|
+
module Tuneup
|
|
3
|
+
module Environment
|
|
4
|
+
|
|
5
|
+
def environment
|
|
6
|
+
{
|
|
7
|
+
'application_name' => application_name,
|
|
8
|
+
'rails_env' => rails_env,
|
|
9
|
+
'rails_version' => rails_version
|
|
10
|
+
}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def rails_env
|
|
14
|
+
RAILS_ENV || 'development'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def rails_version
|
|
18
|
+
::Rails::VERSION::STRING rescue 'unknown Rails version'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def application_name
|
|
22
|
+
app_name = RAILS_ROOT.split('/').last
|
|
23
|
+
return app_name unless app_name == 'current'
|
|
24
|
+
File.join(RAILS_ROOT, '..').split('/').last
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Fiveruns
|
|
2
|
+
module Tuneup
|
|
3
|
+
module Instrumentation
|
|
4
|
+
module ActionController
|
|
5
|
+
module Base
|
|
6
|
+
def self.included(base)
|
|
7
|
+
Fiveruns::Tuneup.instrument base, ClassMethods, InstanceMethods
|
|
8
|
+
end
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def cache_page_with_fiveruns_tuneup(*args, &block)
|
|
11
|
+
Fiveruns::Tuneup.step "Cache page", :controller do
|
|
12
|
+
cache_page_without_fiveruns_tuneup(*args, &block)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
def expire_page_with_fiveruns_tuneup(*args, &block)
|
|
16
|
+
Fiveruns::Tuneup.step "Expire cached page", :controller do
|
|
17
|
+
expire_page_without_fiveruns_tuneup(*args, &block)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
module InstanceMethods
|
|
22
|
+
def perform_action_with_fiveruns_tuneup(*args, &block)
|
|
23
|
+
Fiveruns::Tuneup.run(self, request) do
|
|
24
|
+
action = (request.parameters['action'] || 'index').to_s
|
|
25
|
+
if Fiveruns::Tuneup.recording?
|
|
26
|
+
Fiveruns::Tuneup.instrument_filters(self)
|
|
27
|
+
Fiveruns::Tuneup.instrument_action_methods(self)
|
|
28
|
+
Fiveruns::Tuneup.instrument_custom_methods
|
|
29
|
+
end
|
|
30
|
+
result = Fiveruns::Tuneup.step "Perform #{action.capitalize} action in #{self.class.name}", :controller, false do
|
|
31
|
+
perform_action_without_fiveruns_tuneup(*args, &block)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
def process_with_fiveruns_tuneup(request, response, *args, &block)
|
|
36
|
+
result = process_without_fiveruns_tuneup(request, response, *args, &block)
|
|
37
|
+
if !request.xhr? && response.content_type == 'text/html'
|
|
38
|
+
Fiveruns::Tuneup.add_asset_tags_to(response)
|
|
39
|
+
end
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def write_fragment_with_fiveruns_tuneup(*args, &block)
|
|
44
|
+
Fiveruns::Tuneup.step "Cache fragment", :controller do
|
|
45
|
+
write_fragment_without_fiveruns_tuneup(*args, &block)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
def expire_fragment_with_fiveruns_tuneup(*args, &block)
|
|
49
|
+
Fiveruns::Tuneup.step "Expire fragment cache", :controller do
|
|
50
|
+
expire_fragment_without_fiveruns_tuneup(*args, &block)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Fiveruns
|
|
2
|
+
module Tuneup
|
|
3
|
+
module Instrumentation
|
|
4
|
+
module ActionView
|
|
5
|
+
module Base
|
|
6
|
+
|
|
7
|
+
BASIC_TEMPLATE_PATH = File.join(RAILS_ROOT, 'app', 'views')
|
|
8
|
+
|
|
9
|
+
def self.included(base)
|
|
10
|
+
Fiveruns::Tuneup.instrument base, InstanceMethods
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.normalize_path(path)
|
|
14
|
+
return path unless path
|
|
15
|
+
if path[0, BASIC_TEMPLATE_PATH.size] == BASIC_TEMPLATE_PATH
|
|
16
|
+
path[(BASIC_TEMPLATE_PATH.size + 1)..-1]
|
|
17
|
+
else
|
|
18
|
+
if (components = path.split(File::SEPARATOR)).size > 2
|
|
19
|
+
components[-2, 2].join(File::SEPARATOR)
|
|
20
|
+
else
|
|
21
|
+
components.join(File::SEPARATOR)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module InstanceMethods
|
|
27
|
+
def render_file_with_fiveruns_tuneup(path, *args, &block)
|
|
28
|
+
name = Fiveruns::Tuneup::Instrumentation::ActionView::Base.normalize_path(path)
|
|
29
|
+
Fiveruns::Tuneup.step "Render file #{name}", :view do
|
|
30
|
+
render_file_without_fiveruns_tuneup(path, *args, &block)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
def update_page_with_fiveruns_tuneup(*args, &block)
|
|
34
|
+
path = block.to_s.split('/').last.split(':').first rescue ''
|
|
35
|
+
name = Fiveruns::Tuneup::Instrumentation::ActionView::Base.normalize_path(path)
|
|
36
|
+
Fiveruns::Tuneup.step "Render page update #{name}", :view do
|
|
37
|
+
update_page_without_fiveruns_tuneup(*args, &block)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
def render_with_fiveruns_tuneup(*args, &block)
|
|
41
|
+
record = true
|
|
42
|
+
options = args.first || {}
|
|
43
|
+
path = case options
|
|
44
|
+
when String
|
|
45
|
+
"Render #{options}"
|
|
46
|
+
when :update
|
|
47
|
+
name = block.to_s.split('/').last.split(':').first rescue ''
|
|
48
|
+
"Render page update #{name}"
|
|
49
|
+
when Hash
|
|
50
|
+
if options[:file]
|
|
51
|
+
"Render #{options[:file]}"
|
|
52
|
+
elsif options[:partial]
|
|
53
|
+
# Don't record this as it causes duplicate records
|
|
54
|
+
record = false
|
|
55
|
+
elsif options[:inline]
|
|
56
|
+
"Render inline"
|
|
57
|
+
elsif options[:text]
|
|
58
|
+
"Render text"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
path ||= 'Render'
|
|
62
|
+
|
|
63
|
+
if record
|
|
64
|
+
Fiveruns::Tuneup.step path, :view do
|
|
65
|
+
render_without_fiveruns_tuneup(*args, &block)
|
|
66
|
+
end
|
|
67
|
+
else
|
|
68
|
+
render_without_fiveruns_tuneup(*args, &block)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
module Fiveruns
|
|
2
|
+
module Tuneup
|
|
3
|
+
module Instrumentation
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module Base
|
|
6
|
+
|
|
7
|
+
def self.record(model, name, raw_sql=nil, &operation)
|
|
8
|
+
sql = nil
|
|
9
|
+
Fiveruns::Tuneup.exclude do
|
|
10
|
+
model.silence do
|
|
11
|
+
sql = Fiveruns::Tuneup::Step::SQL.new(raw_sql, model.connection) if raw_sql
|
|
12
|
+
Fiveruns::Tuneup.add_schema_for(model.table_name, model.connection)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
Fiveruns::Tuneup.step(name, :model, true, sql, model.table_name, &operation)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.included(base)
|
|
19
|
+
Fiveruns::Tuneup.instrument base, InstanceMethods, ClassMethods
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module ClassMethods
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# FINDS
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
def find_with_fiveruns_tuneup(*args, &block)
|
|
29
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Find #{self.name}" do
|
|
30
|
+
find_without_fiveruns_tuneup(*args, &block)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
def find_by_sql_with_fiveruns_tuneup(conditions, &block)
|
|
34
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Find #{self.name} by SQL", sanitize_sql(conditions) do
|
|
35
|
+
find_by_sql_without_fiveruns_tuneup(conditions, &block)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# CREATE
|
|
41
|
+
#
|
|
42
|
+
|
|
43
|
+
def create_with_fiveruns_tuneup(*args, &block)
|
|
44
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Create #{self.name}" do
|
|
45
|
+
create_without_fiveruns_tuneup(*args, &block)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
#
|
|
50
|
+
# UPDATES
|
|
51
|
+
#
|
|
52
|
+
|
|
53
|
+
def update_with_fiveruns_tuneup(*args, &block)
|
|
54
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Update #{self.name}" do
|
|
55
|
+
update_without_fiveruns_tuneup(*args, &block)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
def update_all_with_fiveruns_tuneup(*args, &block)
|
|
59
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Update #{self.name} (All)" do
|
|
60
|
+
update_all_without_fiveruns_tuneup(*args, &block)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
#
|
|
65
|
+
# DELETES
|
|
66
|
+
#
|
|
67
|
+
|
|
68
|
+
def destroy_with_fiveruns_tuneup(*args, &block)
|
|
69
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Destroy #{self.name}" do
|
|
70
|
+
destroy_without_fiveruns_tuneup(*args, &block)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
def destroy_all_with_fiveruns_tuneup(*args, &block)
|
|
74
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Destroy #{self.name} (All)" do
|
|
75
|
+
destroy_all_without_fiveruns_tuneup(*args, &block)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
def delete_with_fiveruns_tuneup(*args, &block)
|
|
79
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Delete #{self.name}" do
|
|
80
|
+
delete_without_fiveruns_tuneup(*args, &block)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
def delete_all_with_fiveruns_tuneup(*args, &block)
|
|
84
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self, "Delete #{self.name} (All)" do
|
|
85
|
+
delete_all_without_fiveruns_tuneup(*args, &block)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
module InstanceMethods
|
|
90
|
+
|
|
91
|
+
#
|
|
92
|
+
# UPDATES
|
|
93
|
+
#
|
|
94
|
+
|
|
95
|
+
def update_with_fiveruns_tuneup(*args, &block)
|
|
96
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self.class, "Update #{self.class.name}" do
|
|
97
|
+
update_without_fiveruns_tuneup(*args, &block)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
def save_with_fiveruns_tuneup(*args, &block)
|
|
101
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self.class, "Save #{self.class.name}" do
|
|
102
|
+
save_without_fiveruns_tuneup(*args, &block)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
def save_with_fiveruns_tuneup!(*args, &block)
|
|
106
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self.class, "Save #{self.class.name}" do
|
|
107
|
+
save_without_fiveruns_tuneup!(*args, &block)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#
|
|
112
|
+
# DELETES
|
|
113
|
+
#
|
|
114
|
+
|
|
115
|
+
def destroy_with_fiveruns_tuneup(*args, &block)
|
|
116
|
+
Fiveruns::Tuneup::Instrumentation::ActiveRecord::Base.record self.class, "Destroy #{self.class.name}" do
|
|
117
|
+
destroy_without_fiveruns_tuneup(*args, &block)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Fiveruns
|
|
2
|
+
module Tuneup
|
|
3
|
+
module Instrumentation
|
|
4
|
+
module CGI
|
|
5
|
+
module Session
|
|
6
|
+
def self.included(base)
|
|
7
|
+
Fiveruns::Tuneup.instrument base, InstanceMethods
|
|
8
|
+
end
|
|
9
|
+
module InstanceMethods
|
|
10
|
+
def initialize_with_fiveruns_tuneup(*args, &block)
|
|
11
|
+
Fiveruns::Tuneup.step "Create session", :model do
|
|
12
|
+
initialize_without_fiveruns_tuneup(*args, &block)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
def close_with_fiveruns_tuneup(*args, &block)
|
|
16
|
+
Fiveruns::Tuneup.step "Close session", :model do
|
|
17
|
+
close_without_fiveruns_tuneup(*args, &block)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
def delete_with_fiveruns_tuneup(*args, &block)
|
|
21
|
+
Fiveruns::Tuneup.step "Delete session", :model do
|
|
22
|
+
delete_without_fiveruns_tuneup(*args, &block)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
module Fiveruns
|
|
2
|
+
module Tuneup
|
|
3
|
+
module Instrumentation
|
|
4
|
+
module Utilities
|
|
5
|
+
|
|
6
|
+
def stack
|
|
7
|
+
@stack ||= []
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def exclusion_stack
|
|
11
|
+
@exclusion_stack ||= [0]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def custom_methods
|
|
15
|
+
@custom_methods ||= {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add_custom_methods(target, *methods)
|
|
19
|
+
custom_methods[target] = [] unless custom_methods.key?(target)
|
|
20
|
+
custom_methods[target].push(*methods)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stopwatch
|
|
24
|
+
start = Time.now.to_f
|
|
25
|
+
yield
|
|
26
|
+
(Time.now.to_f - start) * 1000
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def exclude
|
|
30
|
+
result = nil
|
|
31
|
+
exclusion_stack[-1] += stopwatch { result = yield }
|
|
32
|
+
result
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def step(name, layer=nil, link=true, sql=nil, table_name=nil, &block)
|
|
36
|
+
if recording?
|
|
37
|
+
result = nil
|
|
38
|
+
caller_line = caller.detect { |l| l.include?(RAILS_ROOT) && l !~ /tuneup|vendor\/rails/ } if link
|
|
39
|
+
file, line = caller_line ? caller_line.split(':')[0, 2] : [nil, nil]
|
|
40
|
+
line = line.to_i if line
|
|
41
|
+
returning ::Fiveruns::Tuneup::Step.new(name, layer, file, line, sql, &block) do |step|
|
|
42
|
+
step.table_name = table_name
|
|
43
|
+
stack.last << step
|
|
44
|
+
stack << step
|
|
45
|
+
handle_exclusions_in step do
|
|
46
|
+
step.time = stopwatch { result = yield(sql) }
|
|
47
|
+
end
|
|
48
|
+
stack.pop
|
|
49
|
+
end
|
|
50
|
+
result
|
|
51
|
+
else
|
|
52
|
+
yield(sql)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Handle removal of excluded time from total for this step, and
|
|
57
|
+
# bubble the value up for removal from the parent step
|
|
58
|
+
def handle_exclusions_in(step)
|
|
59
|
+
exclusion_stack << 0
|
|
60
|
+
yield # Must set +step.time+
|
|
61
|
+
time_to_exclude = exclusion_stack.pop
|
|
62
|
+
step.time -= time_to_exclude
|
|
63
|
+
exclusion_stack[-1] += time_to_exclude unless exclusion_stack.blank?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def instrument(target, *mods)
|
|
67
|
+
mods.each do |mod|
|
|
68
|
+
# Change target for 'ClassMethods' module
|
|
69
|
+
real_target = mod.name.demodulize == 'ClassMethods' ? (class << target; self; end) : target
|
|
70
|
+
real_target.__send__(:include, mod)
|
|
71
|
+
# Find all the instrumentation hooks and chain them in
|
|
72
|
+
mod.instance_methods.each do |meth|
|
|
73
|
+
name = meth.to_s.sub('_with_fiveruns_tuneup', '')
|
|
74
|
+
real_target.alias_method_chain(name, :fiveruns_tuneup) rescue nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def instrument_action_methods(controller)
|
|
80
|
+
klass = controller.class
|
|
81
|
+
actions_for(klass).each do |meth|
|
|
82
|
+
format = alias_format_for(meth)
|
|
83
|
+
next if controller.respond_to?(format % :with, true)
|
|
84
|
+
wrap(klass, format, meth, "Invoke #{meth} action", :controller)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def instrument_filters(controller)
|
|
89
|
+
klass = controller.class
|
|
90
|
+
filters_for(klass).each do |filter|
|
|
91
|
+
format = alias_format_for(filter.filter)
|
|
92
|
+
next if controller.respond_to?(format % :with, true)
|
|
93
|
+
wrap(klass, format, filter.filter, "#{filter.type.to_s.titleize} filter #{filter.filter}", :controller)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def instrument_custom_methods
|
|
98
|
+
custom_methods.each do |meth_target, meths|
|
|
99
|
+
lineage = meth_target.ancestors
|
|
100
|
+
layer = if lineage.include?(ActionController::Base)
|
|
101
|
+
:controller
|
|
102
|
+
elsif lineage.include?(ActiveRecord::Base)
|
|
103
|
+
:model
|
|
104
|
+
elsif lineage.include?(ActionView::Base)
|
|
105
|
+
:view
|
|
106
|
+
else
|
|
107
|
+
:other
|
|
108
|
+
end
|
|
109
|
+
meths.each do |meth|
|
|
110
|
+
format = alias_format_for(meth)
|
|
111
|
+
wrap(meth_target, format, meth, "Method #{meth}", layer)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
#######
|
|
117
|
+
private
|
|
118
|
+
#######
|
|
119
|
+
|
|
120
|
+
def wrap(klass, format, meth, name, layer)
|
|
121
|
+
text = <<-EOC
|
|
122
|
+
def #{format % :with}(*args, &block)
|
|
123
|
+
Fiveruns::Tuneup.step "#{name}", :#{layer} do
|
|
124
|
+
#{format % :without}(*args, &block)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
alias_method_chain :#{meth}, :fiveruns_tuneup
|
|
128
|
+
EOC
|
|
129
|
+
begin
|
|
130
|
+
klass.class_eval text
|
|
131
|
+
rescue SyntaxError => e
|
|
132
|
+
# XXX: Catch-all for reports of oddly-named methods affecting dynamically generated code
|
|
133
|
+
log :warn, %[Bad syntax wrapping #{klass}##{meth}, "#{name}"]
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def alias_format_for(name)
|
|
138
|
+
name.to_s =~ /^(.*?)(\?|!|=)$/ ? "#{$1}_%s_fiveruns_tuneup#{$2}" : "#{name}_%s_fiveruns_tuneup"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def actions_for(klass)
|
|
142
|
+
klass.action_methods.reject { |meth| meth.to_s.include?('fiveruns') }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def filters_for(klass)
|
|
146
|
+
klass.filter_chain.select { |f| f.filter.is_a?(Symbol) }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def install_instrumentation
|
|
150
|
+
instrumentation_path = File.dirname(__FILE__)
|
|
151
|
+
Dir[File.join(instrumentation_path, '/*/**/*.rb')].each do |filename|
|
|
152
|
+
constant_path = filename[(instrumentation_path.size + 1)..-4]
|
|
153
|
+
constant_name = path_to_constant_name(constant_path)
|
|
154
|
+
if (constant = constant_name.constantize rescue nil)
|
|
155
|
+
instrumentation = "Fiveruns::Tuneup::Instrumentation::#{constant_name}".constantize
|
|
156
|
+
constant.__send__(:include, instrumentation)
|
|
157
|
+
else
|
|
158
|
+
log :debug, "#{constant_name} not found; skipping instrumentation."
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def path_to_constant_name(path)
|
|
164
|
+
parts = path.split(File::SEPARATOR)
|
|
165
|
+
parts.map(&:camelize).join('::').sub('Cgi', 'CGI')
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|