ngauthier-slow-actions 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,14 @@
1
+ = Slow Actions
2
+ Nick Gauthier (nick@smartlogicsolutions.com)
3
+
4
+ == Description
5
+ Reads a rails app's log file for slow actions
6
+
7
+ == Usage
8
+ ./bin/slow-actions.rb path/to/log/file
9
+
10
+ Or:
11
+
12
+ require 'slow_actions'
13
+ sap = SlowActionParser.new(file_path)
14
+ actions = sap.parse
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 2
3
+ :patch: 2
4
+ :major: 0
data/bin/slow-actions ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'slow_actions')
3
+ @sa = SlowActions.new
4
+ @sa.parse_file(ARGV[0])
5
+ puts @sa.print_actions
6
+ puts ""
7
+ puts @sa.print_controller_tree
8
+ puts ""
9
+ puts @sa.print_sessions
10
+
@@ -0,0 +1,124 @@
1
+ require File.join(File.dirname(__FILE__), 'slow_actions_parser')
2
+ require File.join(File.dirname(__FILE__), 'slow_actions_controller')
3
+ require File.join(File.dirname(__FILE__), 'slow_actions_action')
4
+ require File.join(File.dirname(__FILE__), 'slow_actions_session')
5
+
6
+ class SlowActions
7
+ def initialize
8
+ @log_entries = []
9
+ end
10
+
11
+ def parse_file(file_path)
12
+ parser = Parser.new(file_path)
13
+ @log_entries += parser.parse
14
+ process
15
+ end
16
+
17
+ def log_entries
18
+ return @log_entries
19
+ end
20
+
21
+ def print_actions
22
+ str = ""
23
+ str += " Cost Average Max\n"
24
+ actions.sort{|x,y| y.total_cost <=> x.total_cost}.each do |a|
25
+ str += "==#{a.controller.name}:#{a.name}==\n"
26
+ str += " Total: #{ftos a.total_cost}#{ftos a.total_avg}#{ftos a.total_max}\n"
27
+ str += " Render: #{ftos a.render_cost}#{ftos a.render_avg}#{ftos a.render_max}\n"
28
+ str += " DB: #{ftos a.db_cost}#{ftos a.db_avg}#{ftos a.db_max}\n"
29
+
30
+ end
31
+ return str
32
+ end
33
+
34
+ def print_controller_tree
35
+ str = ""
36
+ str += " Cost Average Max\n"
37
+ controllers.sort{|x,y| y.total_cost <=> x.total_cost}.each do |c|
38
+ str += "==#{c.name}==\n"
39
+ str += " Total: #{ftos c.total_cost}#{ftos c.total_avg}#{ftos c.total_max}\n"
40
+ str += " Render: #{ftos c.render_cost}#{ftos c.render_avg}#{ftos c.render_max}\n"
41
+ str += " DB: #{ftos c.db_cost}#{ftos c.db_avg}#{ftos c.db_max}\n"
42
+ c.actions.sort{|x,y| y.total_cost <=> x.total_cost}.each do |a|
43
+ str += " ==#{a.name}==\n"
44
+ str += " Total: #{ftos a.total_cost}#{ftos a.total_avg}#{ftos a.total_max}\n"
45
+ str += " Render: #{ftos a.render_cost}#{ftos a.render_avg}#{ftos a.render_max}\n"
46
+ str += " DB: #{ftos a.db_cost}#{ftos a.db_avg}#{ftos a.db_max}\n"
47
+ end
48
+ end
49
+ return str
50
+ end
51
+
52
+ def print_sessions
53
+ str = ""
54
+ str += " Cost Average Max\n"
55
+ sessions.sort{|x,y| y.total_cost <=> x.total_cost}.each do |s|
56
+ str += "==#{s.name}==\n"
57
+ str += " Total: #{ftos s.total_cost}#{ftos s.total_avg}#{ftos s.total_max}\n"
58
+ str += " Render: #{ftos s.render_cost}#{ftos s.render_avg}#{ftos s.render_max}\n"
59
+ str += " DB: #{ftos s.db_cost}#{ftos s.db_avg}#{ftos s.db_max}\n"
60
+ end
61
+ return str
62
+ end
63
+
64
+ def to_html
65
+ raise "Not Implemented"
66
+ end
67
+
68
+ def controllers
69
+ @controllers.values
70
+ end
71
+
72
+ def actions
73
+ @actions.values
74
+ end
75
+
76
+ def sessions
77
+ @sessions.values
78
+ end
79
+
80
+ private
81
+
82
+ def process
83
+ @controllers ||= {}
84
+ @actions ||= {}
85
+ @sessions ||= {}
86
+ @log_entries.each do |la|
87
+ next if la.processed
88
+ c = @controllers[la.controller]
89
+ if c.nil?
90
+ c = Controller.new(la.controller)
91
+ @controllers[la.controller] = c
92
+ end
93
+ c.add_entry(la)
94
+
95
+ a = @actions[la.action]
96
+ if a.nil?
97
+ a = Action.new(la.action, c)
98
+ @actions[la.action] = a
99
+ c.add_action(a)
100
+ end
101
+ a.add_entry(la)
102
+
103
+ s = @sessions[la.session]
104
+ if s.nil?
105
+ s = Session.new(la.session)
106
+ @sessions[la.session] = s
107
+ end
108
+ s.add_entry(la)
109
+ end
110
+
111
+ # now compute the times for each
112
+ @controllers.values.each{|c| c.compute_times}
113
+ @actions.values.each{|a| a.compute_times}
114
+ @sessions.values.each{|s| s.compute_times}
115
+ end
116
+
117
+ def ftos(float)
118
+ str = ((float*1000).to_i.to_f/1000).to_s
119
+ while str.size < 7
120
+ str += "0"
121
+ end
122
+ str += " "
123
+ end
124
+ end
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(__FILE__), 'slow_actions_computation_module')
2
+ class SlowActions
3
+ private
4
+ class Action
5
+ include Computable
6
+ def initialize(name, controller)
7
+ @name = name
8
+ @controller = controller
9
+ @log_entries = []
10
+ end
11
+ attr_reader :name
12
+ attr_reader :controller
13
+
14
+ def add_entry(la)
15
+ @log_entries << la
16
+ la.action = self
17
+ end
18
+ attr_reader :log_entries
19
+
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ module Computable
2
+ attr_reader :render_avg, :db_avg, :total_avg
3
+ attr_reader :render_max, :db_max, :total_max
4
+ attr_reader :render_cost, :db_cost, :total_cost
5
+ attr_reader :error_avg
6
+
7
+ def compute_times
8
+ @render_avg = 0.0
9
+ @db_avg = 0.0
10
+ @total_avg = 0.0
11
+ @render_max = 0.0
12
+ @db_max = 0.0
13
+ @total_max = 0.0
14
+ @error_avg = 0.0
15
+
16
+ @log_entries.each do |la|
17
+ if la.error?
18
+ @error_avg += 1.0
19
+ next
20
+ end
21
+ @render_avg += la.rendering
22
+ @db_avg += la.db
23
+ @total_avg += la.duration
24
+ @render_max = la.rendering if la.rendering > @render_max
25
+ @db_max = la.db if la.db > @db_max
26
+ @total_max = la.duration if la.duration > @total_max
27
+ end
28
+
29
+ @render_avg /= @log_entries.size.to_f
30
+ @db_avg /= @log_entries.size.to_f
31
+ @total_avg /= @log_entries.size.to_f
32
+ @error_avg /= @log_entries.size.to_f
33
+
34
+ # using math.log allows us to smooth out the score between
35
+ # infrequent and very frequent actions. 0.1 is added for a
36
+ # non-0 result
37
+ @render_cost = @render_avg * Math.log(@log_entries.size+0.1)
38
+ @db_cost = @db_avg * Math.log(@log_entries.size+0.1)
39
+ @total_cost = @total_avg * Math.log(@log_entries.size+0.1)
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ require File.join(File.dirname(__FILE__), 'slow_actions_computation_module')
2
+ class SlowActions
3
+ private
4
+ class Controller
5
+ include Computable
6
+ def initialize(name)
7
+ @name = name
8
+ @log_entries = []
9
+ @actions = []
10
+ end
11
+ attr_reader :name
12
+
13
+ def add_entry(la)
14
+ @log_entries << la
15
+ la.controller = self
16
+ end
17
+ attr_reader :log_entries
18
+
19
+ def add_action(a)
20
+ @actions << a
21
+ end
22
+ attr_reader :actions
23
+
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ class SlowActions
2
+ private
3
+ class LogEntry
4
+ def initialize
5
+ self.processed = false
6
+ end
7
+ attr_accessor :controller
8
+ attr_accessor :action
9
+ attr_accessor :ip
10
+ attr_accessor :date
11
+ attr_accessor :time
12
+ attr_accessor :method
13
+ attr_accessor :session
14
+ attr_accessor :parameters
15
+ attr_accessor :duration
16
+ attr_accessor :rendering
17
+ attr_accessor :db
18
+ attr_accessor :error_text
19
+ attr_accessor :processed
20
+
21
+ def error?
22
+ return false if error_text.nil?
23
+ return false if error_text.empty?
24
+ return true
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,85 @@
1
+ require File.join(File.dirname(__FILE__), 'slow_actions_log_entry')
2
+ class SlowActions
3
+ private
4
+ class Parser
5
+
6
+ def initialize(file_path)
7
+ @file_path = file_path
8
+ raise "File not found: #{file_path}" unless File.exists? file_path
9
+ @file = File.new(file_path, 'r')
10
+ end
11
+
12
+ def parse
13
+ @log_entries = []
14
+ begin
15
+ while true
16
+ line = @file.readline
17
+ if line =~ /^Processing/
18
+ @log_entries << parse_log_entry(line)
19
+ end
20
+ end
21
+ rescue EOFError => ex
22
+ @file.close
23
+ end
24
+ return @log_entries
25
+ end
26
+
27
+ private
28
+
29
+ def parse_log_entry(line)
30
+ la = LogEntry.new
31
+ if line =~ /^Processing (\S+)#(\S+) \(for (\S+) at (\S+) (\S+)\) \[(\S+)\]$/
32
+ la.controller = $1
33
+ la.action = $2
34
+ la.ip = $3
35
+ la.date = $4
36
+ la.time = $5
37
+ la.method = $6
38
+ end
39
+ line = @file.readline
40
+ if line =~ /^\s+Session ID: (\S+)$/
41
+ la.session = $1
42
+ end
43
+ line = @file.readline
44
+ if line =~ /^\s+Parameters: (.*)$/
45
+ la.parameters = $1
46
+ end
47
+ line = @file.readline
48
+ if line == "\n"
49
+ error_text = parse_error
50
+ la.error_text = error_text
51
+ return la
52
+ end
53
+ while !(line =~ /^Completed/ and line != "\n")
54
+ line = @file.readline
55
+ end
56
+ if line =~ /^Completed in (\S+)/
57
+ la.duration = $1.to_f
58
+ end
59
+ if line =~ /Rendering: (\S+)/
60
+ la.rendering = $1.to_f
61
+ else
62
+ la.rendering = 0.0
63
+ end
64
+ if line =~ /DB: (\S+)/
65
+ la.db = $1.to_f
66
+ else
67
+ la.db = 0.0
68
+ end
69
+ return la
70
+ end
71
+
72
+ def parse_error
73
+ line = "\n"
74
+ while line == "\n"
75
+ line = @file.readline
76
+ end
77
+ error_txt = ""
78
+ while line != "\n"
79
+ line = @file.readline
80
+ error_txt += line
81
+ end
82
+ return error_txt
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,19 @@
1
+ require File.join(File.dirname(__FILE__), 'slow_actions_computation_module')
2
+ class SlowActions
3
+ private
4
+ class Session
5
+ include Computable
6
+ def initialize(name)
7
+ @name = name
8
+ @log_entries = []
9
+ end
10
+ attr_reader :name
11
+
12
+ def add_entry(la)
13
+ @log_entries << la
14
+ la.session = self
15
+ end
16
+ attr_reader :log_entries
17
+
18
+ end
19
+ end
@@ -0,0 +1,246 @@
1
+ Processing StaticPagesController#static_hunters_lodge (for 141.153.81.49 at 2009-02-23 22:09:43) [GET]
2
+ Session ID: 926fca1a3f54fdd0adc45c7406155306
3
+ Parameters: {"action"=>"static_hunters_lodge", "controller"=>"static_pages"}
4
+ Rendering template within layouts/application
5
+ Rendering static_pages/static_hunters_lodge
6
+ Completed in 0.06000 (16 reqs/sec) | Rendering: 0.04000 (66%) | DB: 0.00400 (6%) | 200 OK [http://play.scavengrnet.com/]
7
+
8
+
9
+ Processing SessionsController#new (for 141.153.81.49 at 2009-02-23 22:10:01) [GET]
10
+ Session ID: 926fca1a3f54fdd0adc45c7406155306
11
+ Parameters: {"action"=>"new", "controller"=>"sessions"}
12
+ Redirected to https://play.scavengrnet.com/login
13
+ Filter chain halted as [:ensure_proper_protocol] rendered_or_redirected.
14
+ Completed in 0.00010 (10000 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://play.scavengrnet.com/login]
15
+
16
+
17
+ Processing SessionsController#new (for 141.153.81.49 at 2009-02-23 22:10:02) [GET]
18
+ Session ID: 926fca1a3f54fdd0adc45c7406155306
19
+ Parameters: {"action"=>"new", "controller"=>"sessions"}
20
+ Rendering template within layouts/application
21
+ Rendering sessions/new
22
+ Completed in 0.02800 (35 reqs/sec) | Rendering: 0.01600 (57%) | DB: 0.00000 (0%) | 200 OK [https://play.scavengrnet.com/login]
23
+
24
+
25
+ Processing UsersController#index (for 76.120.186.153 at 2009-02-23 22:15:06) [GET]
26
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
27
+ Parameters: {"action"=>"index", "controller"=>"users"}
28
+ Redirected to https://play.scavengrnet.com/hunters_lodge
29
+ Filter chain halted as [:ensure_proper_protocol] rendered_or_redirected.
30
+ Completed in 0.00010 (10000 reqs/sec) | DB: 0.06400 (64002%) | 302 Found [http://play.scavengrnet.com/hunters_lodge]
31
+
32
+
33
+ Processing UsersController#index (for 76.120.186.153 at 2009-02-23 22:15:07) [GET]
34
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
35
+ Parameters: {"action"=>"index", "controller"=>"users"}
36
+ Redirected to https://play.scavengrnet.com/
37
+ Completed in 0.00010 (10000 reqs/sec) | DB: 0.25601 (256014%) | 302 Found [https://play.scavengrnet.com/hunters_lodge]
38
+
39
+
40
+ Processing StaticPagesController#static_hunters_lodge (for 76.120.186.153 at 2009-02-23 22:15:08) [GET]
41
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
42
+ Parameters: {"action"=>"static_hunters_lodge", "controller"=>"static_pages"}
43
+ Redirected to http://play.scavengrnet.com/
44
+ Filter chain halted as [:ensure_proper_protocol] rendered_or_redirected.
45
+ Completed in 0.00010 (10000 reqs/sec) | DB: 0.00000 (0%) | 302 Found [https://play.scavengrnet.com/]
46
+
47
+
48
+ Processing StaticPagesController#static_hunters_lodge (for 76.120.186.153 at 2009-02-23 22:15:08) [GET]
49
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
50
+ Parameters: {"action"=>"static_hunters_lodge", "controller"=>"static_pages"}
51
+ Rendering template within layouts/application
52
+ Rendering static_pages/static_hunters_lodge
53
+ Completed in 0.06000 (16 reqs/sec) | Rendering: 0.04400 (73%) | DB: 0.21601 (360%) | 200 OK [http://play.scavengrnet.com/]
54
+
55
+
56
+ Processing SessionsController#new (for 76.120.186.153 at 2009-02-23 22:15:19) [GET]
57
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
58
+ Parameters: {"action"=>"new", "controller"=>"sessions"}
59
+ Redirected to https://play.scavengrnet.com/login
60
+ Filter chain halted as [:ensure_proper_protocol] rendered_or_redirected.
61
+ Completed in 0.00010 (10000 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://play.scavengrnet.com/login]
62
+
63
+
64
+ Processing SessionsController#new (for 76.120.186.153 at 2009-02-23 22:15:19) [GET]
65
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
66
+ Parameters: {"action"=>"new", "controller"=>"sessions"}
67
+ Rendering template within layouts/application
68
+ Rendering sessions/new
69
+ Completed in 0.01200 (83 reqs/sec) | Rendering: 0.00800 (66%) | DB: 0.00000 (0%) | 200 OK [https://play.scavengrnet.com/login]
70
+
71
+
72
+ Processing SessionsController#create (for 76.120.186.153 at 2009-02-23 22:15:44) [POST]
73
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
74
+ Parameters: {"commit"=>"Log in", "authenticity_token"=>"d86bce53f5938a51f226742582ee28013d794fd8", "action"=>"create", "controller"=>"sessions", "password"=>"rossj", "email"=>"jrmcclain@comcast.net"}
75
+ Redirected to https://play.scavengrnet.com/hunters_lodge
76
+ Completed in 0.06400 (15 reqs/sec) | DB: 0.04800 (75%) | 302 Found [https://play.scavengrnet.com/session]
77
+
78
+
79
+ Processing UsersController#index (for 76.120.186.153 at 2009-02-23 22:15:44) [GET]
80
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
81
+ Parameters: {"action"=>"index", "controller"=>"users"}
82
+ Rendering template within layouts/application
83
+ Rendering users/index
84
+ Completed in 6.62038 (0 reqs/sec) | Rendering: 6.24036 (94%) | DB: 0.36402 (5%) | 200 OK [https://play.scavengrnet.com/hunters_lodge]
85
+
86
+
87
+ Processing UsersController#winning_history (for 76.120.186.153 at 2009-02-23 22:16:31) [GET]
88
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
89
+ Parameters: {"action"=>"winning_history", "id"=>"138", "controller"=>"users"}
90
+ Redirected to http://play.scavengrnet.com/users/138/winning_history
91
+ Filter chain halted as [:ensure_proper_protocol] rendered_or_redirected.
92
+ Completed in 0.00010 (10000 reqs/sec) | DB: 0.02400 (24000%) | 302 Found [https://play.scavengrnet.com/users/138/winning_history]
93
+
94
+
95
+ Processing UsersController#winning_history (for 76.120.186.153 at 2009-02-23 22:16:31) [GET]
96
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
97
+ Parameters: {"action"=>"winning_history", "id"=>"138", "controller"=>"users"}
98
+ Rendering template within layouts/application
99
+ Rendering users/winning_history
100
+ Completed in 0.10401 (9 reqs/sec) | Rendering: 0.03200 (30%) | DB: 0.34802 (334%) | 200 OK [http://play.scavengrnet.com/users/138/winning_history]
101
+
102
+
103
+ Processing UsersController#images (for 76.120.186.153 at 2009-02-23 22:16:32) [GET]
104
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
105
+ Parameters: {"format"=>"png", "action"=>"images", "id"=>"history-bottom", "controller"=>"users"}
106
+
107
+
108
+ ActionController::UnknownAction (No action responded to images):
109
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/filters.rb:579:in `call_filters'
110
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/filters.rb:572:in `perform_action_without_benchmark'
111
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
112
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/1.8/benchmark.rb:293:in `measure'
113
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
114
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/rescue.rb:201:in `perform_action_without_caching'
115
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/caching/sql_cache.rb:13:in `passenger_orig_perform_action'
116
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/connection_adapters/abstract/query_cache.rb:33:in `cache'
117
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/query_cache.rb:8:in `cache'
118
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/caching/sql_cache.rb:12:in `passenger_orig_perform_action'
119
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/request_handler.rb:53:in `perform_action'
120
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/base.rb:529:in `send'
121
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/base.rb:529:in `process_without_filters'
122
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/filters.rb:568:in `process_without_session_management_support'
123
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/session_management.rb:130:in `process'
124
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/base.rb:389:in `process'
125
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:149:in `handle_request'
126
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:107:in `dispatch'
127
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:104:in `synchronize'
128
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:104:in `dispatch'
129
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:120:in `dispatch_cgi'
130
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:35:in `dispatch'
131
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/request_handler.rb:38:in `process_request'
132
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_request_handler.rb:165:in `main_loop'
133
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:321:in `start_request_handler'
134
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:282:in `handle_spawn_application'
135
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:163:in `safe_fork'
136
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:161:in `fork'
137
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:161:in `safe_fork'
138
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:280:in `handle_spawn_application'
139
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:163:in `safe_fork'
140
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:161:in `fork'
141
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:161:in `safe_fork'
142
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:279:in `handle_spawn_application'
143
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `__send__'
144
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `main_loop'
145
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:168:in `start_synchronously'
146
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:135:in `start'
147
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:112:in `fork'
148
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:112:in `start'
149
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:179:in `start'
150
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/framework_spawner.rb:270:in `handle_spawn_application'
151
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/framework_spawner.rb:263:in `synchronize'
152
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/framework_spawner.rb:263:in `handle_spawn_application'
153
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `__send__'
154
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `main_loop'
155
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:168:in `start_synchronously'
156
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:135:in `start'
157
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:112:in `fork'
158
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:112:in `start'
159
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/framework_spawner.rb:87:in `start'
160
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:222:in `spawn_rails_application'
161
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:217:in `synchronize'
162
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:217:in `spawn_rails_application'
163
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:126:in `spawn_application'
164
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:251:in `handle_spawn_application'
165
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `__send__'
166
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `main_loop'
167
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:168:in `start_synchronously'
168
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/bin/passenger-spawn-server:46
169
+
170
+
171
+
172
+ Processing UsersController#images (for 76.120.186.153 at 2009-02-23 22:16:32) [GET]
173
+ Session ID: a0dfedb797521bb9f4749c76bef89d8d
174
+ Parameters: {"format"=>"png", "action"=>"images", "id"=>"hunts-bottom", "controller"=>"users"}
175
+
176
+
177
+ ActionController::UnknownAction (No action responded to images):
178
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/filters.rb:579:in `call_filters'
179
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/filters.rb:572:in `perform_action_without_benchmark'
180
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
181
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/1.8/benchmark.rb:293:in `measure'
182
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
183
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/rescue.rb:201:in `perform_action_without_caching'
184
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/caching/sql_cache.rb:13:in `passenger_orig_perform_action'
185
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/connection_adapters/abstract/query_cache.rb:33:in `cache'
186
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/query_cache.rb:8:in `cache'
187
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/caching/sql_cache.rb:12:in `passenger_orig_perform_action'
188
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/request_handler.rb:53:in `perform_action'
189
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/base.rb:529:in `send'
190
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/base.rb:529:in `process_without_filters'
191
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/filters.rb:568:in `process_without_session_management_support'
192
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/session_management.rb:130:in `process'
193
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/base.rb:389:in `process'
194
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:149:in `handle_request'
195
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:107:in `dispatch'
196
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:104:in `synchronize'
197
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:104:in `dispatch'
198
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:120:in `dispatch_cgi'
199
+ /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_controller/dispatcher.rb:35:in `dispatch'
200
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/request_handler.rb:38:in `process_request'
201
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_request_handler.rb:165:in `main_loop'
202
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:321:in `start_request_handler'
203
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:282:in `handle_spawn_application'
204
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:163:in `safe_fork'
205
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:161:in `fork'
206
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:161:in `safe_fork'
207
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:280:in `handle_spawn_application'
208
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:163:in `safe_fork'
209
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:161:in `fork'
210
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/utils.rb:161:in `safe_fork'
211
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:279:in `handle_spawn_application'
212
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `__send__'
213
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `main_loop'
214
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:168:in `start_synchronously'
215
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:135:in `start'
216
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:112:in `fork'
217
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:112:in `start'
218
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/application_spawner.rb:179:in `start'
219
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/framework_spawner.rb:270:in `handle_spawn_application'
220
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/framework_spawner.rb:263:in `synchronize'
221
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/framework_spawner.rb:263:in `handle_spawn_application'
222
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `__send__'
223
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `main_loop'
224
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:168:in `start_synchronously'
225
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:135:in `start'
226
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:112:in `fork'
227
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:112:in `start'
228
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/railz/framework_spawner.rb:87:in `start'
229
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:222:in `spawn_rails_application'
230
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:217:in `synchronize'
231
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:217:in `spawn_rails_application'
232
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:126:in `spawn_application'
233
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/spawn_manager.rb:251:in `handle_spawn_application'
234
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `__send__'
235
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:317:in `main_loop'
236
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/lib/passenger/abstract_server.rb:168:in `start_synchronously'
237
+ /opt/ruby/lib/ruby/gems/1.8/gems/passenger-2.0.6/bin/passenger-spawn-server:46
238
+
239
+
240
+
241
+ Processing QuestionViewsController#create (for 76.119.35.134 at 2009-02-24 01:30:39) [POST]
242
+ Session ID: 436d4f7cab8b7da618a96d28d79162af
243
+ Parameters: {"authenticity_token"=>"a3c2dbfb77d04c48ecf4f1f2660d540200c5cf3a", "action"=>"create", "controller"=>"question_views", "question_view"=>{"question_id"=>"996", "time"=>"483.6666666666667"}}
244
+ Completed in 0.02800 (35 reqs/sec) | Rendering: 0.00400 (14%) | DB: 0.02400 (85%) | 200 OK [http://play.scavengrnet.com/question_views]
245
+
246
+
@@ -0,0 +1,72 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class SlowActionsTest < Test::Unit::TestCase
4
+ def setup
5
+ @log_file = File.join(File.dirname(__FILE__), 'data', 'production.recent.log')
6
+ @sa = SlowActions.new
7
+ @sa.parse_file(@log_file)
8
+ end
9
+
10
+ def teardown
11
+
12
+ end
13
+
14
+ should "be able to read actions from a file" do
15
+ assert @sa.log_entries.size > 0, "No actions returned"
16
+ assert_equal 16, @sa.log_entries.size, "Wrong number of actions"
17
+ error_action = @sa.log_entries.detect{|la| la.error? }
18
+ assert_not_nil error_action, "There should be an error action"
19
+ end
20
+
21
+ should "have populated controllers" do
22
+ @sa.controllers.each do |c|
23
+ assert c.log_entries.size > 0
24
+ end
25
+ # Make sure each log entry belongs to a controller
26
+ @sa.log_entries.each do |la|
27
+ assert_not_nil @sa.controllers.detect{|c| c.log_entries.include?(la)}
28
+ # and only one controller claims it
29
+ assert_equal 1, @sa.controllers.select{|c| c.log_entries.include?(la)}.size
30
+ end
31
+ end
32
+
33
+ should "have populated actions" do
34
+ @sa.actions.each do |a|
35
+ assert a.log_entries.size > 0
36
+ end
37
+ # Make sure each log entry belongs to an action
38
+ @sa.log_entries.each do |la|
39
+ assert_not_nil @sa.actions.detect{|a| a.log_entries.include?(la)}
40
+ # and only one action claims it
41
+ assert_equal 1, @sa.actions.select{|a| a.log_entries.include?(la)}.size
42
+ end
43
+ end
44
+
45
+ should "have populated sessions" do
46
+ @sa.sessions.each do |a|
47
+ assert a.log_entries.size > 0
48
+ end
49
+ # Make sure each log entry belongs to a session
50
+ @sa.log_entries.each do |la|
51
+ assert_not_nil @sa.sessions.detect{|s| s.log_entries.include?(la)}
52
+ # and only one session claims it
53
+ assert_equal 1, @sa.sessions.select{|s| s.log_entries.include?(la)}.size
54
+ end
55
+ end
56
+
57
+ should "compute times" do
58
+ (@sa.controllers + @sa.actions + @sa.sessions).each do |obj|
59
+ # don't count them as faulty if they are all errors
60
+ next if obj.error_avg == 1
61
+ %w(total_avg total_max total_cost).each do |var|
62
+ assert obj.send(var) > 0, "#{obj.name} should have #{var} that is not 0"
63
+ end
64
+ end
65
+ end
66
+
67
+ should "render text without errors" do
68
+ @sa.print_actions
69
+ @sa.print_controller_tree
70
+ @sa.print_sessions
71
+ end
72
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'slow_actions'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ngauthier-slow-actions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Nick Gauthier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-26 00:00:00 -08:00
13
+ default_executable: slow-actions
14
+ dependencies: []
15
+
16
+ description: TODO
17
+ email: nick@smartlogicsolutions.com
18
+ executables:
19
+ - slow-actions
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - VERSION.yml
26
+ - README.rdoc
27
+ - bin/slow-actions
28
+ - lib/slow_actions_controller.rb
29
+ - lib/slow_actions_action.rb
30
+ - lib/slow_actions_parser.rb
31
+ - lib/slow_actions_log_entry.rb
32
+ - lib/slow_actions.rb
33
+ - lib/slow_actions_session.rb
34
+ - lib/slow_actions_computation_module.rb
35
+ - test/test_helper.rb
36
+ - test/data
37
+ - test/data/production.recent.log
38
+ - test/slow_actions_test.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/ngauthier/slow-actions
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --inline-source
44
+ - --charset=UTF-8
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.2.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: TODO
66
+ test_files: []
67
+