rails_performance 1.2.3 → 1.3.1

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -13
  3. data/Rakefile +14 -14
  4. data/app/assets/images/download.svg +3 -0
  5. data/app/controllers/rails_performance/base_controller.rb +21 -21
  6. data/app/controllers/rails_performance/concerns/csv_exportable.rb +29 -0
  7. data/app/controllers/rails_performance/rails_performance_controller.rb +96 -49
  8. data/app/helpers/rails_performance/rails_performance_helper.rb +152 -156
  9. data/app/views/rails_performance/javascripts/app.js +2 -2
  10. data/app/views/rails_performance/rails_performance/_export.html.erb +3 -0
  11. data/app/views/rails_performance/rails_performance/crashes.html.erb +8 -1
  12. data/app/views/rails_performance/rails_performance/index.html.erb +29 -0
  13. data/app/views/rails_performance/rails_performance/recent.html.erb +8 -6
  14. data/app/views/rails_performance/rails_performance/requests.html.erb +15 -1
  15. data/app/views/rails_performance/rails_performance/slow.html.erb +3 -0
  16. data/app/views/rails_performance/shared/_header.html.erb +0 -1
  17. data/app/views/rails_performance/stylesheets/style.css +10 -0
  18. data/config/routes.rb +16 -18
  19. data/lib/generators/rails_performance/install/install_generator.rb +1 -1
  20. data/lib/generators/rails_performance/install/templates/initializer.rb +56 -42
  21. data/lib/rails_performance/data_source.rb +120 -121
  22. data/lib/rails_performance/engine.rb +8 -8
  23. data/lib/rails_performance/extensions/trace.rb +32 -33
  24. data/lib/rails_performance/gems/custom_ext.rb +31 -34
  25. data/lib/rails_performance/gems/delayed_job_ext.rb +50 -54
  26. data/lib/rails_performance/gems/grape_ext.rb +33 -35
  27. data/lib/rails_performance/gems/rake_ext.rb +41 -44
  28. data/lib/rails_performance/gems/sidekiq_ext.rb +34 -37
  29. data/lib/rails_performance/instrument/metrics_collector.rb +50 -50
  30. data/lib/rails_performance/models/base_record.rb +33 -36
  31. data/lib/rails_performance/models/collection.rb +35 -36
  32. data/lib/rails_performance/models/custom_record.rb +47 -48
  33. data/lib/rails_performance/models/delayed_job_record.rb +61 -62
  34. data/lib/rails_performance/models/grape_record.rb +60 -61
  35. data/lib/rails_performance/models/rake_record.rb +48 -49
  36. data/lib/rails_performance/models/request_record.rb +128 -120
  37. data/lib/rails_performance/models/sidekiq_record.rb +65 -66
  38. data/lib/rails_performance/models/trace_record.rb +18 -19
  39. data/lib/rails_performance/rails/middleware.rb +75 -76
  40. data/lib/rails_performance/rails/query_builder.rb +18 -20
  41. data/lib/rails_performance/reports/base_report.rb +60 -60
  42. data/lib/rails_performance/reports/breakdown_report.rb +15 -18
  43. data/lib/rails_performance/reports/crash_report.rb +15 -17
  44. data/lib/rails_performance/reports/percentile_report.rb +14 -0
  45. data/lib/rails_performance/reports/recent_requests_report.rb +24 -24
  46. data/lib/rails_performance/reports/requests_report.rb +30 -27
  47. data/lib/rails_performance/reports/response_time_report.rb +17 -17
  48. data/lib/rails_performance/reports/slow_requests_report.rb +4 -4
  49. data/lib/rails_performance/reports/throughput_report.rb +15 -17
  50. data/lib/rails_performance/reports/trace_report.rb +16 -18
  51. data/lib/rails_performance/thread/current_request.rb +33 -34
  52. data/lib/rails_performance/utils.rb +64 -54
  53. data/lib/rails_performance/version.rb +2 -2
  54. data/lib/rails_performance.rb +35 -36
  55. metadata +21 -17
