rails_performance 1.6.0 → 1.7.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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -3
  3. data/app/controllers/rails_performance/rails_performance_controller.rb +15 -4
  4. data/app/engine_assets/javascripts/charts.js +3 -3
  5. data/app/engine_assets/stylesheets/style.css +12 -0
  6. data/app/helpers/rails_performance/rails_performance_helper.rb +3 -1
  7. data/app/views/rails_performance/layouts/rails_performance.html.erb +56 -55
  8. data/app/views/rails_performance/rails_performance/_card.html.erb +8 -0
  9. data/app/views/rails_performance/rails_performance/_chart.html.erb +9 -0
  10. data/app/views/rails_performance/rails_performance/index.html.erb +9 -54
  11. data/app/views/rails_performance/rails_performance/jobs.html.erb +69 -0
  12. data/app/views/rails_performance/shared/_header.html.erb +3 -0
  13. data/config/routes.rb +1 -0
  14. data/lib/generators/rails_performance/install/templates/initializer.rb +1 -1
  15. data/lib/rails_performance/data_source.rb +13 -1
  16. data/lib/rails_performance/engine.rb +5 -0
  17. data/lib/rails_performance/gems/active_job_ext.rb +42 -0
  18. data/lib/rails_performance/gems/sidekiq_ext.rb +3 -1
  19. data/lib/rails_performance/models/active_job_record.rb +60 -0
  20. data/lib/rails_performance/reports/base_report.rb +2 -1
  21. data/lib/rails_performance/reports/resources_report.rb +1 -1
  22. data/lib/rails_performance/system_monitor/resources_monitor.rb +2 -4
  23. data/lib/rails_performance/version.rb +1 -1
  24. data/lib/rails_performance/widgets/base.rb +15 -0
  25. data/lib/rails_performance/widgets/card.rb +17 -0
  26. data/lib/rails_performance/widgets/chart.rb +37 -0
  27. data/lib/rails_performance/widgets/percentile_card.rb +21 -0
  28. data/lib/rails_performance/{system_monitor → widgets}/resource_chart.rb +13 -2
  29. data/lib/rails_performance/widgets/response_time_chart.rb +29 -0
  30. data/lib/rails_performance/widgets/throughput_chart.rb +33 -0
  31. data/lib/rails_performance.rb +17 -2
  32. metadata +13 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9baa7d528736ea8e511d085238cd8311fbf4e85f81d776d3caabc6721490d9ff
4
- data.tar.gz: cb06cca4a2646bad65f8eba457d8f2d56372108385f044daafcd1016c115ff26
3
+ metadata.gz: ba9c4e66c3715ddb38e423cc32ca0f20c2d9ce0dde5439e1126cd061e6e7b41d
4
+ data.tar.gz: 930d0a2f8a2a916cfea4e1330f7e4f5fe38f9afa651223e95ead8132a2900b67
5
5
  SHA512:
6
- metadata.gz: 11a970b81b8d3f5d6a227ff1988513a947a0d5e8584d08656405383a944cda5d7539a6904c924235584fa54f2e87a2507a030e13051095089b44fdc7e783d250
7
- data.tar.gz: d9f3a87ebfaa1db462e564399213e9d7a87f40ad930802c5cafbe90cea738be4d00b138347e7e30e13b2e84f9eacf6d76f07f0f1a6193117486d116015d35ad5
6
+ metadata.gz: f608b9e9ad54d01c96ee82669df77b7d7cbeffb442c68ec80bc3163a8325c3f63183ebdcc8bdd710e093be056dc0a37a62322941a5f8e0eff30731507edb3ebc
7
+ data.tar.gz: 1087574e48fc087161d2ed3d1a7088fbe1f82d44c66f43d3ae6dd0e84ef52acc3f98de710cadcf3ca3dddd56e82a371b1375746eee0bd285900821c6ff4326df
data/README.md CHANGED
@@ -36,6 +36,8 @@ It allows you to track:
36
36
  - simple 500-crashes reports
37
37
  - deployment events (or custom events)
38
38
  - Sidekiq jobs
39
+ - SolidQueue jobs
40
+ - ActiveJob jobs
39
41
  - Delayed Job jobs
40
42
  - Grape API inside Rails app
41
43
  - Rake tasks performance
@@ -69,7 +71,7 @@ RailsPerformance.setup do |config|
69
71
  config.redis = Redis.new(url: ENV["REDIS_URL"].presence || "redis://127.0.0.1:6379/0") # or Redis::Namespace.new("rails-performance", redis: Redis.new), see below in README
70
72
  config.duration = 4.hours
71
73
 
72
- config.debug = false # currently not used
74
+ config.debug = false
73
75
  config.enabled = true
74
76
 
75
77
  # configure Recent tab (time window and limit of requests)
@@ -310,8 +312,12 @@ Just clone the repo, setup dummy app (`rails db:migrate`).
310
312
 
311
313
  After this:
312
314
 
