ngauthier-slow-actions 0.2.6 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 2
3
- :patch: 6
2
+ :minor: 3
3
+ :patch: 0
4
4
  :major: 0
data/bin/slow-actions CHANGED
@@ -1,7 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.join(File.dirname(__FILE__), '..', 'lib', 'slow_actions')
3
3
 
4
- @sa = SlowActions.new
4
+ opts = {}
5
+ start_date = ARGV.detect{|arg| arg =~/--start-date=(\S+)/}
6
+ opts[:start_date] = $1 if start_date
7
+ end_date = ARGV.detect{|arg| arg =~/--end-date=(\S+)/}
8
+ opts[:end_date] = $1 if start_date
9
+
10
+
11
+ @sa = SlowActions.new(opts)
5
12
  ARGV.select{|arg| arg[0,2] != "--"}.each do |file|
6
13
  @sa.parse_file(file)
7
14
  end
@@ -34,6 +41,8 @@ if output.size == 0
34
41
  puts "\t--min-cost=FLOAT"
35
42
  puts "\t--min-avg=FLOAT"
36
43
  puts "\t--min-max=FLOAT"
44
+ puts "\t--start-date=YYYY-MM-DD"
45
+ puts "\t--end-date=YYYY-MM-DD"
37
46
  else
38
47
  puts output.join("\n\n")
39
48
  end
data/lib/slow_actions.rb CHANGED
@@ -1,23 +1,44 @@
1
+ # Main class for the slow actions plugin library
1
2
  require File.join(File.dirname(__FILE__), 'slow_actions_parser')
2
3
  require File.join(File.dirname(__FILE__), 'slow_actions_controller')
3
4
  require File.join(File.dirname(__FILE__), 'slow_actions_action')
4
5
  require File.join(File.dirname(__FILE__), 'slow_actions_session')
6
+ require 'date'
5
7
 
8
+ # SlowActions class that is the master controller for processing slow actions
6
9
  class SlowActions
7
- def initialize
10
+ # Takes an options hash where you can specify :start_date and :end_date as "YYYY-MM-DD" strings
11
+ def initialize(opts = {})
8
12
  @log_entries = []
13
+ if opts[:start_date]
14
+ @start_date = Date.strptime(opts[:start_date])
15
+ else
16
+ @start_date = Date.strptime
17
+ end
18
+ if opts[:end_date]
19
+ @end_date = Date.strptime(opts[:end_date])
20
+ else
21
+ @end_date = Date.today
22
+ end
9
23
  end
10
24
 
25
+ # Parse the file found at "file_path" and add the log entries to its collection of entries.
11
26
  def parse_file(file_path)
12
- parser = Parser.new(file_path)
27
+ parser = Parser.new(file_path, @start_date, @end_date)
13
28
  @log_entries += parser.parse
14
29
  process
15
30
  end
16
31
 
32
+ # All the #LogEntry objects
17
33
  def log_entries
18
34
  return @log_entries
19
35
  end
20
36
 
37
+ # Print out all the actions and their statistics
38
+ #
39
+ # :mincost Lower bound on the cost of this action. See Computable.
40
+ # :minavg Lower bound on the average amount of time this action ever took
41
+ # :minmax Lower bound on the maximum amount of time this action ever took
21
42
  def print_actions(opts = {})
22
43
  str = ""
23
44
  str += " Cost Average Max\n"
@@ -34,6 +55,7 @@ class SlowActions
34
55
  return str
35
56
  end
36
57
 
58
+ # Print out all the controllers and their statistics, nesting actions as a tree. See #print_actions for options.
37
59
  def print_controller_tree(opts = {})
38
60
  str = ""
39
61
  str += " Cost Average Max\n"
@@ -59,6 +81,7 @@ class SlowActions
59
81
  return str
60
82
  end
61
83
 
84
+ # Print out all the session_ids and their statistics. See #print_actions for options.
62
85
  def print_sessions(opts = {})
63
86
  str = ""
64
87
  str += " Cost Average Max\n"
@@ -75,30 +98,40 @@ class SlowActions
75
98
  return str
76
99
  end
77
100
 
101
+ # Print out the stats as html. Not implemented.
78
102
  def to_html
79
103
  raise "Not Implemented"
80
104
  end
81
105
 
106
+ # All the #Controller objects.
82
107
  def controllers
83
108
  @controllers.values
84
109
  end
85
110
 
111
+ # All the #Action objects
86
112
  def actions
