rails_performance 0.9.4 → 0.9.9

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 (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