313
- - rails s
314
- - rake test
315
+ - `rails s`
316
+ - `cd test/dummy` and `bundle exec rails db:migrate:queue`
317
+ - `cd test/dummy` and `bundle exec bin/jobs` (if you want to test ActiveJob)
318
+ - `rake test`
319
+
320
+ If you need to start with solid queue `SOLID_QUEUE_IN_PUMA=true rails s`.
315
321
 
316
322
  If you need quickly clear Redis data, you can use `rails runner 'RailsPerformance.redis.flushdb'`.
317
323
 
@@ -7,11 +7,14 @@ module RailsPerformance
7
7
  if RailsPerformance.enabled
8
8
  def index
9
9
  @datasource = RailsPerformance::DataSource.new(**prepare_query(params), type: :requests)
10
- db = @datasource.db
11
10
 
12
- @throughput_report_data = RailsPerformance::Reports::ThroughputReport.new(db).data
13
- @response_time_report_data = RailsPerformance::Reports::ResponseTimeReport.new(db).data
14
- @percentile_report_data = RailsPerformance::Reports::PercentileReport.new(db).data
11
+ @widgets = RailsPerformance.dashboard_charts.map do |row|
12
+ if row.is_a?(Array)
13
+ row.map { |class_name| Widgets.const_get(class_name).new(@datasource) }
14
+ else
15
+ Widgets.const_get(row).new(@datasource)
16
+ end
17
+ end
15
18
  end
16
19
 
17
20
  def resources
@@ -72,6 +75,14 @@ module RailsPerformance
72
75
  end
73
76
  end
74
77
 
78
+ def jobs
79
+ @datasource = RailsPerformance::DataSource.new(**prepare_query, type: :jobs)
80
+ db = @datasource.db
81
+ @throughput_report_data = RailsPerformance::Reports::ThroughputReport.new(db).data
82
+ @response_time_report_data = RailsPerformance::Reports::ResponseTimeReport.new(db).data
83
+ @recent_report_data = RailsPerformance::Reports::RecentRequestsReport.new(db).data
84
+ end
85
+
75
86
  def recent
76
87
  @datasource = RailsPerformance::DataSource.new(**prepare_query(params), type: :requests)
77
88
  db = @datasource.db