87
113
  @actions.values
88
114
  end
89
115
 
116
+ # All the #Session objects
90
117
  def sessions
91
118
  @sessions.values
92
119
  end
93
120
 
94
121
  private
95
122
 
123
+ # The Date to start parsing from
124
+ attr_accessor :start_date
125
+ # The Date to stop parsing at
126
+ attr_accessor :end_date
127
+
128
+ # Process statistics for all #Actions #Controllers and #Sessions
96
129
  def process
97
130
  @controllers ||= {}
98
131
  @actions ||= {}
99
132
  @sessions ||= {}
100
133
  @log_entries.each do |la|
101
- next if la.processed
134
+ next if la.nil? or la.processed
102
135
  c = @controllers[la.controller]
103
136
  if c.nil?
104
137
  c = Controller.new(la.controller)
@@ -129,6 +162,7 @@ class SlowActions
129
162
  @sessions.values.each{|s| s.compute_times}
130
163
  end
131
164
 
165
+ # Convert a float to 7 places padded with zeros then one space
132
166
  def ftos(float)
133
167
  str = ((float*1000).to_i.to_f/1000).to_s
134
168
  while str.size < 7
@@ -1,20 +1,29 @@
1
1
  require File.join(File.dirname(__FILE__), 'slow_actions_computation_module')
2
2
  class SlowActions
3
3
  private
4
+ # Class to hold all #LogEntry objects that are associated with this individual #Action on a #Controller
4
5
  class Action
5
6
  include Computable
7
+ # Create a new #Action object.
8
+ # name: the #name of the #Action. i.e. "new"
9
+ # controller: the #Controller this #Action is a part of
6
10
  def initialize(name, controller)
7
11
  @name = name
8
12
  @controller = controller
9
13
  @log_entries = []
10
14
  end
15
+
16
+ # Name of this #Action
11
17
  attr_reader :name
18
+ # #Controller of this #Action
12
19
  attr_reader :controller
13
20
 
21
+ # Add a log entry to this #Action
14
22
  def add_entry(la)
15
23
  @log_entries << la
16
24
  la.action = self
17
25
  end
26
+ # All the #LogEntry objects this #Action holds
18
27
  attr_reader :log_entries
19
28
 
20
29
  end
@@ -1,9 +1,32 @@
1
+ # Computable module provides the attributes and methods to compute statistics on log entries
2
+ #
3
+ # Cost is computed as
4
+ # avg * Math.log(total + 0.1)
5
+ #
6
+ # So that it can take into account the frequency for which an action is called
1
7
  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
8
+ # the average time for rendering
9
+ attr_reader :render_avg
10
+ # the average time for the database
11
+ attr_reader :db_avg
12
+ # the average time for the entire object
13
+ attr_reader :total_avg
14
+ # the maximum time an object ever took to render
15
+ attr_reader :render_max
16
+ # the maximum time an object ever took to query the database
17
+ attr_reader :db_max
18
+ # the maximum time an object ever took to complete the entire action
19
+ attr_reader :total_max
20
+ # cost for this action to render
21
+ attr_reader :render_cost
22
+ # cost for this action to query the db
23
+ attr_reader :db_cost
24
+ # cost for this action to complete
25
+ attr_reader :total_cost
26
+ # average error rate for this action
5
27
  attr_reader :error_avg
6
28
 
29
+ # Perform all the computations in one loop
7
30
  def compute_times
8
31
  @render_avg = 0.0
9
32
  @db_avg = 0.0
@@ -1,24 +1,32 @@
1
1
  require File.join(File.dirname(__FILE__), 'slow_actions_computation_module')
2
2
  class SlowActions
3
3
  private
4
+ # Class to hold all #LogEntry objects that are associated with this #Controller.
4
5
  class Controller
5
6
  include Computable
7
+ # Create a new #Controller
8
+ # name: The name of the #Controller
6
9
  def initialize(name)
7
10
  @name = name
8
11
  @log_entries = []
9
12
  @actions = []
10
13
  end
14
+ # Name of the #Controller
11
15
  attr_reader :name
12
16
 
17
+ # Add a #LogEntry to this #Controller
13
18
  def add_entry(la)
14
19
  @log_entries << la
15
20
  la.controller = self
16
21
  end
22
+ # All the #LogEntry objects associated with this #Controller
17
23
  attr_reader :log_entries
18
24
 
