rails_performance 0.9.3 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -4
  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} +8 -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 +2 -0
  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/rails/middleware.rb +4 -0
  25. data/lib/rails_performance/utils.rb +1 -2
  26. data/lib/rails_performance/version.rb +1 -1
  27. metadata +17 -14
  28. data/app/controllers/base_controller.rb +0 -19
  29. data/app/controllers/rails_performance_controller.rb +0 -88
  30. data/app/helpers/rails_performance_helper.rb +0 -114
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7083cafce2bc5cd518d4569636fbf29b6f3b9d6988b29934f9b20fd78409ab2b
4
- data.tar.gz: afa5ae508905a5ecd70a61502aae297f7b54e9657055e04de5aae3175a670fef
3
+ metadata.gz: 2fd36bc442cc4c70eb58e007e07df73a44bf7ce745de9d4e50b94d8f41bfa050
4
+ data.tar.gz: 590694fef0143bf1080ef4eb224f6c6beb657728c53d0a13c825b8012fa7ca04
5
5
  SHA512:
6
- metadata.gz: 2a3e8737e2dcf02ee5816e26c518d160b76e4eeb24ba029be79a2a8070df327cd1f18051ce2310a6d2888de17f2b8b1e6186664994217d13c87ccfce8b6d5b58
7
- data.tar.gz: 761c2d6f4f4be425f7c59acb5eed4b7df31d42c0deebf6320e9893b4b97fbfba3f46405ad21e04591896503809ce998d5042e2ce6a8f9302141e30517c264c39
6
+ metadata.gz: b49fda7d3eb4081a963c87417b1033a4a204f52b10bdb544a8984ab7367d77ebe38421e2447c68e45a4110d653ee27dd772a8ec5e6ac5ea80e7954e3210295d6
7
+ data.tar.gz: a649c5987684c72c3b6ded1847478a3bf4ace015054a4e2cbee293f33aaee3f3a442acefbcc59eeb9e9ae68cfd0ca95032c7d353ec38978bee664c4795c2baae
data/README.md CHANGED
@@ -1,6 +1,7 @@
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)
4
5
 
5
6
  A self-hosted tool to monitor the performance of your Ruby on Rails application.
6
7
 
@@ -17,12 +18,13 @@ It allows you to track:
17
18
  - SQL queries, rendering logs in "Recent Requests" section
18
19
  - simple 500-crashes reports
19
20
  - track Sidekiq jobs performance
21
+ - works with Rails 4.2+ (and probably 4.1, 4.0 too) and Ruby 2.2+
20
22
 
21
23
  All data are stored in `local` Redis and not sent to any 3rd party servers.
22
24
 
23
25
  ## Production
24
26
 
25
- Gem is production-ready. At least on my 2 applications with ~800 unique users per day it works perfectly.
27
+ Gem is production-ready. At least on my 2 applications with ~800 unique users per day it works perfectly.
26
28
 
27
29
  Just don't forget to protect performance dashboard with http basic auth or check of current_user.
28
30
 
@@ -48,6 +50,9 @@ RailsPerformance.setup do |config|
48
50
  config.debug = false # currently not used>
49
51
  config.enabled = true
50
52
 
53
+ # default path where to mount gem
54
+ config.mount_at = '/rails/performance'
55
+
51
56
  # protect your Performance Dashboard with HTTP BASIC password
52
57
  config.http_basic_authentication_enabled = false
53
58
  config.http_basic_authentication_user_name = 'rails_performance'
@@ -61,12 +66,13 @@ end if defined?(RailsPerformance)
61
66
  ```
62
67
 
63
68
  ## Installation
69
+
64
70
  Add this line to your application's Gemfile:
65
71
 
66
72
  ```ruby
67
73
  gem 'rails_performance'
68
74
 
69
- # or
75
+ # or
70
76
 
71
77
  group :development, :production do
72
78
  gem 'rails_performance'
@@ -74,10 +80,19 @@ end
74
80
  ```
75
81
 
76
82
  And then execute:
83
+
77
84
  ```bash
78
85
  $ bundle
79
86
  ```
80
87
 
88
+ Create default configuration file:
89
+
90
+ ```bash
91
+ $ rails generate rails_performance:install
92
+ ```
93
+
94
+ Have a look at `config/initializers/rails_performance.rb` and adjust the configuration to your needs.
95
+
81
96
  You must also have installed Redis server, because this gem is storing data into it.
82
97
 
83
98
  After installation and configuration, start your Rails application, make a few requests, and open `https://localhost:3000/rails/performance` URL.
@@ -122,7 +137,6 @@ The idea of this gem grew from curriosity how many RPM my app receiving per day.
122
137
 
123
138
  - documentation in Readme