@@ -43,7 +43,7 @@ class RailsPerformanceChart extends HTMLElement {
43
43
  updateChart(newData) {
44
44
  let incoming = newData;
45
45
  if (this.type === 'Usage') {
46
- const { units, bytes } = calculateByteUnit(newData);
46
+ const { bytes } = calculateByteUnit(newData);
47
47
  incoming = newData.map(([t, v]) => [t, typeof v === 'number' ? (v / bytes).toFixed(2) : null]);
48
48
  }
49
49
  this.chart.updateRollingWindow(incoming, { windowSizeMs: this.windowSizeMs });
@@ -51,9 +51,9 @@ class RailsPerformanceChart extends HTMLElement {
51
51
 
52
52
  get windowSizeMs() {
53
53
  if (this.type === 'TIR' || this.type === 'RT') {
54
- return ms("4h")
54
+ return window.railsPerformanceDuration || ms("4h");
55
55
  } else {
56
- return ms("24h")
56
+ return ms("24h");
57
57
  }
58
58
  }
59
59
 
@@ -189,3 +189,15 @@ body.has-sticky-footer {
189
189
  .apexcharts-tooltip {
190
190
  background: yellow !important;
191
191
  }
192
+
193
+ .row {
194
+ display: flex;
195
+ flex-wrap: wrap;
196
+ gap: 0.75rem;
197
+ margin-bottom: 0.75rem;
198
+ }
199
+
200
+ .row > .widget {
201
+ flex: 1;
202
+ min-width: 0;
203
+ }
@@ -71,7 +71,7 @@ module RailsPerformance
71
71
 
72
72
  def status_tag(status)
73
73
  klass = case status.to_s
74
- when /error/
74
+ when /error/, /exception/
75
75
  "tag is-danger"
76
76
  when /^5/
77
77
  "tag is-danger"
@@ -140,6 +140,8 @@ module RailsPerformance
140
140
  "is-active" if controller_name == "rails_performance" && action_name == "rake"
141
141
  when :custom
142
142
  "is-active" if controller_name == "rails_performance" && action_name == "custom"
143
+ when :jobs
144
+ "is-active" if controller_name == "rails_performance" && action_name == "jobs"
143
145
  end
144
146
  end
145
147
  end
@@ -1,55 +1,56 @@
1
- <!DOCTYPE html>
2
- <html class="theme-light">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Rails Performance</title>
7
- <%= csrf_meta_tags %>
8
- <%= csp_meta_tag if ::Rails::VERSION::STRING.to_f >= 5.2 %>
9
-
10
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
11
- <%= engine_stylesheet_link_tag "style" %>
12
- <%= engine_stylesheet_link_tag "panel" %>
13
- <%= engine_stylesheet_link_tag "responsive" %>
14
-
15
- <link rel="shortcut icon" href="/favicon.ico">
16
-
17
- <%= engine_javascript_importmap_tags "application", {
18
- "@rails/ujs" => "https://cdn.jsdelivr.net/npm/@rails/ujs@7.1.3-4/+esm",
19
- "jquery" => "https://cdn.jsdelivr.net/npm/jquery@3.7.1/+esm",
20
- "apexcharts" => "https://cdn.jsdelivr.net/npm/apexcharts@3.45.0/+esm",
21
- "ms" => "https://cdn.jsdelivr.net/npm/ms@2.1.3/+esm",
22
- "stupid-table-plugin" => "https://cdn.jsdelivr.net/npm/stupid-table-plugin@1.1.3/+esm",
23
- "idiomorph" => "https://cdn.jsdelivr.net/npm/idiomorph@0.7.4/+esm"
24
- } %>
25
-
26
- <script>
27
- window.annotationsData = <%= raw RailsPerformance::Reports::AnnotationsReport.new.data.to_json %>;
28
- </script>
29
- </head>
30
-
31
- <body class="has-sticky-footer">
32
- <div class="loader-wrapper">
33
- <div class="loader is-loading"></div>
34
- </div>
35
-
36
- <div class="main-content">
37
- <section class="section">
38
- <div class="container is-fluid is-size-7">
39
- <%= render '/rails_performance/shared/header' %>
40
- <%= yield %>
41
- </div>
42
- </section>
43
- </div>
44
-
45
- <footer class="footer footer-box">
46
- <div class="container is-fluid is-size-7">
47
- © Rails Performance <span class='red'><i class="fas fa-heart"></i></span>
48
- <%= link_to 'https://github.com/igorkasyanchuk/rails_performance', 'https://github.com/igorkasyanchuk/rails_performance', target: '_blank' %>
49
- <div class="is-pulled-right">v.<%= RailsPerformance::VERSION %></div>
50
- </div>
51
- </footer>
52
-
53
- <%= render '/rails_performance/panel' %>
54
- </body>
55
- </html>
1
+ <!DOCTYPE html>
2
+ <html class="theme-light">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Rails Performance</title>
7
+ <%= csrf_meta_tags %>
8
+ <%= csp_meta_tag if ::Rails::VERSION::STRING.to_f >= 5.2 %>
9
+
10
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
11
+ <%= engine_stylesheet_link_tag "style" %>
12
+ <%= engine_stylesheet_link_tag "panel" %>
13
+ <%= engine_stylesheet_link_tag "responsive" %>
14
+
15
+ <link rel="shortcut icon" href="/favicon.ico">
16
+
17
+ <%= engine_javascript_importmap_tags "application", {
18
+ "@rails/ujs" => "https://cdn.jsdelivr.net/npm/@rails/ujs@7.1.3-4/+esm",
19
+ "jquery" => "https://cdn.jsdelivr.net/npm/jquery@3.7.1/+esm",
20
+ "apexcharts" => "https://cdn.jsdelivr.net/npm/apexcharts@3.45.0/+esm",
21
+ "ms" => "https://cdn.jsdelivr.net/npm/ms@2.1.3/+esm",
22
+ "stupid-table-plugin" => "https://cdn.jsdelivr.net/npm/stupid-table-plugin@1.1.3/+esm",
23
+ "idiomorph" => "https://cdn.jsdelivr.net/npm/idiomorph@0.7.4/+esm"
24
+ } %>
25
+
26
+ <script>
27
+ window.annotationsData = <%= raw RailsPerformance::Reports::AnnotationsReport.new.data.to_json %>;
28
+ window.railsPerformanceDuration = <%= RailsPerformance.duration.to_i * 1000 %>;
29
+ </script>
30
+ </head>
31
+
32
+ <body class="has-sticky-footer">
33
+ <div class="loader-wrapper">
34
+ <div class="loader is-loading"></div>
35
+ </div>
36
+
37
+ <div class="main-content">
38
+ <section class="section">
39
+ <div class="container is-fluid is-size-7">
40
+ <%= render '/rails_performance/shared/header' %>
41
+ <%= yield %>
42
+ </div>
43
+ </section>
44
+ </div>
45
+
46
+ <footer class="footer footer-box">
47
+ <div class="container is-fluid is-size-7">
48
+ © Rails Performance <span class='red'><i class="fas fa-heart"></i></span>
49
+ <%= link_to 'https://github.com/igorkasyanchuk/rails_performance', 'https://github.com/igorkasyanchuk/rails_performance', target: '_blank' %>
50
+ <div class="is-pulled-right">v.<%= RailsPerformance::VERSION %></div>
51
+ </div>
52
+ </footer>
53
+
54
+ <%= render '/rails_performance/panel' %>
55
+ </body>
56
+ </html>
@@ -0,0 +1,8 @@
1
+ <div class="widget">
2
+ <div class="card">
3
+ <div class="card-content">
4
+ <h2 class="subtitle is-size-1"><%= ms card.value %></h2>
5
+ <p class="content is-size-4"><%= card.label %></p>
6
+ </div>
7
+ </div>
8
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="widget">
2
+ <div class="card">
3
+ <div class="card-content">
4
+ <h2 class="subtitle"><%= chart.subtitle %></h2>
5
+ <%= tag.rails_performance_chart(chart.data.to_json.html_safe, id: chart.id, type: chart.type, legend: chart.legend, units: chart.units, class: "chart") %>
6
+ <p class="content is-small"><%= chart.description %></p>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -1,7 +1,7 @@
1
- <title>Number of Requests to the Application</title>
2
-
3
- <% unless @datasource.default? %>
4
- <%#= link_to raw("&larr; Back"), rails_performance_path, class: "back_link" %>
1
+ <title>Number of Requests to the Application</title>
2
+
3
+ <% unless @datasource.default? %>
4
+ <%#= link_to raw("&larr; Back"), rails_performance_path, class: "back_link" %>
5
5
  <% end %>
6
6
 
7
7
  <div class="has-text-right mb-4">
@@ -12,53 +12,8 @@
12
12
  </rails-performance-autoupdate>
13
13
  </div>
14
14
 
15
- <div class="columns">
16
- <div class="column">
17
- <div class="card">
18
- <div class="card-content">
19
- <h2 class="subtitle is-size-1"><%= ms @percentile_report_data[:p50] %></h2>
20
- <p class="content is-size-4">p50</p>
21
- </div>
22
- </div>
23
- </div>
24
-
25
- <div class="column">
26
- <div class="card">
27
- <div class="card-content">
28
- <h2 class="subtitle is-size-1"><%= ms @percentile_report_data[:p95] %></h2>
29
- <p class="content is-size-4">p95</p>
30
- </div>
31
- </div>
32
- </div>
33
-
34
- <div class="column">
35
- <div class="card">
36
- <div class="card-content">
37
- <h2 class="subtitle is-size-1"><%= ms @percentile_report_data[:p99] %></h2>
38
- <p class="content is-size-4">p99</p>
39
- </div>
40
- </div>
41
- </div>
42
- </div>
43
-
44
- <div class="card">
45
- <div class="card-content">
46
- <h2 class="subtitle">Throughput Report</h2>
47
- <rails-performance-chart id="throughput_report_chart" type="TIR" legend="RPM" units="rpm" class="chart">
48
- <%= raw @throughput_report_data.to_json %>
49
- </rails-performance-chart>
50
- <p class="content is-small">All requests (site visitors, search engines, bots, etc)</p>
51
- </div>
52
- </div>
53
-
54
- <br/>
55
-
56
- <div class="card">
57
- <div class="card-content">
58
- <h2 class="subtitle">Average Response Time Report</h2>
59
- <rails-performance-chart id="response_time_report_chart" type="RT" legend="Response Time" class="chart">
60
- <%= raw @response_time_report_data.to_json %>
61
- </rails-performance-chart>
62
- <p class="content is-small">All requests (site visitors, search engines, bots, etc)</p>
63
- </div>
64
- </div>
15
+ <% @widgets.each do |row| %>
16
+ <div class="row">
17
+ <%= render row %>
18
+ </div>
19
+ <% end %>
@@ -0,0 +1,69 @@
1
+ <title>ActiveJob</title>
2
+
3
+ <% unless @datasource.default? %>
4
+ <%#= link_to raw("&larr; Back"), rails_performance_path, class: "back_link" %>
5
+ <% end %>
6
+
7
+ <div class="card">
8
+ <div class="card-content">
9
+ <h2 class="subtitle">ActiveJob Workers Throughput Report</h2>
10
+ <rails-performance-chart id="throughput_report_chart" type="TIR" legend="Jobs" units="jobs / minute" class="chart">
11
+ <%= raw @throughput_report_data.to_json %>
12
+ </rails-performance-chart>
13
+ <p class="content is-small">All active jobs in the application</p>
14
+ </div>
15
+ </div>
16
+
17
+ <br/>
18
+
19
+ <div class="card">
20
+ <div class="card-content">
21
+ <h2 class="subtitle">Average Execution Time</h2>
22
+ <rails-performance-chart id="response_time_report_chart" type="RT" legend="Response Time" class="chart">
23
+ <%= raw @response_time_report_data.to_json %>
24
+ </rails-performance-chart>
25
+ <p class="content is-small">All workers in the application</p>
26
+ </div>
27
+ </div>
28
+
29
+ <br/>
30
+
31
+ <div class="card">
32
+ <div class="card-content">
33
+ <h2 class="subtitle">Recent Jobs (last <%= RailsPerformance.recent_requests_time_window / 60 %> minutes)<h2>
34
+
35
+ <table class="table is-fullwidth is-hoverable is-narrow">
36
+ <thead>
37
+ <tr>
38
+ <th data-sort="string">Datetime</th>
39
+ <th data-sort="string">Job ID</th>
40
+ <th data-sort="string">Queue</th>
41
+ <th data-sort="string">Worker</th>
42
+ <th data-sort="string">Status</th>
43
+ <th data-sort="float">Duration</th>
44
+ </tr>
45
+ </thead>
46
+ <tbody>
47
+ <% if @recent_report_data.empty? %>
48
+ <tr>
49
+ <td colspan="10">Nothing to show here. Try to make a few requests in the main app.</td>
50
+ </tr>
51
+ <% end %>
52
+ <% @recent_report_data.each do |e| %>
53
+ <tr>
54
+ <td><%= format_datetime e[:datetime] %></td>
55
+ <td><%= e[:jid] %></td>
56
+ <td><%= e[:queue] %></td>
57
+ <td><%= e[:worker] %></td>
58
+ <td>
59
+ <%= status_tag e[:status] %>
60
+ </td>
61
+ <td class="nowrap">
62
+ <%= ms e[:duration], 1 %>
63
+ </td>
64
+ </tr>
65
+ <% end %>
66
+ </tbody>
67
+ </table>
68
+ </div>
69
+ </div>
@@ -22,6 +22,9 @@
22
22
  <% end %>
23
23
  <%= link_to 'Slow Requests', rails_performance.rails_performance_slow_url, class: "navbar-item #{active?(:slow)}" %>
24
24
  <%= link_to '500 Errors', rails_performance.rails_performance_crashes_url, class: "navbar-item #{active?(:crashes)}" %>
25
+ <% if defined?(::ActiveJob) %>
26
+ <%= link_to 'ActiveJob', rails_performance.rails_performance_jobs_url, class: "navbar-item #{active?(:jobs)}" %>
27
+ <% end %>
25
28
  <% if defined?(Sidekiq) %>
26
29
  <%= link_to 'Sidekiq', rails_performance.rails_performance_sidekiq_url, class: "navbar-item #{active?(:sidekiq)}" %>
27
30
  <% end %>
data/config/routes.rb CHANGED
@@ -15,6 +15,7 @@ RailsPerformance::Engine.routes.draw do
15
15
  get "/rake" => "rails_performance#rake", :as => :rails_performance_rake
16
16
  get "/custom" => "rails_performance#custom", :as => :rails_performance_custom
17
17
  get "/resources" => "rails_performance#resources", :as => :rails_performance_resources
18
+ get "/jobs" => "rails_performance#jobs", :as => :rails_performance_jobs
18
19
  end
19
20
 
20
21
  Rails.application.routes.draw do
@@ -15,7 +15,7 @@ if defined?(RailsPerformance)
15
15
  # config.slow_requests_limit = 500 # number of slow requests
16
16
  config.slow_requests_threshold = 500 # ms
17
17
 
18
- config.debug = false # currently not used>
18
+ config.debug = false
19
19
  config.enabled = true
20
20
 
21
21
  # default path where to mount gem
@@ -7,7 +7,8 @@ module RailsPerformance
7
7
  grape: RailsPerformance::Models::GrapeRecord,
8
8
  rake: RailsPerformance::Models::RakeRecord,
9
9
  custom: RailsPerformance::Models::CustomRecord,
10
- resources: RailsPerformance::Models::ResourceRecord
10
+ resources: RailsPerformance::Models::ResourceRecord,
11
+ jobs: RailsPerformance::Models::ActiveJobRecord
11
12
  }
12
13
 
13
14
  attr_reader :q, :klass, :type, :days
@@ -68,6 +69,8 @@ module RailsPerformance
68
69
  "rake|*#{compile_rake_query}*|END|#{RailsPerformance::SCHEMA}"
69
70
  when :custom
70
71
  "custom|*#{compile_custom_query}*|END|#{RailsPerformance::SCHEMA}"
72
+ when :jobs
73
+ "active_job|*#{compile_active_job_query}*|END|#{RailsPerformance::SCHEMA}"
71
74
  else
72
75
  raise "wrong type: \"#{type}\" for datasource query builder"
73
76
  end
@@ -94,6 +97,15 @@ module RailsPerformance
94
97
  str.join("*")
95
98
  end
96
99
 
100
+ def compile_active_job_query
101
+ str = []
102
+ str << "queue|#{q[:queue]}|" if q[:queue].present?
103
+ str << "worker|#{q[:worker]}|" if q[:worker].present?
104
+ str << "datetime|#{q[:on].strftime("%Y%m%d")}*|" if q[:on].present?
105
+ str << "status|#{q[:status]}|" if q[:status].present?
106
+ str.join("*")
107
+ end
108
+
97
109
  def compile_resource_query
98
110
  str = []
99
111
  str << "server|#{q[:server]}|" if q[:server].present?
@@ -57,6 +57,11 @@ module RailsPerformance
57
57
  end
58
58
  end
59
59
 
60
+ if defined?(::ActiveJob)
61
+ require_relative "gems/active_job_ext"
62
+ RailsPerformance::Gems::ActiveJobExt.init
63
+ end
64
+
60
65
  if defined?(::Grape)
61
66
  require_relative "gems/grape_ext"
62
67
  RailsPerformance::Gems::GrapeExt.init
@@ -0,0 +1,42 @@
1
+ module RailsPerformance
2
+ module Gems
3
+ class ActiveJobExt
4
+ module AroundPerform
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ around_perform do |job, block|
9
+ now = RailsPerformance::Utils.time
10
+ exception = nil
11
+ record = RailsPerformance::Models::ActiveJobRecord.new(
12
+ worker: job.class.name,
13
+ queue: job.queue_name,
14
+ enqueued_ati: job.enqueued_at.to_i,
15
+ datetimei: job.scheduled_at.to_i,
16
+ jid: job.job_id,
17
+ start_timei: now.to_i,
18
+ datetime: now.strftime(RailsPerformance::FORMAT)
19
+ )
20
+ result = block.call
21
+ record.status = "success"
22
+ result
23
+ rescue Exception => ex # rubocop:disable Lint/RescueException
24
+ record.status = "exception"
25
+ record.message = ex.message
26
+ exception = ex
27
+ ensure
28
+ # store in ms instead of seconds
29
+ record.duration = (RailsPerformance::Utils.time - now) * 1000
30
+ record.save
31
+ CurrentRequest.cleanup
32
+ raise exception if exception
33
+ end
34
+ end
35
+ end
36
+
37
+ def self.init
38
+ ActiveJob::Base.send :include, AroundPerform
39
+ end
40
+ end
41
+ end
42
+ end
@@ -6,6 +6,7 @@ module RailsPerformance
6
6
 
7
7
  def call(worker, msg, queue)
8
8
  now = RailsPerformance::Utils.time
9
+ exception = nil
9
10
  record = RailsPerformance::Models::SidekiqRecord.new(
10
11
  enqueued_ati: msg["enqueued_at"].to_i,
11
12
  datetimei: msg["created_at"].to_i,
@@ -22,12 +23,13 @@ module RailsPerformance
22
23
  rescue Exception => ex # rubocop:disable Lint/RescueException
23
24
  record.status = "exception"
24
25
  record.message = ex.message
25
- raise ex
26
+ exception = ex
26
27
  ensure
27
28
  # store in ms instead of seconds
28
29
  record.duration = (RailsPerformance::Utils.time - now) * 1000
29
30
  record.save
30
31
  CurrentRequest.cleanup
32
+ raise exception if exception
31
33
  end
32
34
  end
33
35
  end
@@ -0,0 +1,60 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class ActiveJobRecord < BaseRecord
4
+ attr_accessor :queue, :worker, :jid, :datetimei, :enqueued_ati, :datetime, :start_timei, :duration, :status, :message
5
+
6
+ # deserialize from redis
7
+ def self.from_db(key, value)
8
+ items = key.split("|")
9
+
10
+ ActiveJobRecord.new(
11
+ queue: items[2],
12
+ worker: items[4],
13
+ jid: items[6],
14
+ datetime: items[8],
15
+ datetimei: items[10],
16
+ enqueued_ati: items[12],
17
+ start_timei: items[14],
18
+ status: items[16],
19
+ json: value
20
+ )
21
+ end
22
+
23
+ def initialize(queue:, worker:, jid:, datetime:, datetimei:, enqueued_ati:, start_timei:, duration: nil, status: nil, message: nil, json: "{}")
24
+ @queue = queue
25
+ @worker = worker
26
+ @jid = jid
27
+ @datetime = datetime
28
+ @datetimei = datetimei.to_i
29
+ @start_timei = start_timei
30
+ @enqueued_ati = enqueued_ati
31
+ @duration = duration
32
+ @status = status
33
+ @message = message
34
+ @json = json
35
+ end
36
+
37
+ # For UI
38
+ def record_hash
39
+ {
40
+ worker: worker,
41
+ queue: queue,
42
+ jid: jid,
43
+ datetimei: datetimei,
44
+ datetime: RailsPerformance::Utils.from_datetimei(start_timei.to_i),
45
+ start_timei: start_timei,
46
+ duration: value["duration"],
47
+ message: value["message"],
48
+ status: status
49
+ }
50
+ end
51
+
52
+ # serialize to redis
53
+ def save
54
+ key = "active_job|queue|#{queue}|worker|#{worker}|jid|#{jid}|datetime|#{datetime}|datetimei|#{datetimei}|enqueued_ati|#{enqueued_ati}|start_timei|#{start_timei}|status|#{status}|END|#{RailsPerformance::SCHEMA}"
55
+ value = {duration:, message:}
56
+ Utils.save_to_redis(key, value)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -64,7 +64,8 @@ module RailsPerformance
64
64
  # ....
65
65
  # }
66
66
  def nil_data(duration = RailsPerformance.duration)
67
- @nil_data ||= begin
67
+ @nil_data_cache ||= {}
68
+ @nil_data_cache[duration] ||= begin
68
69
  result = {}
69
70
  now = RailsPerformance::Utils.kind_of_now
70
71
  now = now.change(sec: 0, usec: 0)
@@ -8,7 +8,7 @@ module RailsPerformance
8
8
 
9
9
  def charts
10
10
  RailsPerformance.system_monitors.map do |class_name|
11
- SystemMonitor.const_get(class_name).new(self)
11
+ Widgets.const_get(class_name).new(self)
12
12
  end
13
13
  end
14
14
  end
@@ -1,5 +1,3 @@
1
- require "rails_performance/system_monitor/resource_chart"
2
-
3
1
  module RailsPerformance
4
2
  module SystemMonitor
5
3
  class ResourcesMonitor
@@ -49,7 +47,7 @@ module RailsPerformance
49
47
 
50
48
  def monitors
51
49
  @monitors ||= RailsPerformance.system_monitors.map do |class_name|
52
- RailsPerformance::SystemMonitor.const_get(class_name).new(nil)
50
+ RailsPerformance::Widgets.const_get(class_name).new(nil)
53
51
  end
54
52
  end
55
53
 
@@ -58,7 +56,7 @@ module RailsPerformance
58
56
  end
59
57
 
60
58
  def store_data(data)
61
- ::Rails.logger.info("Server: #{server_id}, Context: #{context}, Role: #{role}, data: #{data}")
59
+ RailsPerformance.log("Server: #{server_id}, Context: #{context}, Role: #{role}, data: #{data}")
62
60
 
63
61
  now = RailsPerformance::Utils.kind_of_now
64
62
  now = now.change(sec: 0, usec: 0)
@@ -1,5 +1,5 @@
1
1
  module RailsPerformance
2
- VERSION = "1.6.0"
2
+ VERSION = "1.7.0.beta1"
3
3
  SCHEMA = "1.0.2"
4
4
  EVENTS_SCHEMA = "1.0.0"
5
5
  end
@@ -0,0 +1,15 @@
1
+ module RailsPerformance
2
+ module Widgets
3
+ class Base
4
+ attr_reader :datasource
5
+
6
+ def initialize(datasource)
7
+ @datasource = datasource
8
+ end
9
+
10
+ def to_partial_path
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module RailsPerformance
2
+ module Widgets
3
+ class Card < Base
4
+ def label
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def value
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def to_partial_path
13
+ "rails_performance/rails_performance/card"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ module RailsPerformance
2
+ module Widgets
3
+ class Chart < Base
4
+ def id
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def type
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def subtitle
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def description
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def legend
21
+ raise NotImplementedError
22
+ end
23
+
24
+ def units
25
+ nil
26
+ end
27
+
28
+ def data
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def to_partial_path
33
+ "rails_performance/rails_performance/chart"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ module RailsPerformance
2
+ module Widgets
3
+ class PercentileCard < Card
4
+ def value
5
+ Reports::PercentileReport.new(datasource.db).data[label.to_sym]
6
+ end
7
+ end
8
+
9
+ class P50Card < PercentileCard
10
+ def label = "p50"
11
+ end
12
+
13
+ class P95Card < PercentileCard
14
+ def label = "p95"
15
+ end
16
+
17
+ class P99Card < PercentileCard
18
+ def label = "p99"
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,17 @@
1
1
  module RailsPerformance
2
- module SystemMonitor
3
- ResourceChart = Struct.new(:server, :key, :type, :subtitle, :description, :legend, keyword_init: true) do
2
+ module Widgets
3
+ class ResourceChart < Chart
4
+ attr_reader :server, :key, :type, :subtitle, :description, :legend
5
+
6
+ def initialize(server:, key:, type:, subtitle:, description:, legend:)
7
+ @server = server
8
+ @key = key
9
+ @type = type
10
+ @subtitle = subtitle
11
+ @description = description
12
+ @legend = legend
13
+ end
14
+
4
15
  def id
5
16
  [key, "report", server.key.parameterize].join("_")
6
17
  end
@@ -0,0 +1,29 @@
1
+ module RailsPerformance
2
+ module Widgets
3
+ class ResponseTimeChart < Chart
4
+ def id
5
+ "response_time_report_chart"
6
+ end
7
+
8
+ def type
9
+ "RT"
10
+ end
11
+
12
+ def subtitle
13
+ "Average Response Time Report"
14
+ end
15
+
16
+ def description
17
+ "All requests (site visitors, search engines, bots, etc)"
18
+ end
19
+
20
+ def legend
21
+ "Response Time"
22
+ end
23
+
24
+ def data
25
+ Reports::ResponseTimeReport.new(datasource.db).data
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ module RailsPerformance
2
+ module Widgets
3
+ class ThroughputChart < Chart
4
+ def id
5
+ "throughput_report_chart"
6
+ end
7
+
8
+ def type
9
+ "TIR"
10
+ end
11
+
12
+ def subtitle
13
+ "Throughput Report"
14
+ end
15
+
16
+ def description
17
+ "All requests (site visitors, search engines, bots, etc)"
18
+ end
19
+
20
+ def legend
21
+ "RPM"
22
+ end
23
+
24
+ def units
25
+ "rpm"
26
+ end
27
+
28
+ def data
29
+ Reports::ThroughputReport.new(datasource.db).data
30
+ end
31
+ end
32
+ end
33
+ end
@@ -13,6 +13,7 @@ require_relative "rails_performance/models/trace_record"
13
13
  require_relative "rails_performance/models/rake_record"
14
14
  require_relative "rails_performance/models/resource_record"
15
15
  require_relative "rails_performance/models/custom_record"
16
+ require_relative "rails_performance/models/active_job_record"
16
17
  require_relative "rails_performance/data_source"
17
18
  require_relative "rails_performance/utils"
18
19
  require_relative "rails_performance/reports/base_report"
@@ -28,6 +29,13 @@ require_relative "rails_performance/reports/percentile_report"
28
29
  require_relative "rails_performance/reports/resources_report"
29
30
  require_relative "rails_performance/reports/annotations_report"
30
31
  require_relative "rails_performance/events/record"
32
+ require_relative "rails_performance/widgets/base"
33
+ require_relative "rails_performance/widgets/chart"
34
+ require_relative "rails_performance/widgets/card"
35
+ require_relative "rails_performance/widgets/throughput_chart"
36
+ require_relative "rails_performance/widgets/response_time_chart"
37
+ require_relative "rails_performance/widgets/percentile_card"
38
+ require_relative "rails_performance/widgets/resource_chart"
31
39
  require_relative "rails_performance/extensions/trace"
32
40
  require_relative "rails_performance/thread/current_request"
33
41
  require_relative "rails_performance/interface"
@@ -139,6 +147,13 @@ module RailsPerformance
139
147
  "DiskUsage"
140
148
  ]
141
149
 
150
+ mattr_accessor :dashboard_charts
151
+ @@dashboard_charts = [
152
+ ["P50Card", "P95Card", "P99Card"],
153
+ "ThroughputChart",
154
+ "ResponseTimeChart"
155
+ ]
156
+
142
157
  # -- internal usage --
143
158
  #
144
159
  #
@@ -164,9 +179,9 @@ module RailsPerformance
164
179
  return unless RailsPerformance.debug
165
180
 
166
181
  if ::Rails.logger
167
- # puts(message)
182
+ puts(message) if ENV["DEV_LOGS"] == "true"
168
183
  ::Rails.logger.debug(message)
169
- else
184
+ elsif ENV["DEV_LOGS"] == "true"
170
185
  puts(message)
171
186
  end
172
187
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_performance
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
@@ -317,6 +317,8 @@ files:
317
317
  - app/helpers/rails_performance/rails_performance_helper.rb
318
318
  - app/views/rails_performance/_panel.html.erb
319
319
  - app/views/rails_performance/layouts/rails_performance.html.erb
320
+ - app/views/rails_performance/rails_performance/_card.html.erb
321
+ - app/views/rails_performance/rails_performance/_chart.html.erb
320
322
  - app/views/rails_performance/rails_performance/_export.html.erb
321
323
  - app/views/rails_performance/rails_performance/_recent_row.html.erb
322
324
  - app/views/rails_performance/rails_performance/_summary.html.erb
@@ -326,6 +328,7 @@ files:
326
328
  - app/views/rails_performance/rails_performance/delayed_job.html.erb
327
329
  - app/views/rails_performance/rails_performance/grape.html.erb
328
330
  - app/views/rails_performance/rails_performance/index.html.erb
331
+ - app/views/rails_performance/rails_performance/jobs.html.erb
329
332
  - app/views/rails_performance/rails_performance/rake.html.erb
330
333
  - app/views/rails_performance/rails_performance/recent.html.erb
331
334
  - app/views/rails_performance/rails_performance/requests.html.erb
@@ -347,6 +350,7 @@ files:
347
350
  - lib/rails_performance/engine_assets/helper.rb
348
351
  - lib/rails_performance/events/record.rb
349
352
  - lib/rails_performance/extensions/trace.rb
353
+ - lib/rails_performance/gems/active_job_ext.rb
350
354
  - lib/rails_performance/gems/custom_ext.rb
351
355
  - lib/rails_performance/gems/delayed_job_ext.rb
352
356
  - lib/rails_performance/gems/grape_ext.rb
@@ -354,6 +358,7 @@ files:
354
358
  - lib/rails_performance/gems/sidekiq_ext.rb
355
359
  - lib/rails_performance/instrument/metrics_collector.rb
356
360
  - lib/rails_performance/interface.rb
361
+ - lib/rails_performance/models/active_job_record.rb
357
362
  - lib/rails_performance/models/base_record.rb
358
363
  - lib/rails_performance/models/collection.rb
359
364
  - lib/rails_performance/models/custom_record.rb
@@ -378,11 +383,17 @@ files:
378
383
  - lib/rails_performance/reports/slow_requests_report.rb
379
384
  - lib/rails_performance/reports/throughput_report.rb
380
385
  - lib/rails_performance/reports/trace_report.rb
381
- - lib/rails_performance/system_monitor/resource_chart.rb
382
386
  - lib/rails_performance/system_monitor/resources_monitor.rb
383
387
  - lib/rails_performance/thread/current_request.rb
384
388
  - lib/rails_performance/utils.rb
385
389
  - lib/rails_performance/version.rb
390
+ - lib/rails_performance/widgets/base.rb
391
+ - lib/rails_performance/widgets/card.rb
392
+ - lib/rails_performance/widgets/chart.rb
393
+ - lib/rails_performance/widgets/percentile_card.rb
394
+ - lib/rails_performance/widgets/resource_chart.rb
395
+ - lib/rails_performance/widgets/response_time_chart.rb
396
+ - lib/rails_performance/widgets/throughput_chart.rb
386
397
  homepage: https://github.com/igorkasyanchuk/rails_performance
387
398
  licenses:
388
399
  - MIT