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.
- checksums.yaml +4 -4
- data/README.md +5 -13
- data/Rakefile +14 -14
- data/app/assets/images/download.svg +3 -0
- data/app/controllers/rails_performance/base_controller.rb +21 -21
- data/app/controllers/rails_performance/concerns/csv_exportable.rb +29 -0
- data/app/controllers/rails_performance/rails_performance_controller.rb +96 -49
- data/app/helpers/rails_performance/rails_performance_helper.rb +152 -156
- data/app/views/rails_performance/javascripts/app.js +2 -2
- data/app/views/rails_performance/rails_performance/_export.html.erb +3 -0
- data/app/views/rails_performance/rails_performance/crashes.html.erb +8 -1
- data/app/views/rails_performance/rails_performance/index.html.erb +29 -0
- data/app/views/rails_performance/rails_performance/recent.html.erb +8 -6
- data/app/views/rails_performance/rails_performance/requests.html.erb +15 -1
- data/app/views/rails_performance/rails_performance/slow.html.erb +3 -0
- data/app/views/rails_performance/shared/_header.html.erb +0 -1
- data/app/views/rails_performance/stylesheets/style.css +10 -0
- data/config/routes.rb +16 -18
- data/lib/generators/rails_performance/install/install_generator.rb +1 -1
- data/lib/generators/rails_performance/install/templates/initializer.rb +56 -42
- data/lib/rails_performance/data_source.rb +120 -121
- data/lib/rails_performance/engine.rb +8 -8
- data/lib/rails_performance/extensions/trace.rb +32 -33
- data/lib/rails_performance/gems/custom_ext.rb +31 -34
- data/lib/rails_performance/gems/delayed_job_ext.rb +50 -54
- data/lib/rails_performance/gems/grape_ext.rb +33 -35
- data/lib/rails_performance/gems/rake_ext.rb +41 -44
- data/lib/rails_performance/gems/sidekiq_ext.rb +34 -37
- data/lib/rails_performance/instrument/metrics_collector.rb +50 -50
- data/lib/rails_performance/models/base_record.rb +33 -36
- data/lib/rails_performance/models/collection.rb +35 -36
- data/lib/rails_performance/models/custom_record.rb +47 -48
- data/lib/rails_performance/models/delayed_job_record.rb +61 -62
- data/lib/rails_performance/models/grape_record.rb +60 -61
- data/lib/rails_performance/models/rake_record.rb +48 -49
- data/lib/rails_performance/models/request_record.rb +128 -120
- data/lib/rails_performance/models/sidekiq_record.rb +65 -66
- data/lib/rails_performance/models/trace_record.rb +18 -19
- data/lib/rails_performance/rails/middleware.rb +75 -76
- data/lib/rails_performance/rails/query_builder.rb +18 -20
- data/lib/rails_performance/reports/base_report.rb +60 -60
- data/lib/rails_performance/reports/breakdown_report.rb +15 -18
- data/lib/rails_performance/reports/crash_report.rb +15 -17
- data/lib/rails_performance/reports/percentile_report.rb +14 -0
- data/lib/rails_performance/reports/recent_requests_report.rb +24 -24
- data/lib/rails_performance/reports/requests_report.rb +30 -27
- data/lib/rails_performance/reports/response_time_report.rb +17 -17
- data/lib/rails_performance/reports/slow_requests_report.rb +4 -4
- data/lib/rails_performance/reports/throughput_report.rb +15 -17
- data/lib/rails_performance/reports/trace_report.rb +16 -18
- data/lib/rails_performance/thread/current_request.rb +33 -34
- data/lib/rails_performance/utils.rb +64 -54
- data/lib/rails_performance/version.rb +2 -2
- data/lib/rails_performance.rb +35 -36
- metadata +21 -17
@@ -1,35 +1,33 @@
|
|
1
|
-
module RailsPerformance
|
2
|
-
module Gems
|
3
|
-
class GrapeExt
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
CurrentRequest.current.
|
12
|
-
CurrentRequest.current.record
|
13
|
-
CurrentRequest.current.record.
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
CurrentRequest.current.record.
|
22
|
-
CurrentRequest.current.record.
|
23
|
-
CurrentRequest.current.record.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
if
|
17
|
-
|
18
|
-
|
19
|
-
RailsPerformance::
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
record.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
record.
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
6
|
-
end
|
7
|
-
|
8
|
-
def save
|
9
|
-
raise
|
10
|
-
end
|
11
|
-
|
12
|
-
def record_hash
|
13
|
-
raise
|
14
|
-
end
|
15
|
-
|
16
|
-
def value
|
17
|
-
@value ||= JSON.parse(@json || "{}")
|
18
|
-
end
|
19
|
-
|
20
|
-
def duration
|
21
|
-
value[
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def ms(e)
|
27
|
-
if e
|
28
|
-
e.to_f.round(1).to_s + " ms"
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
35
|
-
|
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
|
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,
|
20
|
-
@tag_name
|
21
|
-
@namespace_name = namespace_name
|
22
|
-
@duration
|
23
|
-
@datetime
|
24
|
-
@datetimei
|
25
|
-
@status
|
26
|
-
@json
|
27
|
-
end
|
28
|
-
|
29
|
-
def record_hash
|
30
|
-
{
|
31
|
-
tag_name:
|
32
|
-
namespace_name:
|
33
|
-
status:
|
34
|
-
datetimei: datetimei,
|
35
|
-
datetime: Time.at(
|
36
|
-
duration:
|
37
|
-
}
|
38
|
-
end
|
39
|
-
|
40
|
-
def save
|
41
|
-
key
|
42
|
-
value = {
|
43
|
-
Utils.save_to_redis(key, value)
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|