rails_performance 0.9.5 → 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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +59 -9
  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/layouts/rails_performance.html.erb +2 -2
  7. data/app/views/rails_performance/rails_performance/_summary.html.erb +1 -1
  8. data/app/views/rails_performance/rails_performance/custom.html.erb +83 -0
  9. data/app/views/rails_performance/rails_performance/delayed_job.html.erb +74 -0
  10. data/app/views/rails_performance/rails_performance/grape.html.erb +64 -0
  11. data/app/views/rails_performance/rails_performance/rake.html.erb +55 -0
  12. data/app/views/rails_performance/rails_performance/recent.html.erb +3 -1
  13. data/app/views/rails_performance/rails_performance/requests.html.erb +1 -1
  14. data/app/views/rails_performance/rails_performance/{jobs.html.erb → sidekiq.html.erb} +5 -4
  15. data/app/views/rails_performance/rails_performance/summary.js.erb +1 -1
  16. data/app/views/rails_performance/rails_performance/trace.js.erb +1 -1
  17. data/app/views/rails_performance/shared/_header.html.erb +9 -1
  18. data/app/views/rails_performance/stylesheets/style.css +5 -0
  19. data/config/routes.rb +7 -3
  20. data/lib/generators/rails_performance/install/USAGE +8 -0
  21. data/lib/generators/rails_performance/install/install_generator.rb +8 -0
  22. data/lib/generators/rails_performance/install/templates/initializer.rb +23 -0
  23. data/lib/rails_performance.rb +40 -7
  24. data/lib/rails_performance/data_source.rb +52 -13
  25. data/lib/rails_performance/engine.rb +39 -18
  26. data/lib/rails_performance/extensions/{capture_everything.rb → trace.rb} +2 -2
  27. data/lib/rails_performance/gems/custom_ext.rb +33 -0
  28. data/lib/rails_performance/gems/delayed_job_ext.rb +54 -0
  29. data/lib/rails_performance/gems/grape_ext.rb +35 -0
  30. data/lib/rails_performance/gems/rake_ext.rb +40 -0
  31. data/lib/rails_performance/gems/{sidekiq.rb → sidekiq_ext.rb} +14 -12
  32. data/lib/rails_performance/instrument/metrics_collector.rb +5 -3
  33. data/lib/rails_performance/models/base_record.rb +12 -0
  34. data/lib/rails_performance/models/custom_record.rb +48 -0
  35. data/lib/rails_performance/models/delayed_job_record.rb +62 -0
  36. data/lib/rails_performance/models/grape_record.rb +61 -0
  37. data/lib/rails_performance/models/rake_record.rb +49 -0
  38. data/lib/rails_performance/models/request_record.rb +98 -0
  39. data/lib/rails_performance/models/sidekiq_record.rb +66 -0
  40. data/lib/rails_performance/models/trace_record.rb +19 -0
  41. data/lib/rails_performance/rails/middleware.rb +42 -16
  42. data/lib/rails_performance/rails/query_builder.rb +1 -1
  43. data/lib/rails_performance/reports/breakdown_report.rb +4 -16
  44. data/lib/rails_performance/reports/crash_report.rb +4 -15
  45. data/lib/rails_performance/reports/recent_requests_report.rb +7 -44
  46. data/lib/rails_performance/reports/trace_report.rb +1 -1
  47. data/lib/rails_performance/{models → thread}/current_request.rb +9 -4
  48. data/lib/rails_performance/utils.rb +15 -29
  49. data/lib/rails_performance/version.rb +1 -1
  50. metadata +96 -10
  51. data/lib/rails_performance/models/job_record.rb +0 -48
  52. data/lib/rails_performance/models/record.rb +0 -68
