rails_request_stats 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67a34ab4f6878674fdf3cf11c2b9129bd25d61fb
4
- data.tar.gz: 1bd610a86b78aa721061c875d517057e9c43bfc5
3
+ metadata.gz: c2d27ad0c7ca09478c330b639daab0a4813a2256
4
+ data.tar.gz: 5265e09e5fa4c1b39f30d8232ffb2b544b1dec27
5
5
  SHA512:
6
- metadata.gz: 46500b124a71c42c4ab0aa609eb004b090528be062ab12999c8db9e4141586dd2cdd6abc502c6fe5a399c2ca65f6e8c0ced702daf5fc4b2a4080232271b0304f
7
- data.tar.gz: bb43c7e65b32142a7823acdf71999aef0d2e2d5aec8efeafbd3465bc201c5cb5bf3e5b59f3f473106f4ef35d10eec19b5f5d38df6a7954aef8ab1c3fece36c74
6
+ metadata.gz: f66bf947b48629445e225ae7ce1b43131e8d7d4e9d697d67a017422c8d9e4fad6cb567da2074ffd697d7ca5b5423a1aeef417dc3d01ed641a36405910ed1f94f
7
+ data.tar.gz: 5662c228ddbaa04ab9f45a7e35d5c5e0264f2b8302be7c0512b9021e9700aea0fd8c91a72fe65316f463653b35d02fabda3cec46d5e8b423ac9eb3343a476848
data/README.md CHANGED
@@ -19,7 +19,7 @@ During development have you ever:
19
19
  `RailsRequestStats::NotificationSubscribers` when required will subscribe to the `sql.active_record`, `start_processing.action_controller`, and `process_action.action_controller` `ActionSupport::Notifications`.
20
20
 
21
21
  * The `sql.active_record` event allow us to count each SQL query that passes though ActiveRecord, which we count internally.
22
- * The `start_processing.action_controller` event allows us to clear iternal counts, as well as perform a `GC.start` and capturing the total number of objects residing in the `ObjectSpace`.
22
+ * The `start_processing.action_controller` event allows us to clear iternal counts, as well as perform a `GC.start` and capturing the count of objects residing in the `ObjectSpace`.
23
23
  * The `process_action.action_controller` event provides us runtime information along with identifying controller action details, we even determine the number of generated objects since the start of processing the action. At this point we are able to synthesis the query information and runtime information and store them internally in running collection of `RailsRequestStats::RequestStats` objects.
24
24
 
25
25
  **Note** the data collection is tracked and stored in class-level instance variables. Thus this is not threadsafe, as no concurrency mechanisms are used (i.e., mutex). For non-threaded and forking application servers this should be fine.
@@ -50,6 +50,21 @@ Finally when you exit the application's server, you should see a report of all t
50
50
 
51
51
  ## Customizing Outputs
52
52
 
53
+ ### Memory Stats
54
+ By setting the following class variable within in an initializer (`./config/initializers/rails_request_stats.rb`):
55
+
56
+ ```ruby
57
+ RailsRequestStats::Report.print_memory_stats = true
58
+ ```
59
+
60
+ You can see the *generated objects* within the `ObjectSpace` for individual requests:
61
+
62
+ ```
63
+ [RailsRequestStats] (AVG view_runtime: 93.7252ms | AVG db_runtime: 8.66075ms | AVG generated_object_count: 125282 | query_count: 8 | cached_query_count: 0 | generated_objects: {:total_generated_objects=>111878, :object=>921, :class=>35, :module=>0, :float=>0, :string=>49501, :regexp=>1556, :array=>17855, :hash=>2087, :struct=>103, :bignum=>0, :file=>0, :data=>37682, :match=>373, :complex=>0, :node=>1688, :iclass=>0})
64
+ ```
65
+
66
+ ### Override Reports
67
+
53
68
  You can manually override the output by monkey-patching in an initializer (`./config/initializers/rails_request_stats.rb`):
54
69
 
