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,20 +1,27 @@
1
1
  module RailsPerformance
2
2
  class DataSource
3
+ KLASSES = {
4
+ requests: RailsPerformance::Models::RequestRecord,
5
+ sidekiq: RailsPerformance::Models::SidekiqRecord,
6
+ delayed_job: RailsPerformance::Models::DelayedJobRecord,
7
+ grape: RailsPerformance::Models::GrapeRecord,
8
+ rake: RailsPerformance::Models::RakeRecord,
9
+ custom: RailsPerformance::Models::CustomRecord,
10
+ }
11
+
3
12
  attr_reader :q, :klass, :type
4
13
 
5
- def initialize(q: {}, type:, klass:)
6
- @klass = klass
14
+ def initialize(q: {}, type:)
7
15
  @type = type
16
+ @klass = KLASSES[type]
8
17
  q[:on] ||= Date.today
9
18
  @q = q
10
-
11
- #puts " [DataSource Q] --> #{@q.inspect}\n\n"
12
19
  end
13
20
 
14
21
  def db
15
22
  result = RP::Models::Collection.new
16
23
  (RP::Utils.days + 1).times do |e|
17
- RP::DataSource.new(q: self.q.merge({ on: e.days.ago.to_date }), klass: klass, type: type).add_to(result)
24
+ RP::DataSource.new(q: self.q.merge({ on: e.days.ago.to_date }), type: type).add_to(result)
18
25
  end
19
26
  result
20
27
  end
@@ -36,7 +43,7 @@ module RailsPerformance
36
43
  return [] if keys.blank?
37
44
 
38
45
  keys.each_with_index do |key, index|
39
- yield klass.new(key, values[index])
46
+ yield klass.from_db(key, values[index])
40
47
  end
41
48
  end
42
49
 
@@ -45,9 +52,17 @@ module RailsPerformance
45
52
  def query
46
53
  case type
47
54
  when :requests
48
- "performance|*#{compile_requests_query}*|END"
49
- when :jobs
50
- "jobs|*#{compile_jobs_query}*|END"
55
+ "performance|*#{compile_requests_query}*|END|#{RailsPerformance::VERSION}"
56
+ when :sidekiq
57
+ "sidekiq|*#{compile_sidekiq_query}*|END|#{RailsPerformance::VERSION}"
58
+ when :delayed_job
59
+ "delayed_job|*#{compile_delayed_job_query}*|END|#{RailsPerformance::VERSION}"
60
+ when :grape
61
+ "grape|*#{compile_grape_query}*|END|#{RailsPerformance::VERSION}"
62
+ when :rake
63
+ "rake|*#{compile_rake_query}*|END|#{RailsPerformance::VERSION}"
64
+ when :custom
65
+ "custom|*#{compile_custom_query}*|END|#{RailsPerformance::VERSION}"
51
66
  else
52
67
  raise "wrong type for datasource query builder"
53
68
  end
@@ -55,7 +70,6 @@ module RailsPerformance
55
70
 
56
71
  def compile_requests_query
57
72
  str = []
58
-
59
73
  str << "controller|#{q[:controller]}|" if q[:controller].present?
60
74
  str << "action|#{q[:action]}|" if q[:action].present?
61
75
  str << "format|#{q[:format]}|" if q[:format].present?
@@ -63,18 +77,43 @@ module RailsPerformance
63
77
  str << "datetime|#{q[:on].strftime('%Y%m%d')}*|" if q[:on].present?
64
78
  str << "method|#{q[:method]}|" if q[:method].present?
65
79
  str << "path|#{q[:path]}|" if q[:path].present?
66
-
67
80
  str.join("*")
68
81
  end
69
82
 
70
- def compile_jobs_query
83
+ def compile_sidekiq_query
71
84
  str = []
72
-
73
85
  str << "queue|#{q[:queue]}|" if q[:queue].present?
74
86
  str << "worker|#{q[:worker]}|" if q[:worker].present?
75
87
  str << "datetime|#{q[:on].strftime('%Y%m%d')}*|" if q[:on].present?
76
88
  str << "status|#{q[:status]}|" if q[:status].present?
89
+ str.join("*")
90
+ end
91
+
92
+ def compile_delayed_job_query
93
+ str = []
94
+ str << "datetime|#{q[:on].strftime('%Y%m%d')}*|" if q[:on].present?
95
+ str << "status|#{q[:status]}|" if q[:status].present?
96
+ str.join("*")
97
+ end
98
+
99
+ def compile_rake_query
100
+ str = []
101
+ str << "datetime|#{q[:on].strftime('%Y%m%d')}*|" if q[:on].present?
102
+ str << "status|#{q[:status]}|" if q[:status].present?
103
+ str.join("*")
104
+ end
105
+
106
+ def compile_custom_query
107
+ str = []
108
+ str << "datetime|#{q[:on].strftime('%Y%m%d')}*|" if q[:on].present?
109
+ str << "status|#{q[:status]}|" if q[:status].present?
110
+ str.join("*")
111
+ end
77
112
 