@@ -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
@@ -0,0 +1,49 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class RakeRecord < BaseRecord
4
+ attr_accessor :task, :duration, :datetime, :datetimei, :status
5
+
6
+ # rake|task|["task3"]|datetime|20210416T1254|datetimei|1618602843|status|error|END|1.0.0
7
+ # {"duration":0.00012442}
8
+ def RakeRecord.from_db(key, value)
9
+ items = key.split("|")
10
+
11
+ RakeRecord.new(
12
+ task: JSON.parse(items[2]),
13
+ datetime: items[4],
14
+ datetimei: items[6],
15
+ status: items[8],
16
+ json: value
17
+ )
18
+ end
19
+
20
+ def initialize(task:, duration: nil, datetime:, datetimei:, status:, json: '{}')
21
+ @task = Array.wrap(task)
22
+ @datetime = datetime
23
+ @datetimei = datetimei.to_i
24
+ @status = status
25
+ @duration = duration
26
+ @json = json
27
+
28
+ @duration ||= value['duration']
29
+ end
30
+
31
+ def record_hash
32
+ {
33
+ task: task,
34
+ datetime: Time.at(datetimei),
35
+ datetimei: datetimei,
36
+ duration: duration,
37
+ status: status,
38
+ }
39
+ end
40
+
41
+ def save
42
+ key = "rake|task|#{task.to_json}|datetime|#{datetime}|datetimei|#{datetimei}|status|#{status}|END|#{RailsPerformance::VERSION}"
43
+ value = { duration: duration }
44
+ Utils.save_to_redis(key, value)
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,98 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class RequestRecord < BaseRecord
4
+ attr_accessor :controller, :action, :format, :status, :datetime, :datetimei, :method, :path, :request_id, :json
5
+ attr_accessor :view_runtime, :db_runtime, :duration, :http_referer
6
+
7
+ def RequestRecord.find_by(request_id:)
8
+ keys, values = RP::Utils.fetch_from_redis("performance|*|request_id|#{request_id}|*")
9
+
10
+ return nil if keys.blank?
11
+ return nil if values.blank?
12
+
13
+ RP::Models::RequestRecord.from_db(keys[0], values[0])
14
+ end
15
+
16
+ # key = performance|
17
+ # controller|HomeController|
18
+ # action|index|
19
+ # format|html|
20
+ # status|200|
21
+ # datetime|20200124T0523|
22
+ # datetimei|1579861423|
23
+ # method|GET|
24
+ # path|/|
25
+ # request_id|454545454545454545|
26
+ # END|1.0.0
27
+ # = {"view_runtime":8.444603008683771,"db_runtime":0,"duration":9.216095000000001}
28
+ # value = JSON
29
+ def RequestRecord.from_db(key, value)
30
+ items = key.split("|")
31
+
32
+ RequestRecord.new(
33
+ controller: items[2],
34
+ action: items[4],
35
+ format: items[6],
36
+ status: items[8],
37
+ datetime: items[10],
38
+ datetimei: items[12],
39
+ method: items[14],
40
+ path: items[16],
41
+ request_id: items[18],
42
+ json: value
43
+ )
44
+ end
45
+
46
+ def initialize(controller:, action:, format:, status:, datetime:, datetimei:, method:, path:, request_id:, view_runtime: nil, db_runtime: nil, duration: nil, http_referer: nil, json: '{}')
47
+ @controller = controller
48
+ @action = action
49
+ @format = format
50
+ @status = status
51
+ @datetime = datetime
52
+ @datetimei = datetimei.to_i
53
+ @method = method
54
+ @path = path
55
+ @request_id = request_id
56
+
57
+ @view_runtime = view_runtime
58
+ @db_runtime = db_runtime
59
+ @duration = duration
60
+ @http_referer = http_referer
61
+
62
+ @json = json
63
+ end
64
+
65
+ def controller_action
66
+ "#{controller}##{action}"
67
+ end
68
+
69
+ def controller_action_format
70
+ "#{controller}##{action}|#{format}"
71
+ end
72
+
73
+ def record_hash
74
+ {
75
+ controller: self.controller,
76
+ action: self.action,
77
+ format: self.format,
78
+ status: self.status,
79
+ method: self.method,
80
+ path: self.path,
81
+ request_id: self.request_id,
82
+ datetime: Time.at(self.datetimei.to_i),
83
+ datetimei: datetimei,
84
+ duration: self.value['duration'],
85
+ db_runtime: self.value['db_runtime'],
86
+ view_runtime: self.value['view_runtime'],
87
+ }
88
+ end
89
+
90
+ def save
91
+ value = { view_runtime: view_runtime, db_runtime: db_runtime, duration: duration, http_referer: http_referer }
92
+ key = "performance|controller|#{controller}|action|#{action}|format|#{format}|status|#{status}|datetime|#{datetime}|datetimei|#{datetimei}|method|#{method}|path|#{path}|request_id|#{request_id}|END|#{RailsPerformance::VERSION}"
93
+ Utils.save_to_redis(key, value)
94
+ end
95
+
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,66 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class SidekiqRecord < BaseRecord
4
+ attr_accessor :queue, :worker, :jid, :datetimei, :enqueued_ati, :datetime, :start_timei, :status, :duration, :message
5
+
6
+ # key = job-performance
7
+ # |queue|default
8
+ # |worker|SimpleWorker
9
+ # |jid|7d48fbf20976c224510dbc60
10
+ # |datetime|20200124T0523
11
+ # |datetimei|1583146613
12
+ # |enqueued_ati|1583146613
13
+ # |start_timei|1583146614
14
+ # |status|success|END|1.0.0
15
+ # value = JSON
16
+ def SidekiqRecord.from_db(key, value)
17
+ items = key.split("|")
18
+
19
+ SidekiqRecord.new(
20
+ queue: items[2],
21
+ worker: items[4],
22
+ jid: items[6],
23
+ datetime: items[8],
24
+ datetimei: items[10],
25
+ enqueued_ati: items[12],
26
+ start_timei: items[14],
27
+ status: items[16],
28
+ json: value
29
+ )
30
+ end
31
+
32
+ def initialize(queue:, worker:, jid:, datetime:, datetimei:, enqueued_ati:, start_timei:, status: nil, duration: nil, json: "{}")
33
+ @queue = queue
34
+ @worker = worker
35
+ @jid = jid
36
+ @datetime = datetime
37
+ @datetimei = datetimei.to_i
38
+ @enqueued_ati = enqueued_ati
39
+ @start_timei = start_timei
40
+ @status = status
41
+ @duration = duration
42
+ @json = json
43
+ end
44
+
45
+ def record_hash
46
+ {
47
+ worker: self.worker,
48
+ queue: self.queue,
49
+ jid: self.jid,
50
+ status: self.status,
51
+ datetimei: datetimei,
52
+ datetime: Time.at(self.start_timei.to_i),
53
+ duration: self.value['duration'],
54
+ message: value['message']
55
+ }
56
+ end
57
+
58
+ def save
59
+ key = "sidekiq|queue|#{queue}|worker|#{worker}|jid|#{jid}|datetime|#{datetime}|datetimei|#{datetimei}|enqueued_ati|#{enqueued_ati}|start_timei|#{start_timei}|status|#{status}|END|#{RailsPerformance::VERSION}"
60
+ value = { message: message, duration: duration }
61
+ Utils.save_to_redis(key, value)
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,19 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class TraceRecord < BaseRecord
4
+ attr_accessor :request_id, :value
5
+
6
+ def initialize(request_id:, value:)
7
+ @request_id = request_id
8
+ @value = value
9
+ end
10
+
11
+ def save
12
+ return if value.empty?
13
+
14
+ Utils.save_to_redis("trace|#{request_id}|END|#{RailsPerformance::VERSION}", value, RailsPerformance::Reports::RecentRequestsReport::TIME_WINDOW.to_i)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,34 @@
1
1
  module RailsPerformance