55
70
  ```ruby
@@ -81,4 +96,3 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/kevinj
81
96
  ## License
82
97
 
83
98
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
84
-
@@ -1,7 +1,4 @@
1
- require 'rails_request_stats/version'
2
- require 'rails_request_stats/request_stats'
3
- require 'rails_request_stats/report'
4
- require 'rails_request_stats/notification_subscribers'
1
+ Dir.glob(File.dirname(__FILE__) + '/**/*.rb') { |file| require file }
5
2
 
6
3
  module RailsRequestStats
7
4
  end
@@ -3,17 +3,19 @@ module RailsRequestStats
3
3
  SCHEMA_NAME = 'SCHEMA'.freeze
4
4
  CACHE_NAME = 'CACHE'.freeze
5
5
 
6
- attr_reader :query_count,
7
- :cached_query_count,
8
- :before_action_object_count,
9
- :generated_object_count,
10
- :requests
6
+ class << self
7
+ attr_accessor :query_count,
8
+ :cached_query_count,
9
+ :before_object_space,
10
+ :after_object_space
11
+ :requests
12
+ end
11
13
 
12
14
  def self.reset_counts
13
15
  @query_count = 0
14
16
  @cached_query_count = 0
15
- @before_action_object_count = 0
16
- @generated_object_count = 0
17
+ @before_object_space = {}
18
+ @after_object_space = {}
17
19
  end
18
20
  reset_counts
19
21
 
@@ -55,28 +57,29 @@ module RailsRequestStats
55
57
  reset_counts
56
58
 
57
59
  GC.start
58
- @before_action_object_count = total_object_count
60
+ GC.disable
61
+
62
+ @before_object_space = ObjectSpace.count_objects(@before_object_space)
59
63
  end
60
64
 
61
65
  def self.handle_process_action_event(event)
62
- @generated_object_count = total_object_count - @before_action_object_count
66
+ @after_object_space = ObjectSpace.count_objects(@after_object_space)
63
67
 
64
- request_key = { action: event[:action], format: event[:format], method: event[:method], path: event[:path] }
68
+ GC.enable
65
69
 
70
+ request_key = { action: event[:action], format: event[:format], method: event[:method], path: event[:path] }
66
71
  request_stats = @requests[request_key] || RequestStats.new(request_key)
67
- request_stats.add_stats(event[:view_runtime], event[:db_runtime], @query_count, @cached_query_count, @generated_object_count)
68
-
69
- @requests[request_key] = request_stats
72
+ @requests[request_key] = request_stats.tap do |stats|
73
+ stats.add_database_query_stats(@query_count, @cached_query_count)
74
+ stats.add_object_space_stats(@before_object_space, @after_object_space)
75
+ stats.add_runtime_stats(event[:view_runtime], event[:db_runtime])
76
+ end
70
77
 
71
- Rails.logger.info { Report.new(request_stats).report_text }
78
+ print_report(request_stats)
72
79
  end
73
80
 
74
- class << self
75
- private
76
-
77
- def total_object_count
78
- ObjectSpace.count_objects.select { |k, v| k.to_s.start_with?('T_') }.values.reduce(:+)
79
- end
81
+ def self.print_report(request_stats)
82
+ Rails.logger.info { Report.new(request_stats).report_text }
80
83
  end
81
84
  end
82
85
  end
@@ -2,6 +2,11 @@ module RailsRequestStats
2
2
  class Report
3
3
  FORMAT_FLAG = '%g'.freeze
4
4
 
5
+ class << self
6
+ attr_accessor :print_memory_stats
7
+ end
8
+ self.print_memory_stats = false
9
+
5
10
  attr_reader :request_stats
6
11
 
7
12
  def initialize(request_stats)
@@ -9,60 +14,52 @@ module RailsRequestStats
9
14
  end
10
15
 
11
16
  def report_text
12
- avg_view_runtime = "AVG view_runtime: #{format_number(avg_stat(:view_runtime))}ms"
13
- avg_db_runtime = "AVG db_runtime: #{format_number(avg_stat(:db_runtime))}ms"
14
- avg_generated_object_count = "AVG generated_object_count: #{format_number(avg_stat(:generated_object_count))}"
15
- query_count = "query_count: #{format_number(last_stat(:query_count))}"
16
- cached_query_count = "cached_query_count: #{format_number(last_stat(:cached_query_count))}"
17
+ avg_view_runtime = "AVG view_runtime: #{format_number(avg(runtime_stats.view_runtime_collection))}ms"
18
+ avg_db_runtime = "AVG db_runtime: #{format_number(avg(runtime_stats.db_runtime_collection))}ms"
19
+ avg_generated_object_count = "AVG generated_object_count: #{format_number(avg(object_space_stats.generated_object_count_collection))}"
20
+ query_count = "query_count: #{format_number(database_query_stats.query_count_collection.last)}"
21
+ cached_query_count = "cached_query_count: #{format_number(database_query_stats.cached_query_count_collection.last)}"
22
+ generated_objects = self.class.print_memory_stats ? "generated_objects: #{object_space_stats.last_stats_generated_objects}" : nil
17
23
 
18
- "[RailsRequestStats] (#{[avg_view_runtime, avg_db_runtime, avg_generated_object_count, query_count, cached_query_count].join(' | ')})"
24
+ "[RailsRequestStats] (#{[avg_view_runtime, avg_db_runtime, avg_generated_object_count, query_count, cached_query_count, generated_objects].compact.join(' | ')})"
19
25
  end
20
26
 
21
27
  def exit_report_text
22
28
  controller_information = "[RailsRequestStats] #{@request_stats.action.upcase}:#{@request_stats.format} \"#{@request_stats.path}\""
23
- avg_view_runtime = "AVG view_runtime: #{format_number(avg_stat(:view_runtime))}ms"
24
- avg_db_runtime = "AVG db_runtime: #{format_number(avg_stat(:db_runtime))}ms"
25
- avg_generated_object_count = "AVG generated_object_count: #{format_number(avg_stat(:generated_object_count))}"
26
- min_query_count = "MIN query_count: #{format_number(min_stat(:query_count))}"
27
- max_query_count = "MAX query_count: #{format_number(max_stat(:query_count))}"
28
- request_count = "from #{format_number(count_stat(:view_runtime))} requests"
29
+ avg_view_runtime = "AVG view_runtime: #{format_number(avg(runtime_stats.view_runtime_collection))}ms"
30
+ avg_db_runtime = "AVG db_runtime: #{format_number(avg(runtime_stats.db_runtime_collection))}ms"
31
+ avg_generated_object_count = "AVG generated_object_count: #{format_number(avg(object_space_stats.generated_object_count_collection))}"
32
+ min_query_count = "MIN query_count: #{format_number(database_query_stats.query_count_collection.min)}"
33
+ max_query_count = "MAX query_count: #{format_number(database_query_stats.query_count_collection.max)}"
34
+ request_count = "from #{format_number(runtime_stats.view_runtime_collection.size)} requests"
29
35
 
30
36
  "#{controller_information} (#{[avg_view_runtime, avg_db_runtime, avg_generated_object_count, min_query_count, max_query_count].join(' | ')}) #{request_count}"
31
37
  end
32
38
 
33
- def min_stat(category)
34
- category_collection(category).min
39
+ def total(collection)
40
+ collection.reduce(:+)
35
41
  end
36
42
 
37
- def max_stat(category)
38
- category_collection(category).max
43
+ def avg(collection)
44
+ total(collection).to_f / collection.size
39
45
  end
40
46
 
41
- def total_stat(category)
42
- category_collection(category).reduce(:+)
43
- end
44
-
45
- def count_stat(category)
46
- category_collection(category).size
47
- end
47
+ private
48
48
 
49
- def last_stat(category)
50
- category_collection(category).last
49
+ def format_number(number)
50
+ format(FORMAT_FLAG, number || 0)
51
51
  end
52
52
 
53
- def avg_stat(category)
54
- total_stat(category).to_f / count_stat(category)
53
+ def database_query_stats
54
+ @database_query_stats ||= @request_stats.database_query_stats
55
55
  end
56
56
 
57
- private
58
-
59
- def format_number(number)
60
- format(FORMAT_FLAG, number)
57
+ def object_space_stats
58
+ @object_space_stats ||= @request_stats.object_space_stats
61
59
  end
62
60
 
63
- def category_collection(category)
64
- collection_variable_name = "#{category}_collection"
65
- @request_stats.public_send(collection_variable_name) if @request_stats.respond_to?(collection_variable_name)
61
+ def runtime_stats
62
+ @runtime_stats ||= @request_stats.runtime_stats
66
63
  end
67
64
  end
68
65
  end
@@ -5,11 +5,9 @@ module RailsRequestStats
5
5
  :method,
6
6
  :path,
7
7
 
8
- :view_runtime_collection,
9
- :db_runtime_collection,
10
- :query_count_collection,
11
- :cached_query_count_collection,
12
- :generated_object_count_collection
8
+ :database_query_stats,
9
+ :object_space_stats,
10
+ :runtime_stats
13
11
 
14
12
  def initialize(key)
15
13
  @action = key[:action]
@@ -17,19 +15,21 @@ module RailsRequestStats
17
15
  @method = key[:method]
18
16
  @path = key[:path]
19
17
 
20
- @view_runtime_collection = []
21
- @db_runtime_collection = []
22
- @query_count_collection = []
23
- @cached_query_count_collection = []
24
- @generated_object_count_collection = []
18
+ @database_query_stats = Stats::DatabaseQueryStats.new
19
+ @object_space_stats = Stats::ObjectSpaceStats.new
20
+ @runtime_stats = Stats::RuntimeStats.new
25
21
  end
26
22
 
27
- def add_stats(view_runtime, db_runtime, query_count, cached_query_count, generated_object_count)
28
- @view_runtime_collection << view_runtime.to_f
29
- @db_runtime_collection << db_runtime.to_f
30
- @query_count_collection << query_count
31
- @cached_query_count_collection << cached_query_count
32
- @generated_object_count_collection << generated_object_count
23
+ def add_database_query_stats(query_count, cached_query_count)
24
+ @database_query_stats.add_stats(query_count, cached_query_count)
25
+ end
26
+
27
+ def add_object_space_stats(before_object_space, after_object_space)
28
+ @object_space_stats.add_stats(before_object_space, after_object_space)
29
+ end
30
+
31
+ def add_runtime_stats(view_runtime, db_runtime)
32
+ @runtime_stats.add_stats(view_runtime, db_runtime)
33
33
  end
34
34
  end
35
35
  end
@@ -0,0 +1,18 @@
1
+ module RailsRequestStats
2
+ module Stats
3
+ class DatabaseQueryStats
4
+ attr_reader :query_count_collection,
5
+ :cached_query_count_collection
6
+
7
+ def initialize
8
+ @query_count_collection = []
9
+ @cached_query_count_collection = []
10
+ end
11
+
12
+ def add_stats(query_count, cached_query_count)
13
+ @query_count_collection << query_count
14
+ @cached_query_count_collection << cached_query_count
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,89 @@
1
+ module RailsRequestStats
2
+ module Stats
3
+ class ObjectSpaceStats
4
+ attr_reader :object_count_collection,
5
+ :class_count_collection,
6
+ :module_count_collection,
7
+ :float_count_collection,
8
+ :string_count_collection,
9
+ :regexp_count_collection,
10
+ :array_count_collection,
11
+ :hash_count_collection,
12
+ :struct_count_collection,
13
+ :bignum_count_collection,
14
+ :file_count_collection,
15
+ :data_count_collection,
16
+ :match_count_collection,
17
+ :complex_count_collection,
18
+ :node_count_collection,
19
+ :iclass_count_collection,
20
+ :generated_object_count_collection
21
+
22
+ def initialize
23
+ @object_count_collection = []
24
+ @class_count_collection = []
25
+ @module_count_collection = []
26
+ @float_count_collection = []
27
+ @string_count_collection = []
28
+ @regexp_count_collection = []
29
+ @array_count_collection = []
30
+ @hash_count_collection = []
31
+ @struct_count_collection = []
32
+ @bignum_count_collection = []
33
+ @file_count_collection = []
34
+ @data_count_collection = []
35
+ @match_count_collection = []
36
+ @complex_count_collection = []
37
+ @node_count_collection = []
38
+ @iclass_count_collection = []
39
+ @generated_object_count_collection = []
40
+ end
41
+
42
+ def add_stats(before_object_space, after_object_space)
43
+ @object_count_collection << after_object_space[:T_OBJECT] - before_object_space[:T_OBJECT]
44
+ @class_count_collection << after_object_space[:T_CLASS] - before_object_space[:T_CLASS]
45
+ @module_count_collection << after_object_space[:T_MODULE] - before_object_space[:T_MODULE]
46
+ @float_count_collection << after_object_space[:T_FLOAT] - before_object_space[:T_FLOAT]
47
+ @string_count_collection << after_object_space[:T_STRING] - before_object_space[:T_STRING]
48
+ @regexp_count_collection << after_object_space[:T_REGEXP] - before_object_space[:T_REGEXP]
49
+ @array_count_collection << after_object_space[:T_ARRAY] - before_object_space[:T_ARRAY]
50
+ @hash_count_collection << after_object_space[:T_HASH] - before_object_space[:T_HASH]
51
+ @struct_count_collection << after_object_space[:T_STRUCT] - before_object_space[:T_STRUCT]
52
+ @bignum_count_collection << after_object_space[:T_BIGNUM] - before_object_space[:T_BIGNUM]
53
+ @file_count_collection << after_object_space[:T_FILE] - before_object_space[:T_FILE]
54
+ @data_count_collection << after_object_space[:T_DATA] - before_object_space[:T_DATA]
55
+ @match_count_collection << after_object_space[:T_MATCH] - before_object_space[:T_MATCH]
56
+ @complex_count_collection << after_object_space[:T_COMPLEX] - before_object_space[:T_COMPLEX]
57
+ @node_count_collection << after_object_space[:T_NODE] - before_object_space[:T_NODE]
58
+ @iclass_count_collection << after_object_space[:T_ICLASS] - before_object_space[:T_ICLASS]
59
+ @generated_object_count_collection << total_object_space_count(after_object_space) - total_object_space_count(before_object_space)
60
+ end
61
+
62
+ def total_object_space_count(object_space)
63
+ object_space.select { |k, v| k.to_s.start_with?('T_') }.values.reduce(:+)
64
+ end
65
+
66
+ def last_stats_generated_objects
67
+ {
68
+ total_generated_objects: generated_object_count_collection.last,
69
+ object: object_count_collection.last,
70
+ class: class_count_collection.last,
71
+ module: module_count_collection.last,
72
+ float: float_count_collection.last,
73
+ string: string_count_collection.last,
74
+ regexp: regexp_count_collection.last,
75
+ array: array_count_collection.last,
76
+ hash: hash_count_collection.last,
77
+ struct: struct_count_collection.last,
78
+ bignum: bignum_count_collection.last,
79
+ file: file_count_collection.last,
80
+ data: data_count_collection.last,
81
+ match: match_count_collection.last,
82
+ complex: complex_count_collection.last,
83
+ node: node_count_collection.last,
84
+ iclass: iclass_count_collection.last
85
+ }
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,18 @@
1
+ module RailsRequestStats
2
+ module Stats
3
+ class RuntimeStats
4
+ attr_reader :view_runtime_collection,
5
+ :db_runtime_collection
6
+
7
+ def initialize
8
+ @view_runtime_collection = []
9
+ @db_runtime_collection = []
10
+ end
11
+
12
+ def add_stats(view_runtime, db_runtime)
13
+ @view_runtime_collection << view_runtime
14
+ @db_runtime_collection << db_runtime
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsRequestStats
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_request_stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Jalbert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-05 00:00:00.000000000 Z
11
+ date: 2016-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -99,6 +99,9 @@ files:
99
99
  - lib/rails_request_stats/notification_subscribers.rb
100
100
  - lib/rails_request_stats/report.rb
101
101
  - lib/rails_request_stats/request_stats.rb
102
+ - lib/rails_request_stats/stats/database_query_stats.rb
103
+ - lib/rails_request_stats/stats/object_space_stats.rb
104
+ - lib/rails_request_stats/stats/runtime_stats.rb
102
105
  - lib/rails_request_stats/version.rb
103
106
  - rails_request_stats.gemspec
104
107
  homepage: https://github.com/kevinjalbert/rails_request_stats/