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 +4 -4
- data/README.md +16 -2
- data/lib/rails_request_stats.rb +1 -4
- data/lib/rails_request_stats/notification_subscribers.rb +23 -20
- data/lib/rails_request_stats/report.rb +31 -34
- data/lib/rails_request_stats/request_stats.rb +16 -16
- data/lib/rails_request_stats/stats/database_query_stats.rb +18 -0
- data/lib/rails_request_stats/stats/object_space_stats.rb +89 -0
- data/lib/rails_request_stats/stats/runtime_stats.rb +18 -0
- data/lib/rails_request_stats/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2d27ad0c7ca09478c330b639daab0a4813a2256
|
4
|
+
data.tar.gz: 5265e09e5fa4c1b39f30d8232ffb2b544b1dec27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
data/lib/rails_request_stats.rb
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
@
|
16
|
-
@
|
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
|
-
|
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
|
-
@
|
66
|
+
@after_object_space = ObjectSpace.count_objects(@after_object_space)
|
63
67
|
|
64
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
78
|
+
print_report(request_stats)
|
72
79
|
end
|
73
80
|
|
74
|
-
|
75
|
-
|
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(
|
13
|
-
avg_db_runtime = "AVG db_runtime: #{format_number(
|
14
|
-
avg_generated_object_count = "AVG generated_object_count: #{format_number(
|
15
|
-
query_count = "query_count: #{format_number(
|
16
|
-
cached_query_count = "cached_query_count: #{format_number(
|
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(
|
24
|
-
avg_db_runtime = "AVG db_runtime: #{format_number(
|
25
|
-
avg_generated_object_count = "AVG generated_object_count: #{format_number(
|
26
|
-
min_query_count = "MIN query_count: #{format_number(
|
27
|
-
max_query_count = "MAX query_count: #{format_number(
|
28
|
-
request_count = "from #{format_number(
|
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
|
34
|
-
|
39
|
+
def total(collection)
|
40
|
+
collection.reduce(:+)
|
35
41
|
end
|
36
42
|
|
37
|
-
def
|
38
|
-
|
43
|
+
def avg(collection)
|
44
|
+
total(collection).to_f / collection.size
|
39
45
|
end
|
40
46
|
|
41
|
-
|
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
|
50
|
-
|
49
|
+
def format_number(number)
|
50
|
+
format(FORMAT_FLAG, number || 0)
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
54
|
-
|
53
|
+
def database_query_stats
|
54
|
+
@database_query_stats ||= @request_stats.database_query_stats
|
55
55
|
end
|
56
56
|
|
57
|
-
|
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
|
64
|
-
|
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
|
-
:
|
9
|
-
:
|
10
|
-
:
|
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
|
-
@
|
21
|
-
@
|
22
|
-
@
|
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
|
28
|
-
@
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
@
|
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
|
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.
|
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-
|
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/
|