124
139
  - capture stacktrace of 500 errors and show in side panel
125
- - generator for initial config
126
140
  - CI for tests
127
141
  - time/zone config?
128
142
  - connected charts on dashboard, when zoom, when hover?
@@ -148,7 +162,15 @@ You are welcome to contribute. I've a big list of TODO.
148
162
  ## Big thanks to contributors
149
163
 
150
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
151
170
 
152
171
  ## License
153
172
 
154
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>
@@ -5,6 +5,7 @@
5
5
  <table class="table is-fullwidth is-hoverable is-narrow">
6
6
  <thead>
7
7
  <tr>
8
+ <th data-sort="string"></th>
8
9
  <th data-sort="string">Datetime</th>
9
10
  <th data-sort="string">Controller#action</th>
10
11
  <th data-sort="string">Method</th>
@@ -25,6 +26,13 @@
25
26
  <% end %>
26
27
  <% @data.each do |e| %>
27
28
  <tr>
29
+ <td>
30
+ <% if e[:request_id].present? %>
31
+ <%= link_to rails_performance.rails_performance_trace_path(id: e[:request_id]), remote: true do %>
32
+ <span class="stats_icon_max"><%= icon 'activity' %></span>
33
+ <% end %>
34
+ <% end %>
35
+ </td>
28
36
  <td><%= format_datetime e[:datetime] %></td>
29
37
  <td><%= link_to e[:controller] + '#' + e[:action], rails_performance.rails_performance_summary_path({controller_eq: e[:controller], action_eq: e[:action]}), remote: true %></td>
30
38
  <td><%= e[:method] %></td>
@@ -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,9 +1,11 @@
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
10
  if RailsPerformance.try(:enabled) # for rails c
9
11
 
@@ -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
@@ -6,6 +6,10 @@ module RailsPerformance
6
6
  end
7
7
 
8
8
  def call(env)
9
+ dup.call!(env)
10
+ end
11
+
12
+ def call!(env)
9
13
  @status, @headers, @response = @app.call(env)
10
14
 
11
15
  #t = Time.now
@@ -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.3'
2
+ VERSION = '0.9.8'
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.3
4
+ version: 0.9.8
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-06-03 00:00:00.000000000 Z
11
+ date: 2021-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -115,14 +115,10 @@ files:
115
115
  - app/assets/images/import.svg
116
116
  - app/assets/images/menu.svg
117
117
  - 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
118
+ - app/controllers/rails_performance/base_controller.rb
119
+ - app/controllers/rails_performance/rails_performance_controller.rb
120
+ - app/helpers/rails_performance/application_helper.rb
121
121
  - 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
122
  - app/views/rails_performance/javascripts/_javascripts.html.erb
127
123
  - app/views/rails_performance/javascripts/app.js
128
124
  - app/views/rails_performance/javascripts/jquery-3.4.1.min.js
@@ -130,18 +126,25 @@ files:
130
126
  - app/views/rails_performance/javascripts/rails.js
131
127
  - app/views/rails_performance/javascripts/stupidtable.min.js
132
128
  - app/views/rails_performance/javascripts/table.js
133
- - app/views/rails_performance/jobs.html.erb
134
129
  - 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
130
+ - app/views/rails_performance/rails_performance/_summary.html.erb
131
+ - app/views/rails_performance/rails_performance/_trace.html.erb
132
+ - app/views/rails_performance/rails_performance/crashes.html.erb
133
+ - app/views/rails_performance/rails_performance/index.html.erb
134
+ - app/views/rails_performance/rails_performance/jobs.html.erb
135
+ - app/views/rails_performance/rails_performance/recent.html.erb
136
+ - app/views/rails_performance/rails_performance/requests.html.erb
137
+ - app/views/rails_performance/rails_performance/summary.js.erb
138
+ - app/views/rails_performance/rails_performance/trace.js.erb
137
139
  - app/views/rails_performance/shared/_header.html.erb
138
140
  - app/views/rails_performance/stylesheets/_stylesheets.html.erb
139
141
  - app/views/rails_performance/stylesheets/bulma.min.css
140
142
  - app/views/rails_performance/stylesheets/panel.css
141
143
  - app/views/rails_performance/stylesheets/style.css
142
- - app/views/rails_performance/summary.js.erb
143
- - app/views/rails_performance/trace.js.erb
144
144
  - config/routes.rb
145
+ - lib/generators/rails_performance/install/USAGE
146
+ - lib/generators/rails_performance/install/install_generator.rb
147
+ - lib/generators/rails_performance/install/templates/initializer.rb
145
148
  - lib/rails_performance.rb
146
149
  - lib/rails_performance/data_source.rb
147
150
  - 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