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.
- checksums.yaml +4 -4
- data/README.md +59 -9
- data/app/controllers/rails_performance/rails_performance_controller.rb +47 -35
- data/app/helpers/rails_performance/application_helper.rb +25 -7
- data/app/views/rails_performance/javascripts/app.js +2 -2
- data/app/views/rails_performance/layouts/rails_performance.html.erb +2 -2
- data/app/views/rails_performance/rails_performance/_summary.html.erb +1 -1
- data/app/views/rails_performance/rails_performance/custom.html.erb +83 -0
- data/app/views/rails_performance/rails_performance/delayed_job.html.erb +74 -0
- data/app/views/rails_performance/rails_performance/grape.html.erb +64 -0
- data/app/views/rails_performance/rails_performance/rake.html.erb +55 -0
- data/app/views/rails_performance/rails_performance/recent.html.erb +3 -1
- data/app/views/rails_performance/rails_performance/requests.html.erb +1 -1
- data/app/views/rails_performance/rails_performance/{jobs.html.erb → sidekiq.html.erb} +5 -4
- data/app/views/rails_performance/rails_performance/summary.js.erb +1 -1
- data/app/views/rails_performance/rails_performance/trace.js.erb +1 -1
- data/app/views/rails_performance/shared/_header.html.erb +9 -1
- data/app/views/rails_performance/stylesheets/style.css +5 -0
- data/config/routes.rb +7 -3
- data/lib/generators/rails_performance/install/USAGE +8 -0
- data/lib/generators/rails_performance/install/install_generator.rb +8 -0
- data/lib/generators/rails_performance/install/templates/initializer.rb +23 -0
- data/lib/rails_performance.rb +40 -7
- data/lib/rails_performance/data_source.rb +52 -13
- data/lib/rails_performance/engine.rb +39 -18
- data/lib/rails_performance/extensions/{capture_everything.rb → trace.rb} +2 -2
- data/lib/rails_performance/gems/custom_ext.rb +33 -0
- data/lib/rails_performance/gems/delayed_job_ext.rb +54 -0
- data/lib/rails_performance/gems/grape_ext.rb +35 -0
- data/lib/rails_performance/gems/rake_ext.rb +40 -0
- data/lib/rails_performance/gems/{sidekiq.rb → sidekiq_ext.rb} +14 -12
- data/lib/rails_performance/instrument/metrics_collector.rb +5 -3
- data/lib/rails_performance/models/base_record.rb +12 -0
- data/lib/rails_performance/models/custom_record.rb +48 -0
- data/lib/rails_performance/models/delayed_job_record.rb +62 -0
- data/lib/rails_performance/models/grape_record.rb +61 -0
- data/lib/rails_performance/models/rake_record.rb +49 -0
- data/lib/rails_performance/models/request_record.rb +98 -0
- data/lib/rails_performance/models/sidekiq_record.rb +66 -0
- data/lib/rails_performance/models/trace_record.rb +19 -0
- data/lib/rails_performance/rails/middleware.rb +42 -16
- data/lib/rails_performance/rails/query_builder.rb +1 -1
- data/lib/rails_performance/reports/breakdown_report.rb +4 -16
- data/lib/rails_performance/reports/crash_report.rb +4 -15
- data/lib/rails_performance/reports/recent_requests_report.rb +7 -44
- data/lib/rails_performance/reports/trace_report.rb +1 -1
- data/lib/rails_performance/{models → thread}/current_request.rb +9 -4
- data/lib/rails_performance/utils.rb +15 -29
- data/lib/rails_performance/version.rb +1 -1
- metadata +96 -10
- data/lib/rails_performance/models/job_record.rb +0 -48
- 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
|
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 }),
|
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.
|
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 :
|
50
|
-
"
|
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
|
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
|
-
|
10
|
+
initializer "rails_performance.middleware" do |app|
|
11
|
+
next unless RailsPerformance.enabled
|
10
12
|
|
11
13
|
if ::Rails::VERSION::MAJOR.to_i >= 5
|
12
|
-
|
14
|
+
app.middleware.insert_after ActionDispatch::Executor, RailsPerformance::Rails::Middleware
|
13
15
|
else
|
14
|
-
|
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
|
-
|
18
|
-
|
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::
|
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.
|
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.
|
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
|
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
|
10
|
-
|
9
|
+
now = Time.now
|
10
|
+
record = RP::Models::SidekiqRecord.new(
|
11
11
|
enqueued_ati: msg['enqueued_at'].to_i,
|
12
|
-
|
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
|
-
|
20
|
+
result = yield
|
21
|
+
record.status = "success"
|
22
|
+
result
|
22
23
|
rescue Exception => ex
|
23
|
-
|
24
|
-
|
24
|
+
record.status = "exception"
|
25
|
+
record.message = ex.message
|
26
|
+
raise ex
|
25
27
|
ensure
|
26
28
|
# store in ms instead of seconds
|
27
|
-
|
28
|
-
|
29
|
-
|
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[:
|
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.
|
39
|
+
CurrentRequest.current.data = record
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
41
|
-
end
|
43
|
+
end
|