rails_performance 0.9.0.1 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +39 -5
  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/javascripts/app.js +3 -3
  7. data/app/views/rails_performance/layouts/rails_performance.html.erb +1 -1
  8. data/app/views/rails_performance/{_summary.html.erb → rails_performance/_summary.html.erb} +0 -0
  9. data/app/views/rails_performance/{_trace.html.erb → rails_performance/_trace.html.erb} +0 -0
  10. data/app/views/rails_performance/{crashes.html.erb → rails_performance/crashes.html.erb} +0 -0
  11. data/app/views/rails_performance/{index.html.erb → rails_performance/index.html.erb} +1 -1
  12. data/app/views/rails_performance/rails_performance/jobs.html.erb +73 -0
  13. data/app/views/rails_performance/{recent.html.erb → rails_performance/recent.html.erb} +8 -1
  14. data/app/views/rails_performance/{requests.html.erb → rails_performance/requests.html.erb} +0 -0
  15. data/app/views/rails_performance/{summary.js.erb → rails_performance/summary.js.erb} +2 -2
  16. data/app/views/rails_performance/{trace.js.erb → rails_performance/trace.js.erb} +1 -1
  17. data/app/views/rails_performance/shared/_header.html.erb +3 -0
  18. data/config/routes.rb +2 -0
  19. data/lib/rails_performance.rb +2 -0
  20. data/lib/rails_performance/data_source.rb +27 -20
  21. data/lib/rails_performance/engine.rb +14 -1
  22. data/lib/rails_performance/gems/sidekiq.rb +35 -0
  23. data/lib/rails_performance/models/base_record.rb +24 -0
  24. data/lib/rails_performance/models/job_record.rb +48 -0
  25. data/lib/rails_performance/models/record.rb +2 -17
  26. data/lib/rails_performance/rails/middleware.rb +4 -0
  27. data/lib/rails_performance/reports/recent_requests_report.rb +37 -14
  28. data/lib/rails_performance/utils.rb +17 -17
  29. data/lib/rails_performance/version.rb +1 -1
  30. metadata +32 -14
  31. data/app/controllers/base_controller.rb +0 -19
  32. data/app/controllers/rails_performance_controller.rb +0 -74
  33. data/app/helpers/rails_performance_helper.rb +0 -112
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f448780915ccb27d02015c9b9b4d011ae318175c5564ae33643fcf0c0a3ecd2f
4
- data.tar.gz: cd3f09c47e39ab49a35df35ff83f0f604e76758ebea92a424e5a817e6eef7294
3
+ metadata.gz: 91dc41ef53b796c8c0755afd109fc7b7684ea9a5567828ab0e7f9e6c80cf9e79
4
+ data.tar.gz: 434e5e19a7abb0fc86b094d591623d626ab4b8a8e2ad28b70d2dfe70583e510b
5
5
  SHA512:
6
- metadata.gz: '0891876b6e5aa7826da42d1a58800b574c5d0d987c286ae836c31a493adea505cd5d407f833b681f72e66526dbbfa6da05a16b7562002f328c150c1070beee4a'
7
- data.tar.gz: eab4c06078ef53261b90f7063c54859d39157e1999f27674db5f7f7dab3c30fe2fb87fa1013502f0910a0ea36e24e46ec2d22251e3c4707220d58fb5c61370c4
6
+ metadata.gz: dffbb9eab0930f214009a8717c97a9fe82b7ea5fea22cd7a18d9a34426811d8467a19600e38e5fbdc1eb4c1aee1308b7819a8b79ff77d721907a644b9f2facea
7
+ data.tar.gz: 69e08649d416bf680f203ee801534c1c5dbedd5ee956e85cca5439db3eaa8062ca830800454eb37335059732239946f6a39ad0a1d756b7efa40864fc5ebb9dc9
data/README.md CHANGED
@@ -1,29 +1,45 @@
1
1
  # Rails Performance
2
2
 