@@ -1,35 +1,33 @@
1
- module RailsPerformance
2
- module Gems
3
- class GrapeExt
4
-
5
- def self.init
6
- ActiveSupport::Notifications.subscribe(/grape/) do |name, start, finish, id, payload|
7
- # TODO change to set
8
- CurrentRequest.current.ignore.add(:performance)
9
-
10
- now = Time.current
11
- CurrentRequest.current.data ||= {}
12
- CurrentRequest.current.record ||= RailsPerformance::Models::GrapeRecord.new(request_id: CurrentRequest.current.request_id)
13
- CurrentRequest.current.record.datetimei ||= now.to_i
14
- CurrentRequest.current.record.datetime ||= now.strftime(RailsPerformance::FORMAT)
15
-
16
- if ['endpoint_render.grape', 'endpoint_run.grape', 'format_response.grape'].include?(name)
17
- CurrentRequest.current.record.send(name.gsub(".", "_") + "=", (finish - start) * 1000)
18
- end
19
-
20
- if payload[:env]
21
- CurrentRequest.current.record.status = payload[:env]['api.endpoint'].status
22
- CurrentRequest.current.record.format = payload[:env]["api.format"]
23
- CurrentRequest.current.record.method = payload[:env]['REQUEST_METHOD']
24
- CurrentRequest.current.record.path = payload[:env]["PATH_INFO"]
25
- end
26
-
27
- if name == 'format_response.grape'
28
- CurrentRequest.current.record.save
29
- end
30
- end
31
- end
32
-
33
- end
34
- end
35
- end
1
+ module RailsPerformance
2
+ module Gems
3
+ class GrapeExt
4
+ def self.init
5
+ ActiveSupport::Notifications.subscribe(/grape/) do |name, start, finish, id, payload|
6
+ # TODO change to set
7
+ CurrentRequest.current.ignore.add(:performance)
8
+
9
+ now = Time.current
10
+ CurrentRequest.current.data ||= {}
11
+ CurrentRequest.current.record ||= RailsPerformance::Models::GrapeRecord.new(request_id: CurrentRequest.current.request_id)
12
+ CurrentRequest.current.record.datetimei ||= now.to_i
13
+ CurrentRequest.current.record.datetime ||= now.strftime(RailsPerformance::FORMAT)
14
+
15
+ if ["endpoint_render.grape", "endpoint_run.grape", "format_response.grape"].include?(name)
16
+ CurrentRequest.current.record.send(name.tr(".", "_") + "=", (finish - start) * 1000)
17
+ end
18
+
19
+ if payload[:env]
20
+ CurrentRequest.current.record.status = payload[:env]["api.endpoint"].status
21
+ CurrentRequest.current.record.format = payload[:env]["api.format"]
22
+ CurrentRequest.current.record.method = payload[:env]["REQUEST_METHOD"]
23
+ CurrentRequest.current.record.path = payload[:env]["PATH_INFO"]
24
+ end
25
+
26
+ if name == "format_response.grape"
27
+ CurrentRequest.current.record.save
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,44 +1,41 @@
1
- module RailsPerformance
2
- module Gems
3
-
4
- class RakeExt
5
- def self.init
6
- ::Rake::Task.class_eval do
7
- def invoke_with_rails_performance(*args)
8
- begin
9
- now = Time.current
10
- status = 'success'
11
- invoke_without_new_rails_performance(*args)
12
- rescue Exception => ex
13
- status = 'error'
14
- raise(ex)
15
- ensure
16
- if !RailsPerformance.skipable_rake_tasks.include?(self.name)
17
- task_info = RailsPerformance::Gems::RakeExt.find_task_name(*args)
18
- task_info = [self.name] if task_info.empty?
19
- RailsPerformance::Models::RakeRecord.new(
20
- task: task_info,
21
- datetime: now.strftime(RailsPerformance::FORMAT),
22
- datetimei: now.to_i,
23
- duration: (Time.current - now) * 1000,
24
- status: status,
25
- ).save
26
- end
27
- end
28
- end
29
-
30
- alias_method :invoke_without_new_rails_performance, :invoke
31
- alias_method :invoke, :invoke_with_rails_performance
32
-
33
- def invoke(*args)
34
- invoke_with_rails_performance(*args)
35
- end
36
- end
37
- end
38
-
39
- def self.find_task_name(*args)
40
- (ARGV + args).compact
41
- end
42
- end
43
- end
44
- end
1
+ module RailsPerformance
2
+ module Gems
3
+ class RakeExt
4
+ def self.init
5
+ ::Rake::Task.class_eval do
6
+ def invoke_with_rails_performance(*args)
7
+ now = Time.current
8
+ status = "success"
9
+ invoke_without_new_rails_performance(*args)
10
+ rescue Exception => ex # rubocop:disable Lint/RescueException
11
+ status = "error"
12
+ raise(ex)
13
+ ensure
14
+ if !RailsPerformance.skipable_rake_tasks.include?(name)
15
+ task_info = RailsPerformance::Gems::RakeExt.find_task_name(*args)
16
+ task_info = [name] if task_info.empty?
17
+ RailsPerformance::Models::RakeRecord.new(
18
+ task: task_info,
19
+ datetime: now.strftime(RailsPerformance::FORMAT),
20
+ datetimei: now.to_i,
21
+ duration: (Time.current - now) * 1000,
22
+ status: status
23
+ ).save
24
+ end
25
+ end
26
+
27
+ alias_method :invoke_without_new_rails_performance, :invoke
28
+ alias_method :invoke, :invoke_with_rails_performance
29
+
30
+ def invoke(*args) # rubocop:disable Lint/DuplicateMethods
31
+ invoke_with_rails_performance(*args)
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.find_task_name(*args)
37
+ (ARGV + args).compact
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,37 +1,34 @@
1
- module RailsPerformance
2
- module Gems
3
- class SidekiqExt
4
-
5
- def initialize(options=nil)
6
- end
7
-
8
- def call(worker, msg, queue)
9
- now = Time.current
10
- record = RailsPerformance::Models::SidekiqRecord.new(
11
- enqueued_ati: msg['enqueued_at'].to_i,
12
- datetimei: msg['created_at'].to_i,
13
- jid: msg['jid'],
14
- queue: queue,
15
- start_timei: now.to_i,
16
- datetime: now.strftime(RailsPerformance::FORMAT),
17
- worker: msg['wrapped'.freeze] || worker.class.to_s
18
- )
19
- begin
20
- result = yield
21
- record.status = "success"
22
- result
23
- rescue Exception => ex
24
- record.status = "exception"
25
- record.message = ex.message
26
- raise ex
27
- ensure
28
- # store in ms instead of seconds
29
- record.duration = (Time.current - now) * 1000
30
- record.save
31
- result
32
- end
33
- end
34
-
35
- end
36
- end
37
- end
1
+ module RailsPerformance
2
+ module Gems
3
+ class SidekiqExt
4
+ def initialize(options = nil)
5
+ end
6
+
7
+ def call(worker, msg, queue)
8
+ now = Time.current
9
+ record = RailsPerformance::Models::SidekiqRecord.new(
10
+ enqueued_ati: msg["enqueued_at"].to_i,
11
+ datetimei: msg["created_at"].to_i,
12
+ jid: msg["jid"],
13
+ queue: queue,
14
+ start_timei: now.to_i,
15
+ datetime: now.strftime(RailsPerformance::FORMAT),
16
+ worker: msg["wrapped".freeze] || worker.class.to_s
17
+ )
18
+ begin
19
+ result = yield
20
+ record.status = "success"
21
+ result
22
+ rescue Exception => ex # rubocop:disable Lint/RescueException
23
+ record.status = "exception"
24
+ record.message = ex.message
25
+ raise ex
26
+ ensure
27
+ # store in ms instead of seconds
28
+ record.duration = (Time.current - now) * 1000
29
+ record.save
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,50 +1,50 @@
1
- module RailsPerformance
2
- module Instrument
3
- class MetricsCollector
4
- # payload
5
- # {
6
- # controller: "PostsController",
7
- # action: "index",
8
- # params: {"action" => "index", "controller" => "posts"},
9
- # headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
10
- # format: :html,
11
- # method: "GET",
12
- # path: "/posts",
13
- # status: 200,
14
- # view_runtime: 46.848,
15
- # db_runtime: 0.157
16
- # }
17
-
18
- def call(event_name, started, finished, event_id, payload)
19
- return if RailsPerformance.skip
20
- return if CurrentRequest.current.data
21
-
22
- # TODO do we need this new?
23
- event = ActiveSupport::Notifications::Event.new(event_name, started, finished, event_id, payload)
24
-
25
- return if RailsPerformance.ignored_endpoints.include? "#{event.payload[:controller]}##{event.payload[:action]}"
26
- return if RailsPerformance.ignored_paths.any? { |p| event.payload[:path].start_with?(p) }
27
-
28
- record = {
29
- controller: event.payload[:controller],
30
- action: event.payload[:action],
31
- format: event.payload[:format],
32
- status: event.payload[:status],
33
- datetime: finished.strftime(RailsPerformance::FORMAT),
34
- datetimei: finished.to_i,
35
- method: event.payload[:method],
36
- path: event.payload[:path],
37
- view_runtime: event.payload[:view_runtime],
38
- db_runtime: event.payload[:db_runtime],
39
- duration: event.duration,
40
- exception: event.payload[:exception],
41
- exception_object: event.payload[:exception_object]
42
- }
43
-
44
- # pass the record to Thread.current
45
- # and saves later in middleware
46
- CurrentRequest.current.data = record
47
- end
48
- end
49
- end
50
- end
1
+ module RailsPerformance
2
+ module Instrument
3
+ class MetricsCollector
4
+ # payload
5
+ # {
6
+ # controller: "PostsController",
7
+ # action: "index",
8
+ # params: {"action" => "index", "controller" => "posts"},
9
+ # headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
10
+ # format: :html,
11
+ # method: "GET",
12
+ # path: "/posts",
13
+ # status: 200,
14
+ # view_runtime: 46.848,
15
+ # db_runtime: 0.157
16
+ # }
17
+
18
+ def call(event_name, started, finished, event_id, payload)
19
+ return if RailsPerformance.skip
20
+ return if CurrentRequest.current.data
21
+
22
+ # TODO do we need this new?
23
+ event = ActiveSupport::Notifications::Event.new(event_name, started, finished, event_id, payload)
24
+
25
+ return if RailsPerformance.ignored_endpoints.include? "#{event.payload[:controller]}##{event.payload[:action]}"
26
+ return if RailsPerformance.ignored_paths.any? { |p| event.payload[:path].start_with?(p) }
27
+
28
+ record = {
29
+ controller: event.payload[:controller],
30
+ action: event.payload[:action],
31
+ format: event.payload[:format],
32
+ status: event.payload[:status],
33
+ datetime: finished.strftime(RailsPerformance::FORMAT),
34
+ datetimei: finished.to_i,
35
+ method: event.payload[:method],
36
+ path: event.payload[:path],
37
+ view_runtime: event.payload[:view_runtime],
38
+ db_runtime: event.payload[:db_runtime],
39
+ duration: event.duration,
40
+ exception: event.payload[:exception],
41
+ exception_object: event.payload[:exception_object]
42
+ }
43
+
44
+ # pass the record to Thread.current
45
+ # and saves later in middleware
46
+ CurrentRequest.current.data = record
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,36 +1,33 @@
1
- module RailsPerformance
2
- module Models
3
- class BaseRecord
4
- def self.from_db(key, value)
5
- raise 'implement me'
6
- end
7
-
8
- def save
9
- raise 'implement me'
10
- end
11
-
12
- def record_hash
13
- raise 'implement me'
14
- end
15
-
16
- def value
17
- @value ||= JSON.parse(@json || "{}")
18
- end
19
-
20
- def duration
21
- value['duration']
22
- end
23
-
24
- private
25
-
26
- def ms(e)
27
- if e
28
- e.to_f.round(1).to_s + " ms"
29
- else
30
- nil
31
- end
32
- end
33
-
34
- end
35
- end
36
- end
1
+ module RailsPerformance
2
+ module Models
3
+ class BaseRecord
4
+ def self.from_db(key, value)
5
+ raise "implement me"
6
+ end
7
+
8
+ def save
9
+ raise "implement me"
10
+ end
11
+
12
+ def record_hash
13
+ raise "implement me"
14
+ end
15
+
16
+ def value
17
+ @value ||= JSON.parse(@json || "{}")
18
+ end
19
+
20
+ def duration
21
+ value["duration"]
22
+ end
23
+
24
+ private
25
+
26
+ def ms(e)
27
+ if e
28
+ e.to_f.round(1).to_s + " ms"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,36 +1,35 @@
1
- module RailsPerformance
2
- module Models
3
- class Collection
4
- attr_reader :data
5
-
6
- def initialize
7
- @data = []
8
- end
9
-
10
- def add(record)
11
- @data << record
12
- end
13
-
14
- def group_by(type)
15
- case type
16
- when :controller_action, :controller_action_format, :datetime, :path
17
- fetch_values @data.group_by(&type)
18
- else
19
- {}
20
- end
21
- end
22
-
23
- def fetch_values(groupped_collection)
24
- result = {}
25
- groupped_collection.each do |key, records|
26
- result[key] ||= []
27
- records.each do |record|
28
- result[key] << record.value
29
- end
30
- end
31
- result
32
- end
33
-
34
- end
35
- end
36
- end
1
+ module RailsPerformance
2
+ module Models
3
+ class Collection
4
+ attr_reader :data
5
+
6
+ def initialize
7
+ @data = []
8
+ end
9
+
10
+ def add(record)
11
+ @data << record
12
+ end
13
+
14
+ def group_by(type)
15
+ case type
16
+ when :controller_action, :controller_action_format, :datetime, :path
17
+ fetch_values @data.group_by(&type)
18
+ else
19
+ {}
20
+ end
21
+ end
22
+
23
+ def fetch_values(groupped_collection)
24
+ result = {}
25
+ groupped_collection.each do |key, records|
26
+ result[key] ||= []
27
+ records.each do |record|
28
+ result[key] << record.value
29
+ end
30
+ end
31
+ result
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,48 +1,47 @@
1
- module RailsPerformance
2
- module Models
3
- class CustomRecord < BaseRecord
4
- attr_accessor :tag_name, :namespace_name, :duration, :datetime, :datetimei, :status, :json
5
-
6
- def CustomRecord.from_db(key, value)
7
- items = key.split("|")
8
-
9
- CustomRecord.new(
10
- tag_name: items[2],
11
- namespace_name: items[4],
12
- datetime: items[6],
13
- datetimei: items[8],
14
- status: items[10],
15
- json: value
16
- )
17
- end
18
-
19
- def initialize(tag_name:, namespace_name: nil, duration: nil, datetime:, datetimei:, status:, json: '{}')
20
- @tag_name = tag_name
21
- @namespace_name = namespace_name
22
- @duration = duration
23
- @datetime = datetime
24
- @datetimei = datetimei.to_i
25
- @status = status
26
- @json = json
27
- end
28
-
29
- def record_hash
30
- {
31
- tag_name: self.tag_name,
32
- namespace_name: self.namespace_name,
33
- status: self.status,
34
- datetimei: datetimei,
35
- datetime: Time.at(self.datetimei.to_i),
36
- duration: self.value['duration'],
37
- }
38
- end
39
-
40
- def save
41
- key = "custom|tag_name|#{tag_name}|namespace_name|#{namespace_name}|datetime|#{datetime}|datetimei|#{datetimei}|status|#{status}|END|#{RailsPerformance::SCHEMA}"
42
- value = { duration: duration }
43
- Utils.save_to_redis(key, value)
44
- end
45
-
46
- end
47
- end
48
- end
1
+ module RailsPerformance
2
+ module Models
3
+ class CustomRecord < BaseRecord
4
+ attr_accessor :tag_name, :namespace_name, :duration, :datetime, :datetimei, :status, :json
5
+
6
+ def self.from_db(key, value)
7
+ items = key.split("|")
8
+
9
+ CustomRecord.new(
10
+ tag_name: items[2],
11
+ namespace_name: items[4],
12
+ datetime: items[6],
13
+ datetimei: items[8],
14
+ status: items[10],
15
+ json: value
16
+ )
17
+ end
18
+
19
+ def initialize(tag_name:, datetime:, datetimei:, status:, namespace_name: nil, duration: nil, json: "{}")
20
+ @tag_name = tag_name
21
+ @namespace_name = namespace_name
22
+ @duration = duration
23
+ @datetime = datetime
24
+ @datetimei = datetimei.to_i
25
+ @status = status
26
+ @json = json
27
+ end
28
+
29
+ def record_hash
30
+ {
31
+ tag_name: tag_name,
32
+ namespace_name: namespace_name,
33
+ status: status,
34
+ datetimei: datetimei,
35
+ datetime: Time.at(datetimei.to_i),
36
+ duration: value["duration"]
37
+ }
38
+ end
39
+
40
+ def save
41
+ key = "custom|tag_name|#{tag_name}|namespace_name|#{namespace_name}|datetime|#{datetime}|datetimei|#{datetimei}|status|#{status}|END|#{RailsPerformance::SCHEMA}"
42
+ value = {duration: duration}
43
+ Utils.save_to_redis(key, value)
44
+ end
45
+ end
46
+ end
47
+ end