2
2
  module Rails
3
+ class MiddlewareTraceStorerAndCleanup
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ dup.call!(env)
10
+ end
11
+
12
+ def call!(env)
13
+ if %r{#{RailsPerformance.mount_at}}.match?(env["PATH_INFO"])
14
+ RailsPerformance.skip = true
15
+ end
16
+
17
+ @status, @headers, @response = @app.call(env)
18
+
19
+ if !RailsPerformance.skip
20
+ RailsPerformance::Models::TraceRecord.new(
21
+ request_id: CurrentRequest.current.request_id,
22
+ value: CurrentRequest.current.tracings
23
+ ).save
24
+ end
25
+
26
+ CurrentRequest.cleanup
27
+
28
+ [@status, @headers, @response]
29
+ end
30
+ end
31
+
3
32
  class Middleware
4
33
  def initialize(app)
5
34
  @app = app
@@ -13,24 +42,21 @@ module RailsPerformance
13
42
  @status, @headers, @response = @app.call(env)
14
43
 
15
44
  #t = Time.now
16
- if record = CurrentRequest.current.record
17
- begin
18
- record[:status] ||= @status # for 500 errors
19
- record[:request_id] = CurrentRequest.current.request_id
20
-
21
- # capture referer from where this page was opened
22
- if record[:status] == 404
23
- record[:HTTP_REFERER] = env["HTTP_REFERER"]
24
- end
45
+ if !RailsPerformance.skip
46
+ if !CurrentRequest.current.ignore.include?(:performance) # grape is executed first, and than ignore regular future storage of "controller"-like request
47
+ if data = CurrentRequest.current.data
48
+ record = RailsPerformance::Models::RequestRecord.new(**data.merge({request_id: CurrentRequest.current.request_id}))
25
49
 
26
- # store for section "recent requests"
27
- RP::Utils.log_trace_in_redis(CurrentRequest.current.request_id, CurrentRequest.current.storage)
50
+ # for 500 errors
51
+ record.status ||= @status
28
52
 
29
- # store request information
30
- RP::Utils.log_request_in_redis(record)
31
- ensure
32
- # we don't want to have a memory leak
33
- CurrentRequest.cleanup
53
+ # capture referer from where this page was opened
54
+ record.http_referer = env["HTTP_REFERER"] if record.status == 404
55
+
56
+ # store for section "recent requests"
57
+ # store request information (regular rails request)
58
+ record.save
59
+ end
34
60
  end
35
61
  end
36
62
  #puts "==> store performance data: #{(Time.now - t).round(3)}ms"