3
- Self-hosted tool to monitor the performance of your Ruby on Rails application.
3
+ [![Build Status](https://travis-ci.org/igorkasyanchuk/rails_performance.svg?branch=master)](https://travis-ci.org/igorkasyanchuk/rails_performance)
4
+
5
+ A self-hosted tool to monitor the performance of your Ruby on Rails application.
4
6
 
5
7
  This is **simple and free alternative** to the New Relic APM, Datadog or other similar services.
6
8
 
9
+ ![Demo](docs/rails_performance.gif)
10
+
7
11
  It allows you to track:
8
12
 
9
13
  - throughput report (see amount of RPM (requests per minute))
10
14
  - an average response time
11
15
  - the slowest controllers & actions
12
16
  - total duration of time spent per request, views rendering, DB
13
- - SQL queries, rendering log in recent requests
17
+ - SQL queries, rendering logs in "Recent Requests" section
14
18
  - simple 500-crashes reports
19
+ - track Sidekiq jobs performance
20
+ - works with Rails 4.2+ (and probably 4.1, 4.0 too)
15
21
 
16
22
  All data are stored in `local` Redis and not sent to any 3rd party servers.
17
23
 
18
24
  ## Production
19
25
 
20
- Gem is production-ready. At least on my 2 applications with ~800 unique users per day it works perfect.
26
+ Gem is production-ready. At least on my 2 applications with ~800 unique users per day it works perfectly.
27
+
28
+ Just don't forget to protect performance dashboard with http basic auth or check of current_user.
21
29
 
22
30
  ## Usage
23
31
 
32
+ ```
33
+ 1. Add gem to the Gemfile (in appropriate group if needed)
34
+ 2. Start rails server
35
+ 3. Make a few requests to your app
36
+ 4. open localhost:3000/rails/performance
37
+ 5. Tune the configuration and deploy to production
38
+ ```
39
+
24
40
  Default configulation is listed below. But you can overide it.
25
41
 
26
- Create `config/initializers/rails_performance.rb`
42
+ Create `config/initializers/rails_performance.rb` in your app:
27
43
 
28
44
  ```ruby
29
45
  RailsPerformance.setup do |config|
@@ -50,6 +66,12 @@ Add this line to your application's Gemfile:
50
66
 
51
67
  ```ruby
52
68
  gem 'rails_performance'
69
+
70
+ # or
71
+
72
+ group :development, :production do
73
+ gem 'rails_performance'
74
+ end
53
75
  ```
54
76
 
55
77
  And then execute:
@@ -61,6 +83,10 @@ You must also have installed Redis server, because this gem is storing data into
61
83
 
62
84
  After installation and configuration, start your Rails application, make a few requests, and open `https://localhost:3000/rails/performance` URL.
63
85
 
86
+ ## How it works
87
+
88
+ ![Schema](docs/rails_performance.png)
89
+
64
90
  ## Limitations
65
91
 
66
92
  - it doesn't track params of POST/PUT requests
@@ -70,6 +96,8 @@ After installation and configuration, start your Rails application, make a few r
70
96
 
71
97
  ## Redis
72
98
 
99
+ Gem is using Redis. This is the only one dependency.
100
+
73
101
  All information is stored into Redis. The default expiration time is set to `config.duration` from the configuration.
74
102
 
75
103
  ## Development & Testing
@@ -79,7 +107,7 @@ Just clone the repo, setup dummy app (`rails db:migrate`).
79
107
  After this:
80
108
 
81
109
  - rails s
82
- - rake tests
110
+ - rake test
83
111
 
84
112
  Like a regular web development.
85
113
 
@@ -111,11 +139,17 @@ The idea of this gem grew from curriosity how many RPM my app receiving per day.
111
139
  - collect deprecation.rails
112
140
  - fix misspellings?
113
141
  - show "loading banner" until jquery is loaded?
142
+ - better UI on smaller screens? Recent requests when URL's are long? Truncate with CSS?
143
+ - rules for highlighting durations? how many ms to show warning, alert
114
144
 
115
145
  ## Contributing
116
146
 
117
147
  You are welcome to contribute. I've a big list of TODO.
118
148
 
149
+ ## Big thanks to contributors
150
+
151
+ - https://github.com/synth
152
+
119
153
  ## License
120
154
 
121
155
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -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
@@ -1,4 +1,4 @@
1
- function showTIRChart(div, data) {
1
+ function showTIRChart(div, data, addon, name) {
2
2
  Highcharts.chart(div, {
3
3
  time: {
4
4
  timezone: 'Europe/Kiev'
@@ -24,7 +24,7 @@ function showTIRChart(div, data) {
24
24
  if (this.y == 0) {
25
25
  return '';
26
26
  }
27
- return this.y + ' rpm';
27
+ return this.y + addon;
28
28
  }
29
29
  },
30
30
  xAxis: {
@@ -69,7 +69,7 @@ function showTIRChart(div, data) {
69
69
  },
70
70
  series: [{
71
71
  type: 'area',
72
- name: 'RPM',
72
+ name: name,
73
73
  data: data,
74
74
  fillOpacity: 0.3,
75
75
  lineWidth: 1,
@@ -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 %>
8
+ <%= csp_meta_tag if ::Rails::VERSION::MAJOR.to_i >= 5 %>
9
9
  <%= render '/rails_performance/stylesheets/stylesheets' %>
10
10
  <link rel="shortcut icon" href="/favicon.ico">
11
11
  </head>
@@ -25,7 +25,7 @@
25
25
  <% content_for :on_load do %>
26
26
  <script>
27
27
  var data1 = <%= raw @throughput_report_data.to_json %>;
28
- showTIRChart('throughput_report_chart', data1);
28
+ showTIRChart('throughput_report_chart', data1, ' rpm', 'RPM');
29
29
 
30
30
  var data2 = <%= raw @response_time_report_data.to_json %>;
31
31
  showRTChart('response_time_report_chart', data2);
@@ -0,0 +1,73 @@
1
+ <title>Number of Requests to the Application</title>
2
+
3
+ <% unless @datasource.default? %>
4
+ <%#= link_to raw("&larr; Back"), rails_performance_path, class: "back_link" %>
5
+ <% end %>
6
+
7
+ <div class="card">
8
+ <div class="card-content">
9
+ <h2 class="subtitle">Sidekiq Workers Throughput Report</h2>
10
+ <div id="throughput_report_chart" class="chart"></div>
11
+ <p class="content is-small">All workers in the application</p>
12
+ </div>
13
+ </div>
14
+
15
+ <br/>
16
+
17
+ <div class="card">
18
+ <div class="card-content">
19
+ <h2 class="subtitle">Average Execution Time</h2>
20
+ <div id="response_time_report_chart" class="chart"></div>
21
+ <p class="content is-small">All workers in the application</p>
22
+ </div>
23
+ </div>
24
+
25
+ <div class="card">
26
+ <div class="card-content">
27
+ <h2 class="subtitle">Recent Jobs (last <%= RailsPerformance::Reports::RecentRequestsReport::TIME_WINDOW / 60 %> minutes)<h2>
28
+
29
+ <table class="table is-fullwidth is-hoverable is-narrow">
30
+ <thead>
31
+ <tr>
32
+ <th data-sort="string">Datetime</th>
33
+ <th data-sort="string">Queue</th>
34
+ <th data-sort="string">Worker</th>
35
+ <th data-sort="string">Job ID</th>
36
+ <th data-sort="string">Status</th>
37
+ <th data-sort="float">Duration</th>
38
+ <th>Message</th>
39
+ <th></th>
40
+ </tr>
41
+ </thead>
42
+ <tbody>
43
+ <% if @recent_report_data.empty? %>
44
+ <tr>
45
+ <td colspan="10">Nothing to show here. Try to make a few requests in main app.</td>
46
+ </tr>
47
+ <% end %>
48
+ <% @recent_report_data.each do |e| %>
49
+ <tr>
50
+ <td><%= format_datetime e[:datetime] %></td>
51
+ <td><%= e[:queue] %></td>
52
+ <td><%= e[:worker] %></td>
53
+ <td><%= e[:jid] %></td>
54
+ <td><%= status_tag e[:status] %></td>
55
+ <td class="nowrap"><%= ms e[:duration] %></td>
56
+ <td><%= e[:message] %></td>
57
+ </tr>
58
+ <% end %>
59
+ </tbody>
60
+ </table>
61
+ </div>
62
+ </div>
63
+
64
+
65
+ <% content_for :on_load do %>
66
+ <script>
67
+ var data1 = <%= raw @throughput_report_data.to_json %>;
68
+ showTIRChart('throughput_report_chart', data1, ' jobs / minute', 'Jobs');
69
+
70
+ var data2 = <%= raw @response_time_report_data.to_json %>;
71
+ showRTChart('response_time_report_chart', data2);
72
+ </script>
73
+ <% end %>
@@ -1,11 +1,11 @@
1
1
  <div class="card">
2
2
  <div class="card-content">
3
-
4
3
  <h2 class="subtitle">Recent Requests (last <%= RailsPerformance::Reports::RecentRequestsReport::TIME_WINDOW / 60 %> minutes)<h2>
5
4
 
6
5
  <table class="table is-fullwidth is-hoverable is-narrow">
7
6
  <thead>
8
7
  <tr>
8
+ <th data-sort="string"></th>
9
9
  <th data-sort="string">Datetime</th>
10
10
  <th data-sort="string">Controller#action</th>
11
11
  <th data-sort="string">Method</th>
@@ -26,6 +26,13 @@
26
26
  <% end %>
27
27
  <% @data.each do |e| %>
28
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>
29
36
  <td><%= format_datetime e[:datetime] %></td>
30
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>
31
38
  <td><%= e[:method] %></td>
@@ -1,8 +1,8 @@
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
- showTIRChart('throughput_report_chart_mini', data1);
5
+ showTIRChart('throughput_report_chart_mini', data1, ' rpm', 'RPM');
6
6
 
7
7
  var data2 = <%= raw @response_time_report_data.to_json %>;
8
8
  showRTChart('response_time_report_chart_mini', data2);
@@ -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();
@@ -18,6 +18,9 @@
18
18
  <%= link_to 'Requests Analysis', rails_performance.rails_performance_requests_url, class: "navbar-item #{active?(:requests)}" %>
19
19
  <%= link_to '500 Errors', rails_performance.rails_performance_crashes_url, class: "navbar-item #{active?(:crashes)}" %>
20
20
  <%= link_to 'Recent Requests', rails_performance.rails_performance_recent_url, class: "navbar-item #{active?(:recent)}" %>
21
+ <% if defined?(Sidekiq) %>
22
+ <%= link_to 'Sidekiq', rails_performance.rails_performance_jobs_url, class: "navbar-item #{active?(:jobs)}" %>
23
+ <% end %>
21
24
  </div>
22
25
 
23
26
  <div class="navbar-end">
@@ -7,6 +7,8 @@ RailsPerformance::Engine.routes.draw do
7
7
 
8
8
  get '/trace/:id' => 'rails_performance#trace', as: :rails_performance_trace
9
9
  get '/summary' => 'rails_performance#summary', as: :rails_performance_summary
10
+
11
+ get '/jobs' => 'rails_performance#jobs', as: :rails_performance_jobs
10
12
  end
11
13
 
12
14
  Rails.application.routes.draw do
@@ -4,7 +4,9 @@ require_relative "./rails_performance/version.rb"
4
4
  require_relative "rails_performance/rails/query_builder.rb"
5
5
  require_relative "rails_performance/rails/middleware.rb"
6
6
  require_relative "rails_performance/data_source.rb"
7
+ require_relative "rails_performance/models/base_record.rb"
7
8
  require_relative "rails_performance/models/record.rb"
9
+ require_relative "rails_performance/models/job_record.rb"
8
10
  require_relative "rails_performance/utils.rb"
9
11
  require_relative "rails_performance/reports/base_report.rb"
10
12
  require_relative "rails_performance/reports/requests_report.rb"
@@ -1,8 +1,10 @@
1
1
  module RailsPerformance
2
2
  class DataSource
3
- attr_reader :q
3
+ attr_reader :q, :klass, :type
4
4
 
5
- def initialize(q: {})
5
+ def initialize(q: {}, type:, klass:)
6
+ @klass = klass
7
+ @type = type
6
8
  q[:on] ||= Date.today
7
9
  @q = q
8
10
 
@@ -12,7 +14,7 @@ module RailsPerformance
12
14
  def db
13
15
  result = RP::Models::Collection.new
14
16
  (RP::Utils.days + 1).times do |e|
15
- RP::DataSource.new(q: self.q.merge({ on: e.days.ago.to_date })).add_to(result)
17
+ RP::DataSource.new(q: self.q.merge({ on: e.days.ago.to_date }), klass: klass, type: type).add_to(result)
16
18
  end
17
19
  result
18
20
  end
@@ -34,41 +36,46 @@ module RailsPerformance
34
36
  return [] if keys.blank?
35
37
 
36
38
  keys.each_with_index do |key, index|
37
- yield RP::Models::Record.new(key, values[index])
39
+ yield klass.new(key, values[index])
38
40
  end
39
41
  end
40
42
 
41
43
  private
42
44
 
43
- # key = performance|
44
- # controller|HomeController|
45
- # action|index|
46
- # format|html|
47
- # status|200|
48
- # datetime|20200124T0523|
49
- # datetimei|1579861423|
50
- # method|GET|
51
- # path|/|
52
- # END
53
-
54
- def compile_query
45
+ def query
46
+ case type
47
+ when :requests
48
+ "performance|*#{compile_requests_query}*|END"
49
+ when :jobs
50
+ "jobs|*#{compile_jobs_query}*|END"
51
+ else
52
+ raise "wrong type for datasource query builder"
53
+ end
54
+ end
55
+
56
+ def compile_requests_query
55
57
  str = []
56
58
 
57
59
  str << "controller|#{q[:controller]}|" if q[:controller].present?
58
60
  str << "action|#{q[:action]}|" if q[:action].present?
59
61
  str << "format|#{q[:format]}|" if q[:format].present?
60
62
  str << "status|#{q[:status]}|" if q[:status].present?
61
-
62
63
  str << "datetime|#{q[:on].strftime('%Y%m%d')}*|" if q[:on].present?
63
-
64
64
  str << "method|#{q[:method]}|" if q[:method].present?
65
65
  str << "path|#{q[:path]}|" if q[:path].present?
66
66
 
67
67
  str.join("*")
68
68
  end
69
69
 
70
- def query
71
- "performance|*#{compile_query}*|END"
70
+ def compile_jobs_query
71
+ str = []
72
+
73
+ str << "queue|#{q[:queue]}|" if q[:queue].present?
74
+ str << "worker|#{q[:worker]}|" if q[:worker].present?
75
+ str << "datetime|#{q[:on].strftime('%Y%m%d')}*|" if q[:on].present?
76
+ str << "status|#{q[:status]}|" if q[:status].present?
77
+
78
+ str.join("*")
72
79
  end
73
80
 
74
81
  end
@@ -4,10 +4,15 @@ require_relative './instrument/metrics_collector.rb'
4
4
 
5
5
  module RailsPerformance
6
6
  class Engine < ::Rails::Engine
7
+ isolate_namespace RailsPerformance
7
8
 
8
9
  if RailsPerformance.try(:enabled) # for rails c
9
10
 
10
- config.app_middleware.insert_after ActionDispatch::Executor, RailsPerformance::Rails::Middleware
11
+ if ::Rails::VERSION::MAJOR.to_i >= 5
12
+ config.app_middleware.insert_after ActionDispatch::Executor, RailsPerformance::Rails::Middleware
13
+ else
14
+ config.app_middleware.insert_after ActionDispatch::Static, RailsPerformance::Rails::Middleware
15
+ end
11
16
 
12
17
  initializer :configure_metrics, after: :initialize_logger do
13
18
  ActiveSupport::Notifications.subscribe(
@@ -19,7 +24,15 @@ module RailsPerformance
19
24
  ActionView::LogSubscriber.send :prepend, RailsPerformance::Extensions::View
20
25
  ActiveRecord::LogSubscriber.send :prepend, RailsPerformance::Extensions::Db
21
26
  end
27
+ end
22
28
 
29
+ if const_defined?("Sidekiq")
30
+ require_relative './gems/sidekiq.rb'
31
+ Sidekiq.configure_server do |config|
32
+ config.server_middleware do |chain|
33
+ chain.add RailsPerformance::Gems::Sidekiq
34
+ end
35
+ end
23
36
  end
24
37
 
25
38
  end
@@ -0,0 +1,35 @@
1
+ module RailsPerformance
2
+ module Gems
3
+ class Sidekiq
4
+
5
+ def initialize(options=nil)
6
+ end
7
+
8
+ def call(worker, msg, queue)
9
+ now = Time.now
10
+ data = {
11
+ enqueued_ati: msg['enqueued_at'].to_i,
12
+ created_ati: msg['created_at'].to_i,
13
+ jid: msg['jid'],
14
+ queue: queue,
15
+ start_timei: now.to_i,
16
+ datetime: now.strftime(RailsPerformance::FORMAT),
17
+ worker: msg['wrapped'.freeze] || worker.class.to_s
18
+ }
19
+ begin
20
+ yield
21
+ data[:status] = "success"
22
+ rescue Exception => ex
23
+ data[:status] = "exception"
24
+ data[:message] = ex.message
25
+ ensure
26
+ # store in ms instead of seconds
27
+ data[:duration] = (Time.now - now) * 1000
28
+ #puts data
29
+ RailsPerformance::Utils.log_job_in_redis(data)
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class BaseRecord
4
+ def value
5
+ @value ||= JSON.parse(@json || "{}")
6
+ end
7
+
8
+ def duration
9
+ value['duration']
10
+ end
11
+
12
+ private
13
+
14
+ def ms(e)
15
+ if e
16
+ e.to_f.round(1).to_s + " ms"
17
+ else
18
+ nil
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ module RailsPerformance
2
+ module Models
3
+ class JobRecord < BaseRecord
4
+ attr_reader :queue, :worker, :jid, :created_ati, :enqueued_ati, :datetime, :start_timei, :status
5
+
6
+ # key = job-performance
7
+ # |queue|default
8
+ # |worker|SimpleWorker
9
+ # |jid|7d48fbf20976c224510dbc60
10
+ # |datetime|20200124T0523
11
+ # |created_ati|1583146613
12
+ # |enqueued_ati|1583146613
13
+ # |start_timei|1583146614
14
+ # |status|success|END
15
+ # value = JSON
16
+ def initialize(key, value)
17
+ @json = value
18
+
19
+ items = key.split("|")
20
+
21
+ @queue = items[2]
22
+ @worker = items[4]
23
+ @jid = items[6]
24
+ @datetime = items[8]
25
+ @created_ati = items[10]
26
+ @enqueued_ati = items[12]
27
+ @start_timei = items[14]
28
+ @status = items[16]
29
+ end
30
+
31
+ def to_h
32
+ {
33
+ queue: queue,
34
+ worker: worker,
35
+ jid: jid,
36
+ datetime: datetime,
37
+ created_ati: created_ati,
38
+ enqueued_ati: enqueued_ati,
39
+ start_timei: start_timei,
40
+ duration: duration,
41
+ status: status,
42
+ message: value['message']
43
+ }
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -1,9 +1,8 @@
1
1
  module RailsPerformance
2
2
  module Models
3
- class Record
3
+ class Record < BaseRecord
4
4
  attr_reader :controller, :action, :format, :status, :datetime, :datetimei, :method, :path, :request_id
5
5
 
6
-
7
6
  def Record.find_by(request_id:)
8
7
  keys, values = RP::Utils.fetch_from_redis("performance|*|request_id|#{request_id}|*")
9
8
 
@@ -42,10 +41,6 @@ module RailsPerformance
42
41
  @request_id = items[18]
43
42
  end
44
43
 
45
- def value
46
- @value ||= JSON.parse(@json || "{}")
47
- end
48
-
49
44
  def controller_action
50
45
  "#{controller}##{action}"
51
46
  end
@@ -61,23 +56,13 @@ module RailsPerformance
61
56
  format: format,
62
57
  method: method,
63
58
  path: path,
64
- duration: ms(value['duration']),
59
+ duration: ms(duration),
65
60
  view_runtime: ms(value['view_runtime']),
66
61
  db_runtime: ms(value['db_runtime']),
67
62
  HTTP_REFERER: value['HTTP_REFERER']
68
63
  }
69
64
  end
70
65
 
71
- private
72
-
73
- def ms(e)
74
- if e
75
- e.to_f.round(1).to_s + " ms"
76
- else
77
- nil
78
- end
79
- end
80
-
81
66
  end
82
67
  end
83
68
  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
@@ -7,25 +7,48 @@ module RailsPerformance
7
7
  @sort ||= :datetime
8
8
  end
9
9
 
10
- def data
10
+ def data(type = :requests) # most popular type
11
11
  db.data.collect do |record|
12
- {
13
- controller: record.controller,
14
- action: record.action,
15
- format: record.format,
16
- status: record.status,
17
- method: record.method,
18
- path: record.path,
19
- request_id: record.request_id,
20
- datetime: Time.at(record.datetimei.to_i),
21
- duration: record.value['duration'],
22
- db_runtime: record.value['db_runtime'],
23
- view_runtime: record.value['view_runtime'],
24
- }
12
+ case type
13
+ when :requests
14
+ record_hash(record)
15
+ when :jobs
16
+ job_hash(record)
17
+ end
25
18
  end
26
19
  .select{|e| e if e[:datetime] >= TIME_WINDOW.ago}
27
20
  .sort{|a, b| b[sort] <=> a[sort]}
28
21
  end
22
+
23
+ private
24
+
25
+ def record_hash(record)
26
+ {
27
+ controller: record.controller,
28
+ action: record.action,
29
+ format: record.format,
30
+ status: record.status,
31
+ method: record.method,
32
+ path: record.path,
33
+ request_id: record.request_id,
34
+ datetime: Time.at(record.datetimei.to_i),
35
+ duration: record.value['duration'],
36
+ db_runtime: record.value['db_runtime'],
37
+ view_runtime: record.value['view_runtime'],
38
+ }
39
+ end
40
+
41
+ def job_hash(record)
42
+ {
43
+ worker: record.worker,
44
+ queue: record.queue,
45
+
46
+ jid: record.jid,
47
+ status: record.status,
48
+ datetime: Time.at(record.start_timei.to_i),
49
+ duration: record.value['duration'],
50
+ }
51
+ end
29
52
  end
30
53
 
31
54
 
@@ -12,28 +12,21 @@ module RailsPerformance
12
12
  now.strftime("%H:%M")
13
13
  end
14
14
 
15
+ def Utils.log_job_in_redis(e)
16
+ key = "jobs|queue|#{e[:queue]}|worker|#{e[:worker]}|jid|#{e[:jid]}|datetime|#{e[:datetime]}|created_ati|#{e[:created_ati]}|enqueued_ati|#{e[:enqueued_ati]}|start_timei|#{e[:start_timei]}|status|#{e[:status]}|END"
17
+ value = { message: e[:message], duration: e[:duration] }
18
+ Utils.save_to_redis(key, value)
19
+ end
20
+
15
21
  def Utils.log_request_in_redis(e)
16
22
  value = e.slice(:view_runtime, :db_runtime, :duration, :HTTP_REFERER)
17
23
  key = "performance|controller|#{e[:controller]}|action|#{e[:action]}|format|#{e[:format]}|status|#{e[:status]}|datetime|#{e[:datetime]}|datetimei|#{e[:datetimei]}|method|#{e[:method]}|path|#{e[:path]}|request_id|#{e[:request_id]}|END"
18
-
19
- # puts " [SAVE] key ---> #{key}\n"
20
- # puts " value ---> #{value.to_json}\n\n"
21
-
22
- RP.redis.set(key, value.to_json)
23
- RP.redis.expire(key, RP.duration.to_i)
24
-
25
- true
24
+ Utils.save_to_redis(key, value)
26
25
  end
27
26
 
28
27
  def Utils.log_trace_in_redis(request_id, value)
29
28
  key = "trace|#{request_id}"
30
-
31
- # puts " [SAVE] key ---> #{key}\n"
32
- # puts " value ---> #{value.to_json}\n\n"
33
- # pp value
34
-
35
- RP.redis.set(key, value.to_json)
36
- RP.redis.expire(key, RailsPerformance::Reports::RecentRequestsReport::TIME_WINDOW.to_i)
29
+ Utils.save_to_redis(key, value, RailsPerformance::Reports::RecentRequestsReport::TIME_WINDOW.to_i)
37
30
  end
38
31
 
39
32
  def Utils.fetch_from_redis(query)
@@ -47,7 +40,7 @@ module RailsPerformance
47
40
  end
48
41
 
49
42
  def Utils.days
50
- (RP.duration % 24.days).parts[:days] + 1
43
+ (RP.duration / 1.day) + 1
51
44
  end
52
45
 
53
46
  def Utils.median(array)
@@ -64,5 +57,12 @@ module RailsPerformance
64
57
  end
65
58
  end
66
59
 
60
+ def Utils.save_to_redis(key, value, expire = RP.duration.to_i)
61
+ # puts " [SAVE] key ---> #{key}\n"
62
+ # puts " value ---> #{value.to_json}\n\n"
63
+ RP.redis.set(key, value.to_json)
64
+ RP.redis.expire(key, expire.to_i)
65
+ end
66
+
67
67
  end
68
- end
68
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsPerformance
2
- VERSION = '0.9.0.1'
2
+ VERSION = '0.9.5'
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.0.1
4
+ version: 0.9.5
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-02-11 00:00:00.000000000 Z
11
+ date: 2020-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sidekiq
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: 3rd party dependency-free solution how to monitor performance of your
84
98
  Rails applications.
85
99
  email:
@@ -101,14 +115,10 @@ files:
101
115
  - app/assets/images/import.svg
102
116
  - app/assets/images/menu.svg
103
117
  - app/assets/images/stat.svg
104
- - app/controllers/base_controller.rb
105
- - app/controllers/rails_performance_controller.rb
106
- - 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
107
121
  - app/views/rails_performance/_panel.html.erb
108
- - app/views/rails_performance/_summary.html.erb
109
- - app/views/rails_performance/_trace.html.erb
110
- - app/views/rails_performance/crashes.html.erb
111
- - app/views/rails_performance/index.html.erb
112
122
  - app/views/rails_performance/javascripts/_javascripts.html.erb
113
123
  - app/views/rails_performance/javascripts/app.js
114
124
  - app/views/rails_performance/javascripts/jquery-3.4.1.min.js
@@ -117,23 +127,31 @@ files:
117
127
  - app/views/rails_performance/javascripts/stupidtable.min.js
118
128
  - app/views/rails_performance/javascripts/table.js
119
129
  - app/views/rails_performance/layouts/rails_performance.html.erb
120
- - app/views/rails_performance/recent.html.erb
121
- - 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
122
139
  - app/views/rails_performance/shared/_header.html.erb
123
140
  - app/views/rails_performance/stylesheets/_stylesheets.html.erb
124
141
  - app/views/rails_performance/stylesheets/bulma.min.css
125
142
  - app/views/rails_performance/stylesheets/panel.css
126
143
  - app/views/rails_performance/stylesheets/style.css
127
- - app/views/rails_performance/summary.js.erb
128
- - app/views/rails_performance/trace.js.erb
129
144
  - config/routes.rb
130
145
  - lib/rails_performance.rb
131
146
  - lib/rails_performance/data_source.rb
132
147
  - lib/rails_performance/engine.rb
133
148
  - lib/rails_performance/extensions/capture_everything.rb
149
+ - lib/rails_performance/gems/sidekiq.rb
134
150
  - lib/rails_performance/instrument/metrics_collector.rb
151
+ - lib/rails_performance/models/base_record.rb
135
152
  - lib/rails_performance/models/collection.rb
136
153
  - lib/rails_performance/models/current_request.rb
154
+ - lib/rails_performance/models/job_record.rb
137
155
  - lib/rails_performance/models/record.rb
138
156
  - lib/rails_performance/rails/middleware.rb
139
157
  - lib/rails_performance/rails/query_builder.rb
@@ -166,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
184
  - !ruby/object:Gem::Version
167
185
  version: '0'
168
186
  requirements: []
169
- rubygems_version: 3.0.6
187
+ rubygems_version: 3.0.3
170
188
  signing_key:
171
189
  specification_version: 4
172
190
  summary: Simple Rails Performance tracker. Alternative to the NewRelic, Datadog or
@@ -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,74 +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)
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)
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}))
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)
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)
62
- db = @datasource.db
63
- @report = RP::Reports::RecentRequestsReport.new(db)
64
- @data = @report.data
65
- end
66
-
67
- private
68
-
69
- def prepare_query(query = params)
70
- RP::Rails::QueryBuilder.compose_from(query)
71
- end
72
- end
73
-
74
- end
@@ -1,112 +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
- end
111
- end
112
- end