113
+ def compile_grape_query
114
+ str = []
115
+ str << "datetime|#{q[:on].strftime('%Y%m%d')}*|" if q[:on].present?
116
+ str << "status|#{q[:status]}|" if q[:status].present?
78
117
  str.join("*")
79
118
  end
80
119
 
@@ -1,3 +1,4 @@
1
+ require 'action_view/log_subscriber'
1
2
  require_relative './rails/middleware.rb'
2
3
  require_relative './models/collection.rb'
3
4
  require_relative './instrument/metrics_collector.rb'
@@ -6,36 +7,56 @@ module RailsPerformance
6
7
  class Engine < ::Rails::Engine
7
8
  isolate_namespace RailsPerformance
8
9
 
9
- if RailsPerformance.try(:enabled) # for rails c
10
+ initializer "rails_performance.middleware" do |app|
11
+ next unless RailsPerformance.enabled
10
12
 
11
13
  if ::Rails::VERSION::MAJOR.to_i >= 5
12
- config.app_middleware.insert_after ActionDispatch::Executor, RailsPerformance::Rails::Middleware
14
+ app.middleware.insert_after ActionDispatch::Executor, RailsPerformance::Rails::Middleware
13
15
  else
14
- config.app_middleware.insert_after ActionDispatch::Static, RailsPerformance::Rails::Middleware
16
+ app.middleware.insert_after ActionDispatch::Static, RailsPerformance::Rails::Middleware
15
17
  end
18
+ # look like it works in reverse order?
19
+ app.middleware.insert_before RailsPerformance::Rails::Middleware, RailsPerformance::Rails::MiddlewareTraceStorerAndCleanup
16
20
 
17
- initializer :configure_metrics, after: :initialize_logger do
18
- ActiveSupport::Notifications.subscribe(
19
- "process_action.action_controller",
20
- RailsPerformance::Instrument::MetricsCollector.new
21
- )
22
-
23
- config.after_initialize do |app|
24
- ActionView::LogSubscriber.send :prepend, RailsPerformance::Extensions::View
25
- ActiveRecord::LogSubscriber.send :prepend, RailsPerformance::Extensions::Db
26
- end
27
- end
28
-
29
- if const_defined?("Sidekiq")
30
- require_relative './gems/sidekiq.rb'
21
+ if defined?(::Sidekiq)
22
+ require_relative './gems/sidekiq_ext.rb'
31
23
  Sidekiq.configure_server do |config|
32
24
  config.server_middleware do |chain|
33
- chain.add RailsPerformance::Gems::Sidekiq
25
+ chain.add RailsPerformance::Gems::SidekiqExt
34
26
  end
35
27
  end
36
28
  end
37
29
 
30
+ if defined?(::Grape)
31
+ require_relative './gems/grape_ext.rb'
32
+ RailsPerformance::Gems::GrapeExt.init
33
+ end
34
+
35
+ if defined?(::Delayed::Job)
36
+ require_relative './gems/delayed_job_ext.rb'
37
+ RailsPerformance::Gems::DelayedJobExt.init
38
+ end
39
+ end
40
+
41
+ initializer :configure_metrics, after: :initialize_logger do
42
+ next unless RailsPerformance.enabled
43
+
44
+ ActiveSupport::Notifications.subscribe(
45
+ "process_action.action_controller",
46
+ RailsPerformance::Instrument::MetricsCollector.new
47
+ )
38
48
  end
39
49
 
50
+ config.after_initialize do
51
+ next unless RailsPerformance.enabled
52
+
53
+ ActionView::LogSubscriber.send :prepend, RailsPerformance::Extensions::View
54
+ ActiveRecord::LogSubscriber.send :prepend, RailsPerformance::Extensions::Db
55
+ end
56
+
57
+ if defined?(::Rake::Task)
58
+ require_relative './gems/rake_ext.rb'
59
+ RailsPerformance::Gems::RakeExt.init
60
+ end
40
61
  end
41
62
  end
@@ -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,32 +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
26
+ raise ex
25
27
  ensure
26
28
  # store in ms instead of seconds
27
- data[:duration] = (Time.now - now) * 1000
28
- #puts data
29
- RailsPerformance::Utils.log_job_in_redis(data)
29
+ record.duration = (Time.now - now) * 1000
30
+ record.save
31
+ result
30
32
  end
31
33
  end
32
34
 
@@ -16,9 +16,11 @@ 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 event.payload[:path] =~ /^\/rails\/performance/
23
+ return if RailsPerformance.ignored_endpoints.include? "#{event.payload[:controller]}##{event.payload[:action]}"
22
24
 
23
25
  record = {
24
26
  controller: event.payload[:controller],
@@ -34,8 +36,8 @@ module RailsPerformance
34
36
  duration: event.duration
35
37
  }
36
38
 
37
- CurrentRequest.current.record = record
39
+ CurrentRequest.current.data = record
38
40
  end
39
41
  end
40
42
  end
41
- end
43
+ end