rails_performance 0.9.9 → 1.0.0.beta1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -3
  3. data/app/controllers/rails_performance/rails_performance_controller.rb +47 -35
  4. data/app/helpers/rails_performance/application_helper.rb +25 -7
  5. data/app/views/rails_performance/javascripts/app.js +2 -2
  6. data/app/views/rails_performance/rails_performance/_summary.html.erb +1 -1
  7. data/app/views/rails_performance/rails_performance/custom.html.erb +83 -0
  8. data/app/views/rails_performance/rails_performance/delayed_job.html.erb +74 -0
  9. data/app/views/rails_performance/rails_performance/grape.html.erb +64 -0
  10. data/app/views/rails_performance/rails_performance/rake.html.erb +55 -0
  11. data/app/views/rails_performance/rails_performance/recent.html.erb +3 -1
  12. data/app/views/rails_performance/rails_performance/{jobs.html.erb → sidekiq.html.erb} +5 -4
  13. data/app/views/rails_performance/rails_performance/summary.js.erb +1 -1
  14. data/app/views/rails_performance/rails_performance/trace.js.erb +1 -1
  15. data/app/views/rails_performance/shared/_header.html.erb +9 -1
  16. data/app/views/rails_performance/stylesheets/style.css +5 -0
  17. data/config/routes.rb +5 -1
  18. data/lib/rails_performance.rb +29 -6
  19. data/lib/rails_performance/data_source.rb +52 -13
  20. data/lib/rails_performance/engine.rb +20 -3
  21. data/lib/rails_performance/extensions/{capture_everything.rb → trace.rb} +2 -2
  22. data/lib/rails_performance/gems/custom_ext.rb +33 -0
  23. data/lib/rails_performance/gems/delayed_job_ext.rb +54 -0
  24. data/lib/rails_performance/gems/grape_ext.rb +35 -0
  25. data/lib/rails_performance/gems/rake_ext.rb +40 -0
  26. data/lib/rails_performance/gems/{sidekiq.rb → sidekiq_ext.rb} +13 -12
  27. data/lib/rails_performance/instrument/metrics_collector.rb +3 -2
  28. data/lib/rails_performance/models/base_record.rb +12 -0
  29. data/lib/rails_performance/models/custom_record.rb +48 -0
  30. data/lib/rails_performance/models/delayed_job_record.rb +62 -0
  31. data/lib/rails_performance/models/grape_record.rb +61 -0
  32. data/lib/rails_performance/models/rake_record.rb +49 -0
  33. data/lib/rails_performance/models/request_record.rb +98 -0
  34. data/lib/rails_performance/models/sidekiq_record.rb +66 -0
  35. data/lib/rails_performance/models/trace_record.rb +19 -0
  36. data/lib/rails_performance/rails/middleware.rb +42 -16
  37. data/lib/rails_performance/rails/query_builder.rb +1 -1
  38. data/lib/rails_performance/reports/breakdown_report.rb +4 -16
  39. data/lib/rails_performance/reports/crash_report.rb +4 -15
  40. data/lib/rails_performance/reports/recent_requests_report.rb +7 -44
  41. data/lib/rails_performance/reports/trace_report.rb +1 -1
  42. data/lib/rails_performance/{models → thread}/current_request.rb +9 -4
  43. data/lib/rails_performance/utils.rb +15 -28
  44. data/lib/rails_performance/version.rb +1 -1
  45. metadata +79 -10
  46. data/lib/rails_performance/models/job_record.rb +0 -48
  47. data/lib/rails_performance/models/record.rb +0 -68
@@ -3,7 +3,7 @@ module RailsPerformance
3
3
  module View
4
4
 
5
5
  def info(&block)