25
+ # Add an #Action as a child of this #Controller
19
26
  def add_action(a)
20
27
  @actions << a
21
28
  end
29
+ # All the #Actions under this #Controller
22
30
  attr_reader :actions
23
31
 
24
32
  end
@@ -1,23 +1,39 @@
1
1
  class SlowActions
2
2
  private
3
+ # Object representing a single entry in a rails application's log file
3
4
  class LogEntry
5
+ # Create a new #LogEntry
4
6
  def initialize
5
7
  self.processed = false
6
8
  end
9
+ # The #Controller
7
10
  attr_accessor :controller
11
+ # The #Action
8
12
  attr_accessor :action
13
+ # IP address of user
9
14
  attr_accessor :ip
15
+ # date
10
16
  attr_accessor :date
17
+ # time
11
18
  attr_accessor :time
19
+ # HTTP Method
12
20
  attr_accessor :method
21
+ # Session ID
13
22
  attr_accessor :session
23
+ # Parameters to the action
14
24
  attr_accessor :parameters
25
+ # Total duration to complete
15
26
  attr_accessor :duration
27
+ # time spent rendering
16
28
  attr_accessor :rendering
29
+ # time spent in the database
17
30
  attr_accessor :db
31
+ # error text (if any)
18
32
  attr_accessor :error_text
33
+ # whether or not is has already been processed by #SlowActions
19
34
  attr_accessor :processed
20
35
 
36
+ # Whether or not this #LogEntry was an error
21
37
  def error?
22
38
  return false if error_text.nil?
23
39
  return false if error_text.empty?
@@ -1,14 +1,23 @@
1
1
  require File.join(File.dirname(__FILE__), 'slow_actions_log_entry')
2
2
  class SlowActions
3
3
  private
4
+ # Text parser for #SlowActions
4
5
  class Parser
5
6
 
6
- def initialize(file_path)
7
+ # Create a new #Parser
8
+ # file_path: path to log file to parse
9
+ # start_date: Date object. Entries before this date are skipped
10
+ # end_date: Date object. Entries after this date are skipped
11
+ # Dates are inclusive
12
+ def initialize(file_path, start_date, end_date)
7
13
  @file_path = file_path
8
14
  raise "File not found: #{file_path}" unless File.exists? file_path
9
15
  @file = File.new(file_path, 'r')
16
+ @start_date = start_date
17
+ @end_date = end_date
10
18
  end
11
-
19
+
20
+ # Initiate the parsing
12
21
  def parse
13
22
  @log_entries = []
14
23
  begin
@@ -26,6 +35,8 @@ class SlowActions
26
35
 
27
36
  private
28
37
 
38
+ # Parse an individual entry
39
+ # line: one line of text
29
40
  def parse_log_entry(line)
30
41
  la = LogEntry.new
31
42
  if line =~ /^Processing (\S+)#(\S+) \(for (\S+) at (\S+) (\S+)\) \[(\S+)\]$/
@@ -35,6 +46,10 @@ class SlowActions
35
46
  la.date = $4
36
47
  la.time = $5
37
48
  la.method = $6
49
+ parsed_date = Date.strptime(la.date)
50
+ if parsed_date < @start_date or parsed_date > @end_date
51
+ return nil
52
+ end
38
53
  end
39
54
  line = @file.readline
40
55
  if line =~ /^\s+Session ID: (\S+)$/
@@ -69,6 +84,7 @@ class SlowActions
69
84
  return la
70
85
  end
71
86
 
87
+ # parse an error
72
88
  def parse_error
73
89
  line = "\n"
74
90
  while line == "\n"
@@ -1,18 +1,24 @@
1
1
  require File.join(File.dirname(__FILE__), 'slow_actions_computation_module')
2
2
  class SlowActions
3
3
  private
4
+ # Class to hold and #LogEntry objects that are associated with this individual Session ID
4
5
  class Session
5
6
  include Computable
7
+ # Create a new session
8
+ # name: the session_id
6
9
  def initialize(name)
7
10
  @name = name
8
11
  @log_entries = []
9
12
  end
13
+ # The session_id
10
14
  attr_reader :name
11
15
 
16
+ # Add a #LogEntry to this #Session
12
17
  def add_entry(la)
13
18
  @log_entries << la
14
19
  la.session = self
15
20
  end
21
+ # All the #LogEntry objects this #Session holds
16
22
  attr_reader :log_entries
17
23
 
18
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ngauthier-slow-actions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Gauthier