rails_performance 0.9.4 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -7
  3. data/app/controllers/rails_performance/base_controller.rb +21 -0
  4. data/app/controllers/rails_performance/rails_performance_controller.rb +91 -0
  5. data/app/helpers/rails_performance/application_helper.rb +116 -0
  6. data/app/views/rails_performance/layouts/rails_performance.html.erb +2 -2
  7. data/app/views/rails_performance/{_summary.html.erb → rails_performance/_summary.html.erb} +0 -0
  8. data/app/views/rails_performance/{_trace.html.erb → rails_performance/_trace.html.erb} +0 -0
  9. data/app/views/rails_performance/{crashes.html.erb → rails_performance/crashes.html.erb} +0 -0
  10. data/app/views/rails_performance/{index.html.erb → rails_performance/index.html.erb} +0 -0
  11. data/app/views/rails_performance/{jobs.html.erb → rails_performance/jobs.html.erb} +0 -0
  12. data/app/views/rails_performance/{recent.html.erb → rails_performance/recent.html.erb} +0 -0
  13. data/app/views/rails_performance/{requests.html.erb → rails_performance/requests.html.erb} +1 -1
  14. data/app/views/rails_performance/{summary.js.erb → rails_performance/summary.js.erb} +1 -1
  15. data/app/views/rails_performance/{trace.js.erb → rails_performance/trace.js.erb} +1 -1
  16. data/config/routes.rb +2 -2
  17. data/lib/generators/rails_performance/install/USAGE +8 -0
  18. data/lib/generators/rails_performance/install/install_generator.rb +8 -0
  19. data/lib/generators/rails_performance/install/templates/initializer.rb +23 -0
  20. data/lib/rails_performance.rb +11 -1
  21. data/lib/rails_performance/engine.rb +21 -16
  22. data/lib/rails_performance/gems/sidekiq.rb +1 -0
  23. data/lib/rails_performance/instrument/metrics_collector.rb +3 -2
  24. data/lib/rails_performance/utils.rb +1 -2
  25. data/lib/rails_performance/version.rb +1 -1
  26. metadata +31 -14
  27. data/app/controllers/base_controller.rb +0 -19
  28. data/app/controllers/rails_performance_controller.rb +0 -88
  29. data/app/helpers/rails_performance_helper.rb +0 -114
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6532a46e577225137d7fbd9baae88b245157d75c4091690f73209886b6c6c15
4
- data.tar.gz: 7946da511a5e589a854af1bef20c642de207004c4f860353657c92c895e2c485
3
+ metadata.gz: a6efdeeeb71789d08c284f21165138c13bdcb094cd0d48fcbaad521a946fec6f
4
+ data.tar.gz: 81b265d6bf3555fb2868504983ec3b01cf1efe9d99b4b4e74b08533d08ff2023
5
5
  SHA512:
6
- metadata.gz: 7c5a8d54bb4670dfe84cd720410dc30cab1facadcbac0f6457a41c2954d8ab66726728ebff333f1778ebdbcb3525806b01594619a0bf054a9e9c8eb3dfd9ab72
7
- data.tar.gz: b7c6cda16e208941173e3aeaa7d3f5cc282a79d9b4077645364e341b0b30ad169133db769744abb24eefb34b7357145492047cf4a7041b505544df758783836e
6
+ metadata.gz: 1f59e689a2b57a486b857cc910fccdf84fdc2a7afeee08f691a912aa3affcea5138f1be4f693699c06d9ac0c126c07f4b479e1434242d427581a413818d13fc7
7
+ data.tar.gz: 591b8b1334668e285fb8a23fdf01498e90b0f5d172378cce8abfd67af2d81f31046ee7520b1d1aad6c125cc61f13ef83f86dd6f2591eeb0fb1a2f89697518349
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Rails Performance
2
2
 
