rails_performance 0.0.1.18 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +59 -27
- data/app/controllers/base_controller.rb +0 -5
- data/app/controllers/rails_performance_controller.rb +22 -7
- data/app/helpers/rails_performance_helper.rb +29 -2
- data/app/views/rails_performance/_trace.html.erb +4 -3
- data/app/views/rails_performance/crashes.html.erb +6 -0
- data/app/views/rails_performance/index.html.erb +1 -1
- data/app/views/rails_performance/javascripts/app.js +3 -3
- data/app/views/rails_performance/jobs.html.erb +73 -0
- data/app/views/rails_performance/recent.html.erb +6 -2
- data/app/views/rails_performance/shared/_header.html.erb +3 -0
- data/app/views/rails_performance/summary.js.erb +1 -1
- data/app/views/rails_performance/trace.js.erb +6 -1
- data/config/routes.rb +2 -0
- data/lib/rails_performance.rb +2 -0
- data/lib/rails_performance/data_source.rb +27 -20
- data/lib/rails_performance/engine.rb +13 -1
- data/lib/rails_performance/gems/sidekiq.rb +35 -0
- data/lib/rails_performance/instrument/metrics_collector.rb +3 -1
- data/lib/rails_performance/models/base_record.rb +24 -0
- data/lib/rails_performance/models/current_request.rb +2 -0
- data/lib/rails_performance/models/job_record.rb +48 -0
- data/lib/rails_performance/models/record.rb +25 -5
- data/lib/rails_performance/rails/middleware.rb +19 -16
- data/lib/rails_performance/reports/recent_requests_report.rb +37 -14
- data/lib/rails_performance/utils.rb +18 -18
- data/lib/rails_performance/version.rb +2 -2
- metadata +25 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 016c0a4dada04d91fb392c7be96962f28bd65d7a55ca436379eff445ac6f2c76
|
4
|
+
data.tar.gz: c14155acbc63d8c043f60ddf719e33da0f9dc1d6809fb279c34dc4ba39ea6afe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14be1cffee56e247f968e1001788c2c716d3d4e622b2c584bb8cfb60399bcca20f4665324cd7b15f4bcaf3102af331cba0b20950b67de005b48cb1faa3533374
|
7
|
+
data.tar.gz: e982081222f459103fc3d801f2fb18add3f2e93b2efc1073c33ed6501138ca5b536cce7ba6e763849724ab3673e0c3ca3f2a9aa4583665d6c0397b4652c04aad
|
data/README.md
CHANGED
@@ -1,26 +1,44 @@
|
|
1
1
|
# Rails Performance
|
2
2
|
|
3
|
-
|
3
|
+
[![Build Status](https://travis-ci.org/igorkasyanchuk/rails_performance.svg?branch=master)](https://travis-ci.org/igorkasyanchuk/rails_performance)
|
4
4
|
|
5
|
-
|
5
|
+
A self-hosted tool to monitor the performance of your Ruby on Rails application.
|
6
|
+
|
7
|
+
This is **simple and free alternative** to the New Relic APM, Datadog or other similar services.
|
8
|
+
|
9
|
+
![Demo](docs/rails_performance.gif)
|
6
10
|
|
7
11
|
It allows you to track:
|
8
12
|
|
9
|
-
- throughput report (see amount of requests per minute)
|
13
|
+
- throughput report (see amount of RPM (requests per minute))
|
10
14
|
- an average response time
|
11
15
|
- the slowest controllers & actions
|
12
|
-
- duration of
|
13
|
-
-
|
16
|
+
- total duration of time spent per request, views rendering, DB
|
17
|
+
- SQL queries, rendering logs in "Recent Requests" section
|
18
|
+
- simple 500-crashes reports
|
19
|
+
- track Sidekiq jobs performance
|
14
20
|
|
15
|
-
All data
|
21
|
+
All data are stored in `local` Redis and not sent to any 3rd party servers.
|
16
22
|
|
17
23
|
## Production
|
18
24
|
|
19
|
-
Gem is production-ready. At least on my applications with ~800 unique users per day it works
|
25
|
+
Gem is production-ready. At least on my 2 applications with ~800 unique users per day it works perfectly.
|
26
|
+
|
27
|
+
Just don't forget to protect performance dashboard with http basic auth or check of current_user.
|
20
28
|
|
21
29
|
## Usage
|
22
30
|
|
23
|
-
|
31
|
+
```
|
32
|
+
1. Add gem to the Gemfile (in appropriate group if needed)
|
33
|
+
2. Start rails server
|
34
|
+
3. Make a few requests to your app
|
35
|
+
4. open localhost:3000/rails/performance
|
36
|
+
5. Tune the configuration and deploy to production
|
37
|
+
```
|
38
|
+
|
39
|
+
Default configulation is listed below. But you can overide it.
|
40
|
+
|
41
|
+
Create `config/initializers/rails_performance.rb` in your app:
|
24
42
|
|
25
43
|
```ruby
|
26
44
|
RailsPerformance.setup do |config|
|
@@ -47,6 +65,12 @@ Add this line to your application's Gemfile:
|
|
47
65
|
|
48
66
|
```ruby
|
49
67
|
gem 'rails_performance'
|
68
|
+
|
69
|
+
# or
|
70
|
+
|
71
|
+
group :development, :production do
|
72
|
+
gem 'rails_performance'
|
73
|
+
end
|
50
74
|
```
|
51
75
|
|
52
76
|
And then execute:
|
@@ -58,16 +82,21 @@ You must also have installed Redis server, because this gem is storing data into
|
|
58
82
|
|
59
83
|
After installation and configuration, start your Rails application, make a few requests, and open `https://localhost:3000/rails/performance` URL.
|
60
84
|
|
85
|
+
## How it works
|
86
|
+
|
87
|
+
![Schema](docs/rails_performance.png)
|
88
|
+
|
61
89
|
## Limitations
|
62
90
|
|
63
91
|
- it doesn't track params of POST/PUT requests
|
64
|
-
- it doesn't track SQL queries (at least for now)
|
65
92
|
- it doesn't track Redis/ElasticSearch or other apps
|
66
93
|
- it can't compare historical data
|
67
94
|
- depending on your load you may need to reduce time of for how long you store data, because all calculations are done in memory and it could take some time for high-load apps
|
68
95
|
|
69
96
|
## Redis
|
70
97
|
|
98
|
+
Gem is using Redis. This is the only one dependency.
|
99
|
+
|
71
100
|
All information is stored into Redis. The default expiration time is set to `config.duration` from the configuration.
|
72
101
|
|
73
102
|
## Development & Testing
|
@@ -77,12 +106,14 @@ Just clone the repo, setup dummy app (`rails db:migrate`).
|
|
77
106
|
After this:
|
78
107
|
|
79
108
|
- rails s
|
80
|
-
- rake
|
109
|
+
- rake test
|
81
110
|
|
82
111
|
Like a regular web development.
|
83
112
|
|
84
113
|
Please note that to simplify integration with other apps all CSS/JS are bundled inside, and delivered in body of the request. This is to avoid integration with assets pipeline or webpacker.
|
85
114
|
|
115
|
+
For UI changes you need to use Bulma CSS (https://bulma.io/documentation).
|
116
|
+
|
86
117
|
## Why
|
87
118
|
|
88
119
|
The idea of this gem grew from curriosity how many RPM my app receiving per day. Later it evolutionated to something more powerful.
|
@@ -90,32 +121,33 @@ The idea of this gem grew from curriosity how many RPM my app receiving per day.
|
|
90
121
|
## TODO
|
91
122
|
|
92
123
|
- documentation in Readme
|
124
|
+
- capture stacktrace of 500 errors and show in side panel
|
93
125
|
- generator for initial config
|
94
|
-
- gif with demo
|
95
|
-
- time/zone config?
|
96
126
|
- CI for tests
|
97
|
-
-
|
98
|
-
-
|
99
|
-
-
|
127
|
+
- time/zone config?
|
128
|
+
- connected charts on dashboard, when zoom, when hover?
|
129
|
+
- ability to zoom to see requests withing specific datetime range
|
130
|
+
- better hints?
|
100
131
|
- export to csv
|
101
|
-
- http basic auth config
|
102
|
-
- current_user auth config
|
103
132
|
- better stats tooltip, do not show if nothing to show
|
104
|
-
- dark mode toggle? save to the cookies
|
105
|
-
- integration with elastic search
|
133
|
+
- dark mode toggle? save to the cookies?
|
134
|
+
- integration with elastic search? or other?
|
106
135
|
- monitor active job (sidekiq)?
|
107
|
-
- logo?
|
136
|
+
- better logo?
|
108
137
|
- number of requests last 24 hours, hour, etc.
|
109
|
-
-
|
110
|
-
-
|
111
|
-
-
|
112
|
-
-
|
113
|
-
-
|
114
|
-
- scroll to the top details
|
138
|
+
- collect deprecation.rails
|
139
|
+
- fix misspellings?
|
140
|
+
- show "loading banner" until jquery is loaded?
|
141
|
+
- better UI on smaller screens? Recent requests when URL's are long? Truncate with CSS?
|
142
|
+
- rules for highlighting durations? how many ms to show warning, alert
|
115
143
|
|
116
144
|
## Contributing
|
117
145
|
|
118
|
-
You are welcome to contribute.
|
146
|
+
You are welcome to contribute. I've a big list of TODO.
|
147
|
+
|
148
|
+
## Big thanks to contributors
|
149
|
+
|
150
|
+
- https://github.com/synth
|
119
151
|
|
120
152
|
## License
|
121
153
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
class BaseController < ActionController::Base
|
2
2
|
layout 'rails_performance/layouts/rails_performance'
|
3
3
|
|
4
|
-
before_action :leave_finger_print
|
5
4
|
before_action :verify_access
|
6
5
|
|
7
6
|
if RailsPerformance.http_basic_authentication_enabled
|
@@ -12,10 +11,6 @@ class BaseController < ActionController::Base
|
|
12
11
|
|
13
12
|
private
|
14
13
|
|
15
|
-
def leave_finger_print
|
16
|
-
Thread.current[:in_rails_performance] = true
|
17
|
-
end
|
18
|
-
|
19
14
|
def verify_access
|
20
15
|
result = RailsPerformance.verify_access_proc.call(self)
|
21
16
|
redirect_to('/', error: 'Access Denied', status: 401) unless result
|
@@ -4,7 +4,7 @@ class RailsPerformanceController < BaseController
|
|
4
4
|
|
5
5
|
if RailsPerformance.enabled
|
6
6
|
def index
|
7
|
-
@datasource = RP::DataSource.new(prepare_query)
|
7
|
+
@datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
|
8
8
|
db = @datasource.db
|
9
9
|
|
10
10
|
@throughput_report = RP::Reports::ThroughputReport.new(db)
|
@@ -15,7 +15,7 @@ class RailsPerformanceController < BaseController
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def summary
|
18
|
-
@datasource = RP::DataSource.new(prepare_query)
|
18
|
+
@datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
|
19
19
|
db = @datasource.db
|
20
20
|
|
21
21
|
@throughput_report = RP::Reports::ThroughputReport.new(db)
|
@@ -29,40 +29,55 @@ class RailsPerformanceController < BaseController
|
|
29
29
|
|
30
30
|
respond_to do |format|
|
31
31
|
format.js {}
|
32
|
-
format.any { render plain: "Doesn't open in new window" }
|
32
|
+
format.any { render plain: "Doesn't open in new window. Wait until full page load." }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
def trace
|
37
|
+
@record = RP::Models::Record.find_by(request_id: params[:id])
|
37
38
|
@report = RP::Reports::TraceReport.new(request_id: params[:id])
|
38
39
|
@data = @report.data
|
39
40
|
respond_to do |format|
|
40
41
|
format.js {}
|
41
|
-
format.any { render plain: "Doesn't open in new window" }
|
42
|
+
format.any { render plain: "Doesn't open in new window. Wait until full page load." }
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
46
|
def crashes
|
46
|
-
@datasource = RP::DataSource.new(prepare_query({status_eq: 500}))
|
47
|
+
@datasource = RP::DataSource.new(**prepare_query({status_eq: 500}), type: :requests, klass: RP::Models::Record)
|
47
48
|
db = @datasource.db
|
48
49
|
@report = RP::Reports::CrashReport.new(db)
|
49
50
|
@data = @report.data
|
50
51
|
end
|
51
52
|
|
52
53
|
def requests
|
53
|
-
@datasource = RP::DataSource.new(prepare_query)
|
54
|
+
@datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
|
54
55
|
db = @datasource.db
|
55
56
|
@report = RP::Reports::RequestsReport.new(db, group: :controller_action_format, sort: :count)
|
56
57
|
@data = @report.data
|
57
58
|
end
|
58
59
|
|
59
60
|
def recent
|
60
|
-
@datasource = RP::DataSource.new(prepare_query)
|
61
|
+
@datasource = RP::DataSource.new(**prepare_query, type: :requests, klass: RP::Models::Record)
|
61
62
|
db = @datasource.db
|
62
63
|
@report = RP::Reports::RecentRequestsReport.new(db)
|
63
64
|
@data = @report.data
|
64
65
|
end
|
65
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
|
+
|
66
81
|
private
|
67
82
|
|
68
83
|
def prepare_query(query = params)
|
@@ -6,6 +6,29 @@ module RailsPerformanceHelper
|
|
6
6
|
value.nan? ? nil : value.round(1)
|
7
7
|
end
|
8
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
|
+
|
9
32
|
def ms(value)
|
10
33
|
result = round_it(value)
|
11
34
|
result && result != 0 ? "#{result} ms" : '-'
|
@@ -27,14 +50,16 @@ module RailsPerformanceHelper
|
|
27
50
|
|
28
51
|
def report_name(h)
|
29
52
|
h.except(:on).collect do |k, v|
|
53
|
+
next if v.blank?
|
54
|
+
|
30
55
|
%Q{
|
31
56
|
<div class="control">
|
32
57
|
<span class="tags has-addons">
|
33
58
|
<span class="tag">#{k}</span>
|
34
|
-
<span class="tag is-
|
59
|
+
<span class="tag is-info is-light">#{v}</span>
|
35
60
|
</span>
|
36
61
|
</div>}
|
37
|
-
end.join.html_safe
|
62
|
+
end.compact.join.html_safe
|
38
63
|
end
|
39
64
|
|
40
65
|
def status_tag(status)
|
@@ -82,6 +107,8 @@ module RailsPerformanceHelper
|
|
82
107
|
"is-active" if controller_name == "rails_performance" && action_name == "requests"
|
83
108
|
when :recent
|
84
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"
|
85
112
|
end
|
86
113
|
end
|
87
114
|
end
|
@@ -2,16 +2,17 @@
|
|
2
2
|
<tbody>
|
3
3
|
<% @data.each do |e| %>
|
4
4
|
<tr>
|
5
|
-
<td><%= e["group"] %></td>
|
6
5
|
<% if e["group"] == 'db' %>
|
7
|
-
<td class="nowrap">
|
6
|
+
<td class="nowrap has-text-right <%= duraction_alert_class(e['duration']) %>">
|
8
7
|
<%= e["duration"] %> ms
|
9
8
|
</td>
|
10
9
|
<td>
|
11
10
|
<%= e["sql"] %>
|
12
11
|
</td>
|
13
12
|
<% elsif e["group"] == 'view' %>
|
14
|
-
<td
|
13
|
+
<td class="nowrap has-text-right <%= duraction_alert_class(extract_duration(e['message'])) %>">
|
14
|
+
<%= extract_duration(e["message"]) %>
|
15
|
+
</td>
|
15
16
|
<td>
|
16
17
|
<%= e["message"] %>
|
17
18
|
</td>
|
@@ -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);
|
@@ -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
|
-
|
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:
|
72
|
+
name: name,
|
73
73
|
data: data,
|
74
74
|
fillOpacity: 0.3,
|
75
75
|
lineWidth: 1,
|
@@ -0,0 +1,73 @@
|
|
1
|
+
<title>Number of Requests to the Application</title>
|
2
|
+
|
3
|
+
<% unless @datasource.default? %>
|
4
|
+
<%#= link_to raw("← 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,7 +1,6 @@
|
|
1
1
|
<div class="card">
|
2
2
|
<div class="card-content">
|
3
|
-
|
4
|
-
<h2 class="subtitle">Recent Requests (last <%= RailsPerformance::Reports::RecentRequestsReport::TIME_WINDOW %> minutes)<h2>
|
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>
|
@@ -19,6 +18,11 @@
|
|
19
18
|
</tr>
|
20
19
|
</thead>
|
21
20
|
<tbody>
|
21
|
+
<% if @data.empty? %>
|
22
|
+
<tr>
|
23
|
+
<td colspan="10">Nothing to show here. Try to make a few requests in main app.</td>
|
24
|
+
</tr>
|
25
|
+
<% end %>
|
22
26
|
<% @data.each do |e| %>
|
23
27
|
<tr>
|
24
28
|
<td><%= format_datetime e[:datetime] %></td>
|
@@ -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">
|
@@ -2,7 +2,7 @@ window.panel.header.html(window.panel.close + '<%= j report_name(@datasource.q)
|
|
2
2
|
window.panel.content.html("<%= j render '/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);
|
@@ -1,4 +1,9 @@
|
|
1
|
-
|
1
|
+
<% if @record %>
|
2
|
+
window.panel.header.html(window.panel.close + "<%= j report_name(@record.to_h) %>");
|
3
|
+
<% else %>
|
4
|
+
window.panel.header.html(window.panel.close);
|
5
|
+
<% end %>
|
6
|
+
|
2
7
|
window.panel.content.html("<%= j render '/rails_performance/trace' %>");
|
3
8
|
|
4
9
|
showPanel();
|
data/config/routes.rb
CHANGED
@@ -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
|
data/lib/rails_performance.rb
CHANGED
@@ -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
|
39
|
+
yield klass.new(key, values[index])
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
43
|
private
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
def
|
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
|
71
|
-
|
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
|
@@ -5,8 +5,10 @@ require_relative './instrument/metrics_collector.rb'
|
|
5
5
|
module RailsPerformance
|
6
6
|
class Engine < ::Rails::Engine
|
7
7
|
|
8
|
-
if RailsPerformance.enabled
|
8
|
+
if RailsPerformance.try(:enabled) # for rails c
|
9
|
+
|
9
10
|
config.app_middleware.insert_after ActionDispatch::Executor, RailsPerformance::Rails::Middleware
|
11
|
+
|
10
12
|
initializer :configure_metrics, after: :initialize_logger do
|
11
13
|
ActiveSupport::Notifications.subscribe(
|
12
14
|
"process_action.action_controller",
|
@@ -18,6 +20,16 @@ module RailsPerformance
|
|
18
20
|
ActiveRecord::LogSubscriber.send :prepend, RailsPerformance::Extensions::Db
|
19
21
|
end
|
20
22
|
end
|
23
|
+
|
24
|
+
if const_defined?("Sidekiq")
|
25
|
+
require_relative './gems/sidekiq.rb'
|
26
|
+
Sidekiq.configure_server do |config|
|
27
|
+
config.server_middleware do |chain|
|
28
|
+
chain.add RailsPerformance::Gems::Sidekiq
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
21
33
|
end
|
22
34
|
|
23
35
|
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
|
@@ -18,6 +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/
|
22
|
+
|
21
23
|
record = {
|
22
24
|
controller: event.payload[:controller],
|
23
25
|
action: event.payload[:action],
|
@@ -32,7 +34,7 @@ module RailsPerformance
|
|
32
34
|
duration: event.duration
|
33
35
|
}
|
34
36
|
|
35
|
-
|
37
|
+
CurrentRequest.current.record = record
|
36
38
|
end
|
37
39
|
end
|
38
40
|
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
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module RailsPerformance
|
2
2
|
class CurrentRequest
|
3
3
|
attr_reader :request_id, :storage
|
4
|
+
attr_accessor :record
|
4
5
|
|
5
6
|
def CurrentRequest.init
|
6
7
|
Thread.current[:rp_current_request] ||= CurrentRequest.new(SecureRandom.hex(16))
|
@@ -17,6 +18,7 @@ module RailsPerformance
|
|
17
18
|
def initialize(request_id)
|
18
19
|
@request_id = request_id
|
19
20
|
@storage = []
|
21
|
+
@record = nil
|
20
22
|
end
|
21
23
|
|
22
24
|
def store(options = {})
|
@@ -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,8 +1,17 @@
|
|
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
|
+
def Record.find_by(request_id:)
|
7
|
+
keys, values = RP::Utils.fetch_from_redis("performance|*|request_id|#{request_id}|*")
|
8
|
+
|
9
|
+
return nil if keys.blank?
|
10
|
+
return nil if values.blank?
|
11
|
+
|
12
|
+
RP::Models::Record.new(keys[0], values[0])
|
13
|
+
end
|
14
|
+
|
6
15
|
# key = performance|
|
7
16
|
# controller|HomeController|
|
8
17
|
# action|index|
|
@@ -32,10 +41,6 @@ module RailsPerformance
|
|
32
41
|
@request_id = items[18]
|
33
42
|
end
|
34
43
|
|
35
|
-
def value
|
36
|
-
@value ||= JSON.parse(@json || "{}")
|
37
|
-
end
|
38
|
-
|
39
44
|
def controller_action
|
40
45
|
"#{controller}##{action}"
|
41
46
|
end
|
@@ -43,6 +48,21 @@ module RailsPerformance
|
|
43
48
|
def controller_action_format
|
44
49
|
"#{controller}##{action}|#{format}"
|
45
50
|
end
|
51
|
+
|
52
|
+
def to_h
|
53
|
+
{
|
54
|
+
controller: controller,
|
55
|
+
action: action,
|
56
|
+
format: format,
|
57
|
+
method: method,
|
58
|
+
path: path,
|
59
|
+
duration: ms(duration),
|
60
|
+
view_runtime: ms(value['view_runtime']),
|
61
|
+
db_runtime: ms(value['db_runtime']),
|
62
|
+
HTTP_REFERER: value['HTTP_REFERER']
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
46
66
|
end
|
47
67
|
end
|
48
68
|
end
|
@@ -8,25 +8,28 @@ module RailsPerformance
|
|
8
8
|
def call(env)
|
9
9
|
@status, @headers, @response = @app.call(env)
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
#t = Time.now
|
12
|
+
if record = CurrentRequest.current.record
|
13
|
+
begin
|
14
|
+
record[:status] ||= @status # for 500 errors
|
15
|
+
record[:request_id] = CurrentRequest.current.request_id
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# record[:duration] = 50 + rand(100) + rand(50.0) + rand(e)
|
20
|
-
# record[:db_runtime] = rand(50.0)
|
21
|
-
# record[:view_runtime] = rand(50.0)
|
22
|
-
# RP::Utils.log_request_in_redis(record)
|
23
|
-
# end
|
17
|
+
# capture referer from where this page was opened
|
18
|
+
if record[:status] == 404
|
19
|
+
record[:HTTP_REFERER] = env["HTTP_REFERER"]
|
20
|
+
end
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
# store for section "recent requests"
|
23
|
+
RP::Utils.log_trace_in_redis(CurrentRequest.current.request_id, CurrentRequest.current.storage)
|
24
|
+
|
25
|
+
# store request information
|
26
|
+
RP::Utils.log_request_in_redis(record)
|
27
|
+
ensure
|
28
|
+
# we don't want to have a memory leak
|
29
|
+
CurrentRequest.cleanup
|
30
|
+
end
|
29
31
|
end
|
32
|
+
#puts "==> store performance data: #{(Time.now - t).round(3)}ms"
|
30
33
|
|
31
34
|
[@status, @headers, @response]
|
32
35
|
end
|
@@ -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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
value = e.slice(:view_runtime, :db_runtime, :duration)
|
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
|
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.
|
3
|
-
end
|
2
|
+
VERSION = '0.9.2'
|
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.
|
4
|
+
version: 0.9.2
|
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-
|
11
|
+
date: 2020-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -80,7 +80,22 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
|
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'
|
97
|
+
description: 3rd party dependency-free solution how to monitor performance of your
|
98
|
+
Rails applications.
|
84
99
|
email:
|
85
100
|
- igorkasyanchuk@gmail.com
|
86
101
|
executables: []
|
@@ -115,6 +130,7 @@ files:
|
|
115
130
|
- app/views/rails_performance/javascripts/rails.js
|
116
131
|
- app/views/rails_performance/javascripts/stupidtable.min.js
|
117
132
|
- app/views/rails_performance/javascripts/table.js
|
133
|
+
- app/views/rails_performance/jobs.html.erb
|
118
134
|
- app/views/rails_performance/layouts/rails_performance.html.erb
|
119
135
|
- app/views/rails_performance/recent.html.erb
|
120
136
|
- app/views/rails_performance/requests.html.erb
|
@@ -130,9 +146,12 @@ files:
|
|
130
146
|
- lib/rails_performance/data_source.rb
|
131
147
|
- lib/rails_performance/engine.rb
|
132
148
|
- lib/rails_performance/extensions/capture_everything.rb
|
149
|
+
- lib/rails_performance/gems/sidekiq.rb
|
133
150
|
- lib/rails_performance/instrument/metrics_collector.rb
|
151
|
+
- lib/rails_performance/models/base_record.rb
|
134
152
|
- lib/rails_performance/models/collection.rb
|
135
153
|
- lib/rails_performance/models/current_request.rb
|
154
|
+
- lib/rails_performance/models/job_record.rb
|
136
155
|
- lib/rails_performance/models/record.rb
|
137
156
|
- lib/rails_performance/rails/middleware.rb
|
138
157
|
- lib/rails_performance/rails/query_builder.rb
|
@@ -165,8 +184,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
184
|
- !ruby/object:Gem::Version
|
166
185
|
version: '0'
|
167
186
|
requirements: []
|
168
|
-
rubygems_version: 3.0.
|
187
|
+
rubygems_version: 3.0.3
|
169
188
|
signing_key:
|
170
189
|
specification_version: 4
|
171
|
-
summary:
|
190
|
+
summary: Simple Rails Performance tracker. Alternative to the NewRelic, Datadog or
|
191
|
+
other services.
|
172
192
|
test_files: []
|