6
- CurrentRequest.current.store({
6
+ CurrentRequest.current.trace({
7
7
  group: :view,
8
8
  message: block.call
9
9
  })
@@ -19,7 +19,7 @@ module RailsPerformance
19
19
  module Db
20
20
 
21
21
  def sql(event)
22
- CurrentRequest.current.store({
22
+ CurrentRequest.current.trace({
23
23
  group: :db,
24
24
  duration: event.duration.round(2),
25
25
  sql: event.payload[:sql]
@@ -0,0 +1,33 @@
1
+ module RailsPerformance
2
+ module Gems
3
+ module CustomExtension
4
+ extend self
5
+
6
+ def measure(tag_name, namespace_name = nil)
7
+ return yield unless RailsPerformance.enabled
8
+
9
+ begin
10
+ now = Time.now
11
+ status = 'success'
12
+ result = yield
13
+ result
14
+ rescue Exception => ex
15
+ status = 'error'
16
+ raise(ex)
17
+ ensure
18
+ RailsPerformance::Models::CustomRecord.new(
19
+ tag_name: tag_name,
20
+ namespace_name: namespace_name,
21
+ status: status,
22
+ duration: (Time.now - now) * 1000,
23
+ datetime: now.strftime(RailsPerformance::FORMAT),
24
+ datetimei: now.to_i,
25
+ ).save
26
+
27
+ result
28
+ end
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,54 @@
1
+ module RailsPerformance
2
+ module Gems
3
+ class DelayedJobExt
4
+
5
+ class Plugin < ::Delayed::Plugin
6
+ callbacks do |lifecycle|
7
+ lifecycle.around(:invoke_job) do |job, *args, &block|
8
+ begin
9
+ now = Time.now
10
+ block.call(job, *args)
11
+ status = 'success'
12
+ rescue Exception => error
13
+ status = 'error'
14
+ raise error
15
+ ensure
16
+ meta_data = RailsPerformance::Gems::DelayedJobExt::Plugin.meta(job.payload_object)
17
+ record = RailsPerformance::Models::DelayedJobRecord.new(
18
+ jid: job.id,
19
+ duration: (Time.now - now) * 1000,
20
+ datetime: now.strftime(RailsPerformance::FORMAT),
21
+ datetimei: now.to_i,
22
+ source_type: meta_data[0],
23
+ class_name: meta_data[1],
24
+ method_name: meta_data[2],
25
+ status: status
26
+ )
27
+ record.save
28
+ end
29
+ end
30
+ end
31
+
32
+ # [source_type, class_name, method_name, duration]
33
+ def self.meta(payload_object)
34
+ if payload_object.is_a?(::Delayed::PerformableMethod)
35
+ if payload_object.object.is_a?(Module)
36
+ [:class_method, payload_object.object.name, payload_object.method_name.to_s]
37
+ else
38
+ [:instance_method, payload_object.object.class.name, payload_object.method_name.to_s]
39
+ end
40
+ else
41
+ [:instance_method, payload_object.class.name, "perform"]
42
+ end
43
+ rescue
44
+ [:unknown, :unknown, :unknown]
45
+ end
46
+ end
47
+
48
+ def self.init
49
+ ::Delayed::Worker.plugins += [::RailsPerformance::Gems::DelayedJobExt::Plugin]
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
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.now
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
@@ -0,0 +1,40 @@
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.now
10
+ status = 'success'
11
+ invoke_without_new_rails_performance(*args)
12
+ rescue Exception => ex
13
+ status = 'error'
14
+ raise(ex)
15
+ ensure
16
+ RailsPerformance::Models::RakeRecord.new(
17
+ task: RailsPerformance::Gems::RakeExt.find_task_name(*args),
18
+ datetime: now.strftime(RailsPerformance::FORMAT),
19
+ datetimei: now.to_i,
20
+ duration: (Time.now - now) * 1000,
21
+ status: status,
22
+ ).save
23
+ end
24
+ end
25
+
26
+ alias_method :invoke_without_new_rails_performance, :invoke
27
+ alias_method :invoke, :invoke_with_rails_performance
28
+
29
+ def invoke(*args)
30
+ invoke_with_rails_performance(*args)
31
+ end
32
+ end
33
+ end
34
+
35
+ def self.find_task_name(*args)
36
+ (ARGV + args).compact
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,33 +1,34 @@
1
1
  module RailsPerformance
2
2
  module Gems
3
- class Sidekiq
3
+ class SidekiqExt
4
4
 
5
5
  def initialize(options=nil)
6
6
  end
7
7
 
8
8
  def call(worker, msg, queue)
9
- now = Time.now
10
- data = {
9
+ now = Time.now
10
+ record = RP::Models::SidekiqRecord.new(
11
11
  enqueued_ati: msg['enqueued_at'].to_i,
12
- created_ati: msg['created_at'].to_i,
12
+ datetimei: msg['created_at'].to_i,
13
13
  jid: msg['jid'],
14
14
  queue: queue,
15
15
  start_timei: now.to_i,
16
16
  datetime: now.strftime(RailsPerformance::FORMAT),
17
17
  worker: msg['wrapped'.freeze] || worker.class.to_s
18
- }
18
+ )
19
19
  begin
20
- yield
21
- data[:status] = "success"
20
+ result = yield
21
+ record.status = "success"
22
+ result
22
23
  rescue Exception => ex
23
- data[:status] = "exception"
24
- data[:message] = ex.message
24
+ record.status = "exception"
25
+ record.message = ex.message
25
26
  raise ex
26
27
  ensure
27
28
  # store in ms instead of seconds
28
- data[:duration] = (Time.now - now) * 1000
29
- #puts data
30
- RailsPerformance::Utils.log_job_in_redis(data)
29
+ record.duration = (Time.now - now) * 1000
30
+ record.save
31
+ result
31
32
  end
32
33
  end
33
34
 
@@ -16,9 +16,10 @@ module RailsPerformance
16
16
  # }
17
17
 
18
18
  def call(event_name, started, finished, event_id, payload)
19
+ return if RailsPerformance.skip
20
+ # TODO do we need this new?
19
21
  event = ActiveSupport::Notifications::Event.new(event_name, started, finished, event_id, payload)
20
22
 
21
- return if %r{#{RailsPerformance.mount_at}}.match? event.payload[:path]
22
23
  return if RailsPerformance.ignored_endpoints.include? "#{event.payload[:controller]}##{event.payload[:action]}"
23
24
 
24
25
  record = {
@@ -35,7 +36,7 @@ module RailsPerformance
35
36
  duration: event.duration
36
37
  }
37
38
 
38
- CurrentRequest.current.record = record
39
+ CurrentRequest.current.data = record
39
40
  end
40
41
  end
41
42
  end
@@ -1,6 +1,18 @@
1
1
  module RailsPerformance
2
2
  module Models
3
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
+
4
16
  def value
5
17
  @value ||= JSON.parse(@json || "{}")
6
18
  end
@@ -0,0 +1,48 @@
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::VERSION}"
42
+ value = { duration: duration }
43
+ Utils.save_to_redis(key, value)
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,62 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class DelayedJobRecord < BaseRecord
4
+ attr_accessor :jid, :duration, :datetime, :datetimei, :source_type, :class_name, :method_name, :status, :json
5
+
6
+ # delayed_job
7
+ #|jid|22
8
+ #|datetime|20210415T0616
9
+ #|datetimei|1618492591
10
+ #|source_type|instance_method
11
+ #|class_name|User
12
+ #|method_name|say_hello_without_delay
13
+ #|status|success|END|1.0.0
14
+ def DelayedJobRecord.from_db(key, value)
15
+ items = key.split("|")
16
+
17
+ DelayedJobRecord.new(
18
+ jid: items[2],
19
+ datetime: items[4],
20
+ datetimei: items[6],
21
+ source_type: items[8],
22
+ class_name: items[10],
23
+ method_name: items[12],
24
+ status: items[14],
25
+ json: value
26
+ )
27
+ end
28
+
29
+ def initialize(jid:, duration: nil, datetime:, datetimei:, source_type:, class_name:, method_name:, status:, json: '{}')
30
+ @jid = jid
31
+ @duration = duration
32
+ @datetime = datetime
33
+ @datetimei = datetimei.to_i
34
+ @source_type = source_type
35
+ @class_name = class_name
36
+ @method_name = method_name
37
+ @status = status
38
+ @json = json
39
+ end
40
+
41
+ def record_hash
42
+ {
43
+ jid: jid,
44
+ datetime: Time.at(datetimei),
45
+ datetimei: datetimei,
46
+ duration: value['duration'],
47
+ status: status,
48
+ source_type: source_type,
49
+ class_name: class_name,
50
+ method_name: method_name,
51
+ }
52
+ end
53
+
54
+ def save
55
+ key = "delayed_job|jid|#{jid}|datetime|#{datetime}|datetimei|#{datetimei}|source_type|#{source_type}|class_name|#{class_name}|method_name|#{method_name}|status|#{status}|END|#{RailsPerformance::VERSION}"
56
+ value = { duration: duration }
57
+ Utils.save_to_redis(key, value)
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,61 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class GrapeRecord < BaseRecord
4
+ attr_accessor :datetime, :datetimei, :format, :status, :path, :method, :request_id, :json
5
+ attr_accessor :endpoint_render_grape, :endpoint_run_grape, :format_response_grape
6
+
7
+ # key = grape|datetime|20210409T1115|datetimei|1617992134|format|json|path|/api/users|status|200|method|GET|request_id|1122|END|1.0.0
8
+ # value = {"endpoint_render.grape"=>0.000643989, "endpoint_run.grape"=>0.002000907, "format_response.grape"=>0.0348967}
9
+ def GrapeRecord.from_db(key, value)
10
+ items = key.split("|")
11
+
12
+ GrapeRecord.new(
13
+ datetime: items[2],
14
+ datetimei: items[4],
15
+ format: items[6],
16
+ path: items[8],
17
+ status: items[10],
18
+ method: items[12],
19
+ request_id: items[14],
20
+ json: value
21
+ )
22
+ end
23
+
24
+ def initialize(datetime: nil, datetimei: nil, format: nil, path: nil, status: nil, method: nil, request_id:, endpoint_render_grape: nil, endpoint_run_grape: nil, format_response_grape: nil, json: '{}')
25
+ @datetime = datetime
26
+ @datetimei = datetimei.to_i unless datetimei.nil?
27
+ @format = format
28
+ @path = path
29
+ @status = status
30
+ @method = method
31
+ @request_id = request_id
32
+
33
+ @endpoint_render_grape = endpoint_render_grape
34
+ @endpoint_run_grape = endpoint_run_grape
35
+ @format_response_grape = format_response_grape
36
+
37
+ @json = json
38
+ end
39
+
40
+ def record_hash
41
+ {
42
+ format: self.format,
43
+ status: self.status,
44
+ method: self.method,
45
+ path: self.path,
46
+ datetime: Time.at(self.datetimei.to_i),
47
+ datetimei: datetimei.to_i,
48
+ request_id: self.request_id,
49
+ }.merge(self.value)
50
+ end
51
+
52
+ def save
53
+ key = "grape|datetime|#{datetime}|datetimei|#{datetimei}|format|#{format}|path|#{path}|status|#{status}|method|#{method}|request_id|#{request_id}|END|#{RailsPerformance::VERSION}"
54
+ value = { "endpoint_render.grape" => endpoint_render_grape, "endpoint_run.grape" => endpoint_run_grape, "format_response.grape" => format_response_grape }
55
+
56
+ Utils.save_to_redis(key, value)
57
+ end
58
+
59
+ end
60
+ end
61
+ end