3
- [![Build Status](https://travis-ci.org/igorkasyanchuk/rails_performance.svg?branch=master)](https://travis-ci.org/igorkasyanchuk/rails_performance)
3
+ [![Tests](https://github.com/igorkasyanchuk/rails_performance/actions/workflows/ruby.yml/badge.svg)](https://github.com/igorkasyanchuk/rails_performance/actions/workflows/ruby.yml)
4
+ [![RailsJazz](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/my_other.svg?raw=true)](https://www.railsjazz.com)
5
+ [![https://www.patreon.com/igorkasyanchuk](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/patron.svg?raw=true)](https://www.patreon.com/igorkasyanchuk)
4
6
 
5
7
  A self-hosted tool to monitor the performance of your Ruby on Rails application.
6
8
 
@@ -17,13 +19,13 @@ It allows you to track:
17
19
  - SQL queries, rendering logs in "Recent Requests" section
18
20
  - simple 500-crashes reports
19
21
  - track Sidekiq jobs performance
20
- - works with Rails 4.2+ (and probably 4.1, 4.0 too)
22
+ - works with Rails 4.2+ (and probably 4.1, 4.0 too) and Ruby 2.2+
21
23
 
22
24
  All data are stored in `local` Redis and not sent to any 3rd party servers.
23
25
 
24
26
  ## Production
25
27
 
26
- Gem is production-ready. At least on my 2 applications with ~800 unique users per day it works perfectly.
28
+ Gem is production-ready. At least on my 2 applications with ~800 unique users per day it works perfectly.
27
29
 
28
30
  Just don't forget to protect performance dashboard with http basic auth or check of current_user.
29
31
 
@@ -49,6 +51,9 @@ RailsPerformance.setup do |config|
49
51
  config.debug = false # currently not used>
50
52
  config.enabled = true
51
53
 
54
+ # default path where to mount gem
55
+ config.mount_at = '/rails/performance'
56
+
52
57
  # protect your Performance Dashboard with HTTP BASIC password
53
58
  config.http_basic_authentication_enabled = false
54
59
  config.http_basic_authentication_user_name = 'rails_performance'
@@ -62,12 +67,13 @@ end if defined?(RailsPerformance)
62
67
  ```
63
68
 
64
69
  ## Installation
70
+
65
71
  Add this line to your application's Gemfile:
66
72
 
67
73
  ```ruby
68
74
  gem 'rails_performance'
69
75
 
70
- # or
76
+ # or
71
77
 
72
78
  group :development, :production do
73
79
  gem 'rails_performance'
@@ -75,10 +81,19 @@ end
75
81
  ```
76
82
 
77
83
  And then execute:
84
+
78
85
  ```bash
79
86
  $ bundle
80
87
  ```
81
88
 
89
+ Create default configuration file:
90
+
91
+ ```bash
92
+ $ rails generate rails_performance:install
93
+ ```
94
+
95
+ Have a look at `config/initializers/rails_performance.rb` and adjust the configuration to your needs.
96
+
82
97
  You must also have installed Redis server, because this gem is storing data into it.
83
98
 
84
99
  After installation and configuration, start your Rails application, make a few requests, and open `https://localhost:3000/rails/performance` URL.
@@ -121,10 +136,8 @@ The idea of this gem grew from curriosity how many RPM my app receiving per day.
121
136
 
122
137
  ## TODO
123
138
 
124
- - documentation in Readme
139
+ - documentation in Readme?
125
140
  - capture stacktrace of 500 errors and show in side panel
126
- - generator for initial config
127
- - CI for tests
128
141
  - time/zone config?
129
142
  - connected charts on dashboard, when zoom, when hover?
130
143
  - ability to zoom to see requests withing specific datetime range
@@ -149,7 +162,15 @@ You are welcome to contribute. I've a big list of TODO.
149
162
  ## Big thanks to contributors
150
163
 
151
164
  - https://github.com/synth
165
+ - https://github.com/alagos
166
+ - https://github.com/klondaiker
167
+ - https://github.com/jules2689
168
+ - https://github.com/PedroAugustoRamalhoDuarte
169
+ - https://github.com/haffla
152
170
 
153
171
  ## License
154
172
 
155
173
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
174
+
175
+ [<img src="https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/more_gems.png?raw=true"
176
+ />](https://www.railsjazz.com/)
@@ -0,0 +1,21 @@
1
+ module RailsPerformance
2
+ class BaseController < ActionController::Base
3
+ layout 'rails_performance/layouts/rails_performance'
4
+
5
+ before_action :verify_access
6
+
7
+ if RailsPerformance.http_basic_authentication_enabled
8
+ http_basic_authenticate_with \
9
+ name: RailsPerformance.http_basic_authentication_user_name,
10
+ password: RailsPerformance.http_basic_authentication_password
11
+ end
12
+
13
+ private
14
+
15
+ def verify_access
16
+ result = RailsPerformance.verify_access_proc.call(self)
17
+ redirect_to('/', error: 'Access Denied', status: 401) unless result
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,91 @@
1
+ require_relative './base_controller.rb'
2
+
3
+ module RailsPerformance
4
+ class RailsPerformanceController < RailsPerformance::BaseController
5
+ include RailsPerformance::ApplicationHelper
6
+
7
+ if RailsPerformance.enabled
8
+ def index
9
+ @datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
10
+ db = @datasource.db
11
+
12
+ @throughput_report = RP::Reports::ThroughputReport.new(db)
13
+ @throughput_report_data = @throughput_report.data
14
+
15
+ @response_time_report = RP::Reports::ResponseTimeReport.new(db)
16
+ @response_time_report_data = @response_time_report.data
17
+ end
18
+
19
+ def summary
20
+ @datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
21
+ db = @datasource.db
22
+
23
+ @throughput_report = RP::Reports::ThroughputReport.new(db)
24
+ @throughput_report_data = @throughput_report.data
25
+
26
+ @response_time_report = RP::Reports::ResponseTimeReport.new(db)
27
+ @response_time_report_data = @response_time_report.data
28
+
29
+ @report = RP::Reports::BreakdownReport.new(db, title: "Requests")
30
+ @data = @report.data
31
+
32
+ respond_to do |format|
33
+ format.js {}
34
+ format.any { render plain: "Doesn't open in new window. Wait until full page load." }
35
+ end
36
+ end
37
+
38
+ def trace
39
+ @record = RP::Models::Record.find_by(request_id: params[:id])
40
+ @report = RP::Reports::TraceReport.new(request_id: params[:id])
41
+ @data = @report.data
42
+ respond_to do |format|
43
+ format.js {}
44
+ format.any { render plain: "Doesn't open in new window. Wait until full page load." }
45
+ end
46
+ end
47
+
48
+ def crashes
49
+ @datasource = RP::DataSource.new(**prepare_query({status_eq: 500}), type: :requests, klass: RP::Models::Record)
50
+ db = @datasource.db
51
+ @report = RP::Reports::CrashReport.new(db)
52
+ @data = @report.data
53
+ end
54
+
55
+ def requests
56
+ @datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
57
+ db = @datasource.db
58
+ @report = RP::Reports::RequestsReport.new(db, group: :controller_action_format, sort: :count)
59
+ @data = @report.data
60
+ end
61
+
62
+ def recent
63
+ @datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
64
+ db = @datasource.db
65
+ @report = RP::Reports::RecentRequestsReport.new(db)
66
+ @data = @report.data
67
+ end
68
+
69
+ def jobs
70
+ @datasource = RP::DataSource.new(**prepare_query, type: :jobs, klass: RP::Models::JobRecord)
71
+ db = @datasource.db
72
+
73
+ @throughput_report = RP::Reports::ThroughputReport.new(db)
74
+ @throughput_report_data = @throughput_report.data
75
+
76
+ @response_time_report = RP::Reports::ResponseTimeReport.new(db)
77
+ @response_time_report_data = @response_time_report.data
78
+
79
+ @recent_report = RP::Reports::RecentRequestsReport.new(db)
80
+ @recent_report_data = @recent_report.data(:jobs)
81
+ end
82
+
83
+ private
84
+
85
+ def prepare_query(query = params)
86
+ RP::Rails::QueryBuilder.compose_from(query)
87
+ end
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,116 @@
1
+ module RailsPerformance
2
+ module ApplicationHelper
3
+ def round_it(value)
4
+ return nil unless value
5
+ return value if value.is_a?(Integer)
6
+
7
+ value.nan? ? nil : value.round(1)
8
+ end
9
+
10
+ def duraction_alert_class(duration_str)
11
+ if duration_str.to_s =~ /(\d+.?\d+?)/
12
+ duration = $1.to_f
13
+ if duration >= 500
14
+ 'has-background-danger has-text-white-bis'
15
+ elsif duration >= 200
16
+ 'has-background-warning has-text-black-ter'
17
+ else
18
+ 'has-background-success has-text-white-bis'
19
+ end
20
+ else
21
+ 'has-background-light'
22
+ end
23
+ end
24
+
25
+ def extract_duration(str)
26
+ if (str =~ /Duration: (\d+.?\d+?ms)/i)
27
+ $1
28
+ else
29
+ '-'
30
+ end
31
+ end
32
+
33
+ def ms(value)
34
+ result = round_it(value)
35
+ result && result != 0 ? "#{result} ms" : '-'
36
+ end
37
+
38
+ def short_path(path, length: 60)
39
+ content_tag :span, title: path do
40
+ truncate(path, length: length)
41
+ end
42
+ end
43
+
44
+ def link_to_path(e)
45
+ if e[:method] == 'GET'
46
+ link_to(short_path(e[:path]), e[:path], target: '_blank')
47
+ else
48
+ short_path(e[:path])
49
+ end
50
+ end
51
+
52
+ def report_name(h)
53
+ h.except(:on).collect do |k, v|
54
+ next if v.blank?
55
+
56
+ %Q{
57
+ <div class="control">
58
+ <span class="tags has-addons">
59
+ <span class="tag">#{k}</span>
60
+ <span class="tag is-info is-light">#{v}</span>
61
+ </span>
62
+ </div>}
63
+ end.compact.join.html_safe
64
+ end
65
+
66
+ def status_tag(status)
67
+ klass = case status.to_s
68
+ when /^5/
69
+ "tag is-danger"
70
+ when /^4/
71
+ "tag is-warning"
72
+ when /^3/
73
+ "tag is-info"
74
+ when /^2/
75
+ "tag is-success"
76
+ else
77
+ nil
78
+ end
79
+ content_tag(:span, class: klass) do
80
+ status
81
+ end
82
+ end
83
+
84
+ def icon(name)
85
+ # https://www.iconfinder.com/iconsets/vivid
86
+ raw File.read(File.expand_path(File.dirname(__FILE__) + "/../../assets/images/#{name}.svg"))
87
+ end
88
+
89
+ def insert_css_file(file)
90
+ raw "<style>#{raw File.read File.expand_path(File.dirname(__FILE__) + "/../../views/rails_performance/stylesheets/#{file}")}</style>"
91
+ end
92
+
93
+ def insert_js_file(file)
94
+ raw "<script>#{raw File.read File.expand_path(File.dirname(__FILE__) + "/../../views/rails_performance/javascripts/#{file}")}</script>"
95
+ end
96
+
97
+ def format_datetime(e)
98
+ e.strftime("%Y-%m-%d %H:%M:%S")
99
+ end
100
+
101
+ def active?(section)
102
+ case section
103
+ when :dashboard
104
+ "is-active" if controller_name == "rails_performance" && action_name == "index"
105
+ when :crashes
106
+ "is-active" if controller_name == "rails_performance" && action_name == "crashes"
107
+ when :requests
108
+ "is-active" if controller_name == "rails_performance" && action_name == "requests"
109
+ when :recent
110
+ "is-active" if controller_name == "rails_performance" && action_name == "recent"
111
+ when :jobs
112
+ "is-active" if controller_name == "rails_performance" && action_name == "jobs"
113
+ end
114
+ end
115
+ end
116
+ end
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>Rails Performance</title>
7
7
  <%= csrf_meta_tags %>
8
- <%= csp_meta_tag if ::Rails::VERSION::MAJOR.to_i >= 5 %>
8
+ <%= csp_meta_tag if ::Rails::VERSION::STRING.to_f >= 5.2 %>
9
9
  <%= render '/rails_performance/stylesheets/stylesheets' %>
10
10
  <link rel="shortcut icon" href="/favicon.ico">
11
11
  </head>
@@ -29,4 +29,4 @@
29
29
  <%= yield :on_load %>
30
30
 
31
31
  </body>
32
- </html>
32
+ </html>
@@ -26,7 +26,7 @@
26
26
  <% c, a = groups[0].split("#") %>
27
27
  <tr>
28
28
  <td><%= link_to groups[0], rails_performance.rails_performance_summary_path({controller_eq: c, action_eq: a}), remote: true %></td>
29
- <td><%= link_to groups[1]&.upcase, rails_performance.rails_performance_summary_path({controller_eq: c, action_eq: a, format_eq: groups[1]}), remote: true %></td>
29
+ <td><%= link_to groups[1].try(:upcase), rails_performance.rails_performance_summary_path({controller_eq: c, action_eq: a, format_eq: groups[1]}), remote: true %></td>
30
30
  <td><%= e[:count] %></td>
31
31
  <td class="nowrap"><%= ms e[:duration_average] %></td>
32
32
  <td class="nowrap"><%= ms e[:view_runtime_average] %></td>
@@ -1,5 +1,5 @@
1
1
  window.panel.header.html(window.panel.close + '<%= j report_name(@datasource.q) %>');
2
- window.panel.content.html("<%= j render '/rails_performance/summary' %>");
2
+ window.panel.content.html("<%= j render '/rails_performance/rails_performance/summary' %>");
3
3
 
4
4
  var data1 = <%= raw @throughput_report_data.to_json %>;
5
5
  showTIRChart('throughput_report_chart_mini', data1, ' rpm', 'RPM');
@@ -4,6 +4,6 @@
4
4
  window.panel.header.html(window.panel.close);
5
5
  <% end %>
6
6
 
7
- window.panel.content.html("<%= j render '/rails_performance/trace' %>");
7
+ window.panel.content.html("<%= j render '/rails_performance/rails_performance/trace' %>");
8
8
 
9
9
  showPanel();
data/config/routes.rb CHANGED
@@ -13,9 +13,9 @@ end
13
13
 
14
14
  Rails.application.routes.draw do
15
15
  begin
16
- mount RailsPerformance::Engine => '/rails/performance', as: 'rails_performance'
16
+ mount RailsPerformance::Engine => RailsPerformance.mount_at, as: 'rails_performance'
17
17
  rescue ArgumentError
18
18
  # already added
19
- # this cod exist here because engine not includes routing automatically
19
+ # this code exist here because engine not includes routing automatically
20
20
  end
21
21
  end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generates initial config for rails_performance gem
3
+
4
+ Example:
5
+ bin/rails generate rails_performance:install
6
+
7
+ This will create:
8
+ config/initializers/rails_performance.rb
@@ -0,0 +1,8 @@
1
+ class RailsPerformance::InstallGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('templates', __dir__)
3
+ desc "Generates initial config for rails_performance gem"
4
+
5
+ def copy_initializer_file
6
+ copy_file "initializer.rb", "config/initializers/rails_performance.rb"
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ RailsPerformance.setup do |config|
2
+ config.redis = Redis::Namespace.new("#{Rails.env}-rails-performance", redis: Redis.new)
3
+ config.duration = 4.hours
4
+
5
+ config.debug = false # currently not used>
6
+ config.enabled = true
7
+
8
+ # default path where to mount gem
9
+ config.mount_at = '/rails/performance'
10
+
11
+ # protect your Performance Dashboard with HTTP BASIC password
12
+ config.http_basic_authentication_enabled = false
13
+ config.http_basic_authentication_user_name = 'rails_performance'
14
+ config.http_basic_authentication_password = 'password12'
15
+
16
+ # if you need an additional rules to check user permissions
17
+ config.verify_access_proc = proc { |controller| true }
18
+ # for example when you have `current_user`
19
+ # config.verify_access_proc = proc { |controller| controller.current_user && controller.current_user.admin? }
20
+
21
+ # You can ignore endpoints with Rails standard notation controller#action
22
+ # config.ignored_endpoints = ['HomeController#contact']
23
+ end if defined?(RailsPerformance)
@@ -34,6 +34,10 @@ module RailsPerformance
34
34
  mattr_accessor :enabled
35
35
  @@enabled = true
36
36
 
37
+ # default path where to mount gem
38
+ mattr_accessor :mount_at
39
+ @@mount_at = "/rails/performance"
40
+
37
41
  # Enable http basic authentication
38
42
  mattr_accessor :http_basic_authentication_enabled
39
43
  @@http_basic_authentication_enabled = false
@@ -50,6 +54,12 @@ module RailsPerformance
50
54
  mattr_accessor :verify_access_proc
51
55
  @@verify_access_proc = proc { |controller| true }
52
56
 
57
+ mattr_reader :ignored_endpoints
58
+ def RailsPerformance.ignored_endpoints=(endpoints)
59
+ @@ignored_endpoints = Set.new(endpoints)
60
+ end
61
+ @@ignored_endpoints = []
62
+
53
63
  def self.setup
54
64
  yield(self)
55
65
  end
@@ -58,4 +68,4 @@ end
58
68
 
59
69
  RP = RailsPerformance
60
70
 
61
- require "rails_performance/engine"
71
+ require "rails_performance/engine"
@@ -1,31 +1,22 @@
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'
4
5
 
5
6
  module RailsPerformance
6
7
  class Engine < ::Rails::Engine
8
+ isolate_namespace RailsPerformance
7
9
 
8
- if RailsPerformance.try(:enabled) # for rails c
10
+ initializer "rails_performance.middleware" do |app|
11
+ next unless RailsPerformance.enabled
9
12
 
10
13
  if ::Rails::VERSION::MAJOR.to_i >= 5
11
- config.app_middleware.insert_after ActionDispatch::Executor, RailsPerformance::Rails::Middleware
14
+ app.middleware.insert_after ActionDispatch::Executor, RailsPerformance::Rails::Middleware
12
15
  else
13
- config.app_middleware.insert_after ActionDispatch::Static, RailsPerformance::Rails::Middleware
16
+ app.middleware.insert_after ActionDispatch::Static, RailsPerformance::Rails::Middleware
14
17
  end
15
18
 
16
- initializer :configure_metrics, after: :initialize_logger do
17
- ActiveSupport::Notifications.subscribe(
18
- "process_action.action_controller",
19
- RailsPerformance::Instrument::MetricsCollector.new
20
- )
21
-
22
- config.after_initialize do |app|
23
- ActionView::LogSubscriber.send :prepend, RailsPerformance::Extensions::View
24
- ActiveRecord::LogSubscriber.send :prepend, RailsPerformance::Extensions::Db
25
- end
26
- end
27
-
28
- if const_defined?("Sidekiq")
19
+ if defined?(Sidekiq)
29
20
  require_relative './gems/sidekiq.rb'
30
21
  Sidekiq.configure_server do |config|
31
22
  config.server_middleware do |chain|
@@ -33,8 +24,22 @@ module RailsPerformance
33
24
  end
34
25
  end
35
26
  end
27
+ end
28
+
29
+ initializer :configure_metrics, after: :initialize_logger do
30
+ next unless RailsPerformance.enabled
36
31
 
32
+ ActiveSupport::Notifications.subscribe(
33
+ "process_action.action_controller",
34
+ RailsPerformance::Instrument::MetricsCollector.new
35
+ )
37
36
  end
38
37
 
38
+ config.after_initialize do
39
+ next unless RailsPerformance.enabled
40
+
41
+ ActionView::LogSubscriber.send :prepend, RailsPerformance::Extensions::View
42
+ ActiveRecord::LogSubscriber.send :prepend, RailsPerformance::Extensions::Db
43
+ end
39
44
  end
40
45
  end
@@ -22,6 +22,7 @@ module RailsPerformance
22
22
  rescue Exception => ex
23
23
  data[:status] = "exception"
24
24
  data[:message] = ex.message
25
+ raise ex
25
26
  ensure
26
27
  # store in ms instead of seconds
27
28
  data[:duration] = (Time.now - now) * 1000
@@ -18,7 +18,8 @@ module RailsPerformance
18
18
  def call(event_name, started, finished, event_id, payload)
19
19
  event = ActiveSupport::Notifications::Event.new(event_name, started, finished, event_id, payload)
20
20
 
21
- return if event.payload[:path] =~ /^\/rails\/performance/
21
+ return if %r{#{RailsPerformance.mount_at}}.match? event.payload[:path]
22
+ return if RailsPerformance.ignored_endpoints.include? "#{event.payload[:controller]}##{event.payload[:action]}"
22
23
 
23
24
  record = {
24
25
  controller: event.payload[:controller],
@@ -38,4 +39,4 @@ module RailsPerformance
38
39
  end
39
40
  end
40
41
  end
41
- end
42
+ end
@@ -60,8 +60,7 @@ module RailsPerformance
60
60
  def Utils.save_to_redis(key, value, expire = RP.duration.to_i)
61
61
  # puts " [SAVE] key ---> #{key}\n"
62
62
  # puts " value ---> #{value.to_json}\n\n"
63
- RP.redis.set(key, value.to_json)
64
- RP.redis.expire(key, expire.to_i)
63
+ RP.redis.set(key, value.to_json, ex: expire.to_i)
65
64
  end
66
65
 
67
66
  end
@@ -1,3 +1,3 @@
1
1
  module RailsPerformance
2
- VERSION = '0.9.4'
2
+ VERSION = '0.9.9'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_performance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 0.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-19 00:00:00.000000000 Z
11
+ date: 2021-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: mimemagic
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  description: 3rd party dependency-free solution how to monitor performance of your
98
112
  Rails applications.
99
113
  email:
@@ -115,14 +129,10 @@ files:
115
129
  - app/assets/images/import.svg
116
130
  - app/assets/images/menu.svg
117
131
  - app/assets/images/stat.svg
118
- - app/controllers/base_controller.rb
119
- - app/controllers/rails_performance_controller.rb
120
- - app/helpers/rails_performance_helper.rb
132
+ - app/controllers/rails_performance/base_controller.rb
133
+ - app/controllers/rails_performance/rails_performance_controller.rb
134
+ - app/helpers/rails_performance/application_helper.rb
121
135
  - app/views/rails_performance/_panel.html.erb
122
- - app/views/rails_performance/_summary.html.erb
123
- - app/views/rails_performance/_trace.html.erb
124
- - app/views/rails_performance/crashes.html.erb
125
- - app/views/rails_performance/index.html.erb
126
136
  - app/views/rails_performance/javascripts/_javascripts.html.erb
127
137
  - app/views/rails_performance/javascripts/app.js
128
138
  - app/views/rails_performance/javascripts/jquery-3.4.1.min.js
@@ -130,18 +140,25 @@ files:
130
140
  - app/views/rails_performance/javascripts/rails.js
131
141
  - app/views/rails_performance/javascripts/stupidtable.min.js
132
142
  - app/views/rails_performance/javascripts/table.js
133
- - app/views/rails_performance/jobs.html.erb
134
143
  - app/views/rails_performance/layouts/rails_performance.html.erb
135
- - app/views/rails_performance/recent.html.erb
136
- - app/views/rails_performance/requests.html.erb
144
+ - app/views/rails_performance/rails_performance/_summary.html.erb
145
+ - app/views/rails_performance/rails_performance/_trace.html.erb
146
+ - app/views/rails_performance/rails_performance/crashes.html.erb
147
+ - app/views/rails_performance/rails_performance/index.html.erb
148
+ - app/views/rails_performance/rails_performance/jobs.html.erb
149
+ - app/views/rails_performance/rails_performance/recent.html.erb
150
+ - app/views/rails_performance/rails_performance/requests.html.erb
151
+ - app/views/rails_performance/rails_performance/summary.js.erb
152
+ - app/views/rails_performance/rails_performance/trace.js.erb
137
153
  - app/views/rails_performance/shared/_header.html.erb
138
154
  - app/views/rails_performance/stylesheets/_stylesheets.html.erb
139
155
  - app/views/rails_performance/stylesheets/bulma.min.css
140
156
  - app/views/rails_performance/stylesheets/panel.css
141
157
  - app/views/rails_performance/stylesheets/style.css
142
- - app/views/rails_performance/summary.js.erb
143
- - app/views/rails_performance/trace.js.erb
144
158
  - config/routes.rb
159
+ - lib/generators/rails_performance/install/USAGE
160
+ - lib/generators/rails_performance/install/install_generator.rb
161
+ - lib/generators/rails_performance/install/templates/initializer.rb
145
162
  - lib/rails_performance.rb
146
163
  - lib/rails_performance/data_source.rb
147
164
  - lib/rails_performance/engine.rb
@@ -1,19 +0,0 @@
1
- class BaseController < ActionController::Base
2
- layout 'rails_performance/layouts/rails_performance'
3
-
4
- before_action :verify_access
5
-
6
- if RailsPerformance.http_basic_authentication_enabled
7
- http_basic_authenticate_with \
8
- name: RailsPerformance.http_basic_authentication_user_name,
9
- password: RailsPerformance.http_basic_authentication_password
10
- end
11
-
12
- private
13
-
14
- def verify_access
15
- result = RailsPerformance.verify_access_proc.call(self)
16
- redirect_to('/', error: 'Access Denied', status: 401) unless result
17
- end
18
-
19
- end
@@ -1,88 +0,0 @@
1
- require_relative './base_controller.rb'
2
-
3
- class RailsPerformanceController < BaseController
4
-
5
- if RailsPerformance.enabled
6
- def index
7
- @datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
8
- db = @datasource.db
9
-
10
- @throughput_report = RP::Reports::ThroughputReport.new(db)
11
- @throughput_report_data = @throughput_report.data
12
-
13
- @response_time_report = RP::Reports::ResponseTimeReport.new(db)
14
- @response_time_report_data = @response_time_report.data
15
- end
16
-
17
- def summary
18
- @datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
19
- db = @datasource.db
20
-
21
- @throughput_report = RP::Reports::ThroughputReport.new(db)
22
- @throughput_report_data = @throughput_report.data
23
-
24
- @response_time_report = RP::Reports::ResponseTimeReport.new(db)
25
- @response_time_report_data = @response_time_report.data
26
-
27
- @report = RP::Reports::BreakdownReport.new(db, title: "Requests")
28
- @data = @report.data
29
-
30
- respond_to do |format|
31
- format.js {}
32
- format.any { render plain: "Doesn't open in new window. Wait until full page load." }
33
- end
34
- end
35
-
36
- def trace
37
- @record = RP::Models::Record.find_by(request_id: params[:id])
38
- @report = RP::Reports::TraceReport.new(request_id: params[:id])
39
- @data = @report.data
40
- respond_to do |format|
41
- format.js {}
42
- format.any { render plain: "Doesn't open in new window. Wait until full page load." }
43
- end
44
- end
45
-
46
- def crashes
47
- @datasource = RP::DataSource.new(**prepare_query({status_eq: 500}), type: :requests, klass: RP::Models::Record)
48
- db = @datasource.db
49
- @report = RP::Reports::CrashReport.new(db)
50
- @data = @report.data
51
- end
52
-
53
- def requests
54
- @datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
55
- db = @datasource.db
56
- @report = RP::Reports::RequestsReport.new(db, group: :controller_action_format, sort: :count)
57
- @data = @report.data
58
- end
59
-
60
- def recent
61
- @datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
62
- db = @datasource.db
63
- @report = RP::Reports::RecentRequestsReport.new(db)
64
- @data = @report.data
65
- end
66
-
67
- def jobs
68
- @datasource = RP::DataSource.new(**prepare_query, type: :jobs, klass: RP::Models::JobRecord)
69
- db = @datasource.db
70
-
71
- @throughput_report = RP::Reports::ThroughputReport.new(db)
72
- @throughput_report_data = @throughput_report.data
73
-
74
- @response_time_report = RP::Reports::ResponseTimeReport.new(db)
75
- @response_time_report_data = @response_time_report.data
76
-
77
- @recent_report = RP::Reports::RecentRequestsReport.new(db)
78
- @recent_report_data = @recent_report.data(:jobs)
79
- end
80
-
81
- private
82
-
83
- def prepare_query(query = params)
84
- RP::Rails::QueryBuilder.compose_from(query)
85
- end
86
- end
87
-
88
- end
@@ -1,114 +0,0 @@
1
- module RailsPerformanceHelper
2
- def round_it(value)
3
- return nil unless value
4
- return value if value.is_a?(Integer)
5
-
6
- value.nan? ? nil : value.round(1)
7
- end
8
-
9
- def duraction_alert_class(duration_str)
10
- if duration_str.to_s =~ /(\d+.?\d+?)/
11
- duration = $1.to_f
12
- if duration >= 500
13
- 'has-background-danger has-text-white-bis'
14
- elsif duration >= 200
15
- 'has-background-warning has-text-black-ter'
16
- else
17
- 'has-background-success has-text-white-bis'
18
- end
19
- else
20
- 'has-background-light'
21
- end
22
- end
23
-
24
- def extract_duration(str)
25
- if (str =~ /Duration: (\d+.?\d+?ms)/i)
26
- $1
27
- else
28
- '-'
29
- end
30
- end
31
-
32
- def ms(value)
33
- result = round_it(value)
34
- result && result != 0 ? "#{result} ms" : '-'
35
- end
36
-
37
- def short_path(path, length: 60)
38
- content_tag :span, title: path do
39
- truncate(path, length: length)
40
- end
41
- end
42
-
43
- def link_to_path(e)
44
- if e[:method] == 'GET'
45
- link_to(short_path(e[:path]), e[:path], target: '_blank')
46
- else
47
- short_path(e[:path])
48
- end
49
- end
50
-
51
- def report_name(h)
52
- h.except(:on).collect do |k, v|
53
- next if v.blank?
54
-
55
- %Q{
56
- <div class="control">
57
- <span class="tags has-addons">
58
- <span class="tag">#{k}</span>
59
- <span class="tag is-info is-light">#{v}</span>
60
- </span>
61
- </div>}
62
- end.compact.join.html_safe
63
- end
64
-
65
- def status_tag(status)
66
- klass = case status.to_s
67
- when /^5/
68
- "tag is-danger"
69
- when /^4/
70
- "tag is-warning"
71
- when /^3/
72
- "tag is-info"
73
- when /^2/
74
- "tag is-success"
75
- else
76
- nil
77
- end
78
- content_tag(:span, class: klass) do
79
- status
80
- end
81
- end
82
-
83
- def icon(name)
84
- # https://www.iconfinder.com/iconsets/vivid
85
- raw File.read(File.expand_path(File.dirname(__FILE__) + "/../assets/images/#{name}.svg"))
86
- end
87
-
88
- def insert_css_file(file)
89
- raw "<style>#{raw File.read File.expand_path(File.dirname(__FILE__) + "/../views/rails_performance/stylesheets/#{file}")}</style>"
90
- end
91
-
92
- def insert_js_file(file)
93
- raw "<script>#{raw File.read File.expand_path(File.dirname(__FILE__) + "/../views/rails_performance/javascripts/#{file}")}</script>"
94
- end
95
-
96
- def format_datetime(e)
97
- e.strftime("%Y-%m-%d %H:%M:%S")
98
- end
99
-
100
- def active?(section)
101
- case section
102
- when :dashboard
103
- "is-active" if controller_name == "rails_performance" && action_name == "index"
104
- when :crashes
105
- "is-active" if controller_name == "rails_performance" && action_name == "crashes"
106
- when :requests
107
- "is-active" if controller_name == "rails_performance" && action_name == "requests"
108
- when :recent
109
- "is-active" if controller_name == "rails_performance" && action_name == "recent"
110
- when :jobs
111
- "is-active" if controller_name == "rails_performance" && action_name == "jobs"
112
- end
113
- end
114
- end