rails_mini_profiler 0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +302 -0
- data/app/assets/config/rails_mini_profiler_manifest.js +1 -0
- data/app/assets/javascripts/rails_mini_profiler.js +15 -0
- data/app/assets/stylesheets/rails_mini_profiler/application.css +16 -0
- data/app/controllers/rails_mini_profiler/application_controller.rb +33 -0
- data/app/controllers/rails_mini_profiler/flamegraphs_controller.rb +23 -0
- data/app/controllers/rails_mini_profiler/profiled_requests_controller.rb +68 -0
- data/app/helpers/rails_mini_profiler/application_helper.rb +23 -0
- data/app/helpers/rails_mini_profiler/profiled_requests_helper.rb +16 -0
- data/app/javascript/images/bookmark.svg +10 -0
- data/app/javascript/images/chart.svg +12 -0
- data/app/javascript/images/check.svg +3 -0
- data/app/javascript/images/chevron.svg +3 -0
- data/app/javascript/images/delete.svg +9 -0
- data/app/javascript/images/filter.svg +1 -0
- data/app/javascript/images/graph.svg +11 -0
- data/app/javascript/images/logo.svg +18 -0
- data/app/javascript/images/logo_variant.svg +32 -0
- data/app/javascript/images/search.svg +9 -0
- data/app/javascript/images/setting.svg +10 -0
- data/app/javascript/images/show.svg +11 -0
- data/app/javascript/js/checklist_controller.js +48 -0
- data/app/javascript/js/enable_controller.js +24 -0
- data/app/javascript/js/filter_controller.js +44 -0
- data/app/javascript/js/search_controller.js +18 -0
- data/app/javascript/js/select_controller.js +47 -0
- data/app/javascript/packs/rails-mini-profiler.js +88 -0
- data/app/javascript/stylesheets/components/page_header/page_header.scss +3 -0
- data/app/javascript/stylesheets/components/pagination.scss +55 -0
- data/app/javascript/stylesheets/components/profiled_request_table/placeholder.scss +33 -0
- data/app/javascript/stylesheets/components/profiled_request_table/profiled_request_table.scss +179 -0
- data/app/javascript/stylesheets/flamegraph.scss +10 -0
- data/app/javascript/stylesheets/flashes.scss +15 -0
- data/app/javascript/stylesheets/navbar.scss +44 -0
- data/app/javascript/stylesheets/profiled_requests.scss +89 -0
- data/app/javascript/stylesheets/rails-mini-profiler.scss +205 -0
- data/app/javascript/stylesheets/traces.scss +82 -0
- data/app/models/rails_mini_profiler/application_record.rb +17 -0
- data/app/models/rails_mini_profiler/controller_trace.rb +37 -0
- data/app/models/rails_mini_profiler/flamegraph.rb +37 -0
- data/app/models/rails_mini_profiler/instantiation_trace.rb +37 -0
- data/app/models/rails_mini_profiler/profiled_request.rb +65 -0
- data/app/models/rails_mini_profiler/render_partial_trace.rb +37 -0
- data/app/models/rails_mini_profiler/render_template_trace.rb +37 -0
- data/app/models/rails_mini_profiler/rmp_trace.rb +35 -0
- data/app/models/rails_mini_profiler/sequel_trace.rb +37 -0
- data/app/models/rails_mini_profiler/trace.rb +46 -0
- data/app/presenters/rails_mini_profiler/base_presenter.rb +25 -0
- data/app/presenters/rails_mini_profiler/controller_trace_presenter.rb +18 -0
- data/app/presenters/rails_mini_profiler/instantiation_trace_presenter.rb +14 -0
- data/app/presenters/rails_mini_profiler/profiled_request_presenter.rb +38 -0
- data/app/presenters/rails_mini_profiler/render_partial_trace_presenter.rb +11 -0
- data/app/presenters/rails_mini_profiler/render_template_trace_presenter.rb +15 -0
- data/app/presenters/rails_mini_profiler/rmp_trace_presenter.rb +9 -0
- data/app/presenters/rails_mini_profiler/sequel_trace_presenter.rb +69 -0
- data/app/presenters/rails_mini_profiler/trace_presenter.rb +61 -0
- data/app/search/rails_mini_profiler/base_search.rb +67 -0
- data/app/search/rails_mini_profiler/profiled_request_search.rb +34 -0
- data/app/views/layouts/rails_mini_profiler/application.html.erb +15 -0
- data/app/views/layouts/rails_mini_profiler/flamegraph.html.erb +11 -0
- data/app/views/models/_flamegraph.json.jb +3 -0
- data/app/views/models/_profiled_request.jb +3 -0
- data/app/views/models/_trace.jb +3 -0
- data/app/views/rails_mini_profiler/badge.html.erb +37 -0
- data/app/views/rails_mini_profiler/flamegraphs/show.html.erb +13 -0
- data/app/views/rails_mini_profiler/flamegraphs/show.json.jb +3 -0
- data/app/views/rails_mini_profiler/profiled_requests/index.html.erb +9 -0
- data/app/views/rails_mini_profiler/profiled_requests/index.json.jb +3 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/_trace.html.erb +40 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/header/_header.erb +20 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/table/_placeholder.erb +12 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table.erb +14 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_head.erb +125 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_row.erb +21 -0
- data/app/views/rails_mini_profiler/profiled_requests/show.html.erb +40 -0
- data/app/views/rails_mini_profiler/profiled_requests/show.json.jb +5 -0
- data/app/views/rails_mini_profiler/shared/_flashes.html.erb +8 -0
- data/app/views/rails_mini_profiler/shared/_head.erb +13 -0
- data/app/views/rails_mini_profiler/shared/_navbar.html.erb +15 -0
- data/config/routes.rb +11 -0
- data/db/migrate/20210621185018_create_rmp.rb +46 -0
- data/lib/generators/rails_mini_profiler/USAGE +2 -0
- data/lib/generators/rails_mini_profiler/install_generator.rb +40 -0
- data/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.js.erb +13 -0
- data/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.rb.erb +29 -0
- data/lib/rails_mini_profiler/badge.rb +84 -0
- data/lib/rails_mini_profiler/configuration/storage.rb +47 -0
- data/lib/rails_mini_profiler/configuration/user_interface.rb +48 -0
- data/lib/rails_mini_profiler/configuration.rb +65 -0
- data/lib/rails_mini_profiler/engine.rb +34 -0
- data/lib/rails_mini_profiler/flamegraph_guard.rb +47 -0
- data/lib/rails_mini_profiler/guard.rb +57 -0
- data/lib/rails_mini_profiler/logger.rb +25 -0
- data/lib/rails_mini_profiler/middleware.rb +74 -0
- data/lib/rails_mini_profiler/models/base_model.rb +23 -0
- data/lib/rails_mini_profiler/redirect.rb +33 -0
- data/lib/rails_mini_profiler/request_context.rb +86 -0
- data/lib/rails_mini_profiler/request_wrapper.rb +69 -0
- data/lib/rails_mini_profiler/response_wrapper.rb +32 -0
- data/lib/rails_mini_profiler/tracing/controller_tracer.rb +15 -0
- data/lib/rails_mini_profiler/tracing/null_trace.rb +7 -0
- data/lib/rails_mini_profiler/tracing/sequel_tracer.rb +37 -0
- data/lib/rails_mini_profiler/tracing/sequel_tracker.rb +37 -0
- data/lib/rails_mini_profiler/tracing/subscriptions.rb +34 -0
- data/lib/rails_mini_profiler/tracing/trace.rb +45 -0
- data/lib/rails_mini_profiler/tracing/trace_factory.rb +37 -0
- data/lib/rails_mini_profiler/tracing/tracer.rb +31 -0
- data/lib/rails_mini_profiler/tracing/view_tracer.rb +12 -0
- data/lib/rails_mini_profiler/tracing.rb +11 -0
- data/lib/rails_mini_profiler/user.rb +40 -0
- data/lib/rails_mini_profiler/version.rb +5 -0
- data/lib/rails_mini_profiler.rb +79 -0
- data/lib/tasks/rails_mini_profiler_tasks.rake +8 -0
- data/public/rails_mini_profiler/speedscope/LICENSE +21 -0
- data/public/rails_mini_profiler/speedscope/demangle-cpp.1768f4cc.js +4 -0
- data/public/rails_mini_profiler/speedscope/demangle-cpp.1768f4cc.js.map +1 -0
- data/public/rails_mini_profiler/speedscope/favicon-16x16.f74b3187.png +0 -0
- data/public/rails_mini_profiler/speedscope/favicon-32x32.bc503437.png +0 -0
- data/public/rails_mini_profiler/speedscope/file-format-schema.json +324 -0
- data/public/rails_mini_profiler/speedscope/import.e3a73ef4.js +117 -0
- data/public/rails_mini_profiler/speedscope/import.e3a73ef4.js.map +1 -0
- data/public/rails_mini_profiler/speedscope/index.html +2 -0
- data/public/rails_mini_profiler/speedscope/release.txt +3 -0
- data/public/rails_mini_profiler/speedscope/reset.8c46b7a1.css +2 -0
- data/public/rails_mini_profiler/speedscope/reset.8c46b7a1.css.map +1 -0
- data/public/rails_mini_profiler/speedscope/source-map.438fa06b.js +24 -0
- data/public/rails_mini_profiler/speedscope/source-map.438fa06b.js.map +1 -0
- data/public/rails_mini_profiler/speedscope/speedscope.026f36b0.js +200 -0
- data/public/rails_mini_profiler/speedscope/speedscope.026f36b0.js.map +1 -0
- data/vendor/assets/images/bookmark.svg +10 -0
- data/vendor/assets/images/chart.svg +12 -0
- data/vendor/assets/images/check.svg +3 -0
- data/vendor/assets/images/chevron.svg +3 -0
- data/vendor/assets/images/delete.svg +9 -0
- data/vendor/assets/images/filter.svg +1 -0
- data/vendor/assets/images/graph.svg +11 -0
- data/vendor/assets/images/logo.svg +18 -0
- data/vendor/assets/images/logo_variant.svg +32 -0
- data/vendor/assets/images/search.svg +9 -0
- data/vendor/assets/images/setting.svg +10 -0
- data/vendor/assets/images/show.svg +11 -0
- data/vendor/assets/javascripts/rails-mini-profiler.css +1 -0
- data/vendor/assets/javascripts/rails-mini-profiler.js +1 -0
- metadata +248 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 96a6d11caabcae6df487601bf8f2283ddfd4d72eecefcab62355f56ae4dbf552
|
4
|
+
data.tar.gz: ddc642e94f3e9832023d3de12e532490ad509c4a9cfc61b4dd010dab811dc750
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: be8f67fe210563c0857dd665b7a58ce02648814f7b8848eded9919a8af667332d3718d8d5525a4ea5777f380f8c16dfcb41baaec5d74c3b9f53b9284745809de
|
7
|
+
data.tar.gz: 237ddd6a552449b30e13fb0f36d866c65b3be913e4cce8f4f69b9d48e8f800cb75f773ede153409f1dc0aa21314fa0cfd1f6f80551a7e2621aa43b5bb28768ea
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2021 hschne
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
<div align="center">
|
2
|
+
|
3
|
+
# Rails Mini Profiler
|
4
|
+
|
5
|
+
<img alt="logo" src="docs/images/logo.png" width="300px" height="auto">
|
6
|
+
|
7
|
+
### Performance profiling for Rails, made simple.
|
8
|
+
|
9
|
+
[![Gem Version](https://badge.fury.io/rb/rails_mini_profiler.svg)](https://badge.fury.io/rb/rails_mini_profiler)
|
10
|
+
[![Main](https://github.com/hschne/rails-mini-profiler/actions/workflows/main.yml/badge.svg)](https://github.com/hschne/rails-mini-profiler/actions/workflows/main.yml)
|
11
|
+
[![License](https://img.shields.io/github/license/hschne/rails-mini-profiler)](https://img.shields.io/github/license/hschne/rails-mini-profiler)
|
12
|
+
|
13
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/1fcc2f4d01ab5bf7a260/maintainability)](https://codeclimate.com/github/hschne/rails-mini-profiler/maintainability)
|
14
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/1fcc2f4d01ab5bf7a260/test_coverage)](https://codeclimate.com/github/hschne/rails-mini-profiler/test_coverage)
|
15
|
+
|
16
|
+
</div>
|
17
|
+
|
18
|
+
## What's this?
|
19
|
+
|
20
|
+
Rails Mini Profiler is an easy-to-use performance profiler for your Rails applications. It is heavily inspired by [Rack Mini Profiler](https://github.com/MiniProfiler/rack-mini-profiler) and other APM tools. To find out how it stacks up against those check out [Why Rails Mini Profiler](#why-rails-mini-profiler)?
|
21
|
+
|
22
|
+
To see it in action view the preview below:
|
23
|
+
|
24
|
+
<div align="center">
|
25
|
+
|
26
|
+
[![Rails Mini Profiler Preview](http://img.youtube.com/vi/fSR8fCcsO8Q/0.jpg)](https://www.youtube.com/watch?v=fSR8fCcsO8Q)
|
27
|
+
|
28
|
+
</div>
|
29
|
+
|
30
|
+
**Note**: This gem is in early development and I'm looking for contributors. Try it out and leave some feedback, it really goes a long way in helping me out with development. Any [feature request](https://github.com/hschne/rails-mini-profiler/issues/new?assignees=&labels=type%3ABug&template=FEATURE_REQUEST.md&title=) or [bug report](https://github.com/hschne/rails-mini-profiler/issues/new?assignees=&labels=type%3AEnhancement&template=BUG_REPORT.md&title=) is welcome. If you like this project, leave a star to show your support! ⭐
|
31
|
+
|
32
|
+
## Getting Started
|
33
|
+
|
34
|
+
Add Rails Mini Profiler to your Gemfile:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
gem 'rails_mini_profiler'
|
38
|
+
```
|
39
|
+
|
40
|
+
Install the gem and run the installer:
|
41
|
+
|
42
|
+
```bash
|
43
|
+
bundle install
|
44
|
+
rails rails_mini_profiler:install
|
45
|
+
```
|
46
|
+
|
47
|
+
Inspect the generated migration in `db/migrate` and run it:
|
48
|
+
|
49
|
+
```
|
50
|
+
rails db:migrate
|
51
|
+
```
|
52
|
+
|
53
|
+
Start your Rails application and perform some requests. You can either click the little hedgehog 🦔 on the top
|
54
|
+
left or navigate to `/rails_mini_profiler` to view collected performance metrics.
|
55
|
+
|
56
|
+
## Usage
|
57
|
+
|
58
|
+
Rails Mini Profiler provides detailed information about your requests to help you figure out why certain requests perform poorly.
|
59
|
+
|
60
|
+
Installing it will generate a new initializer `config/initializers/rails_mini_profiler.rb` and add a new
|
61
|
+
route:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
# routes.rb
|
65
|
+
Rails.application.routes.draw do
|
66
|
+
...
|
67
|
+
|
68
|
+
mount RailsMiniProfiler::Engine => '/rails_mini_profiler'
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
Once you perform requests against your applications you can inspect them using that route, or by clicking the badge on the
|
73
|
+
top right that is injected into your pages.
|
74
|
+
|
75
|
+
### Request Overview
|
76
|
+
|
77
|
+
![overview](docs/images/overview.png)
|
78
|
+
|
79
|
+
Requests to your application will be profiled automatically. You can view all stored requests by navigating to `yourapp/rails_mini_profiler/profiled_requests`.
|
80
|
+
|
81
|
+
### Request Details
|
82
|
+
|
83
|
+
<p align="center">
|
84
|
+
<img alt="Light" src="docs/images/trace.png" width="45%">
|
85
|
+
|
86
|
+
<img alt="Dark" src="docs/images/sequel.png" width="45%">
|
87
|
+
</p>
|
88
|
+
|
89
|
+
This view shows you how your requests spend their time. How much of it is spent in the DB, how much in rendering views?
|
90
|
+
By clicking on individual traces you can find out detailed information.
|
91
|
+
|
92
|
+
### Flamegraphs
|
93
|
+
|
94
|
+
Rails Mini Profiler automatically records Flamegraphs for profiled requests. To enable this feature, add [Stackprof](https://github.com/tmm1/stackprof)
|
95
|
+
to your Gemfile:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
gem 'stackprof'
|
99
|
+
```
|
100
|
+
|
101
|
+
For convenience, Flamegraphs are recorded for every request. This may incur a significant performance penalty. To change the default behavior see [Configuration](#Configuration).
|
102
|
+
|
103
|
+
Flamegraphs are rendered using [Speedscope](https://github.com/jlfwong/speedscope). See [Troubleshooting](#Troubleshooting) if Flamegraphs are not rendering correctly.
|
104
|
+
|
105
|
+
## Configuration
|
106
|
+
|
107
|
+
Rails Mini Profiler provides a wide array of configuration options. You can find details below. For an example configuration check `initializers/rails_mini_profiler.rb` (or [the template file](https://github.com/hschne/rails-mini-profiler/blob/main/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.rb.erb)).
|
108
|
+
|
109
|
+
| Name | Default | Description |
|
110
|
+
|--------------------------|------------------------------|-------------------------------------------------------------------------------------------------|
|
111
|
+
| `enabled` | `true` (dev)/ `false` (prod) | Whether or not RMP is enabled |
|
112
|
+
| `flamegraph_enabled` | `true` | Should flamegraphs be recorded automatically? |
|
113
|
+
| `flamegraph_sample_rate` | `0.5` | The flamegraph sample rate. How many snapshots per millisecond are created. |
|
114
|
+
| `skip_paths` | `[]` | An array of request paths that should not be profiled. Regex allowed. |
|
115
|
+
| `storage` | `Storage.new` | Storage configuration. See [Storage](#Storage). |
|
116
|
+
| `ui` | `UserInterface.new` | UI configuration. See [UI](#UI). |
|
117
|
+
| `user_provider` | `Rack::Request.new(env).ip` | How to identify users. See [Users](#Users) |
|
118
|
+
|
119
|
+
### Request Configuration
|
120
|
+
|
121
|
+
You may override the configuration by sending request parameters. The following parameters are available:
|
122
|
+
|
123
|
+
| Name | Description |
|
124
|
+
| ---------------- | ------------------------------------------------------------------------------------------- |
|
125
|
+
| `rmp_flamegraph` | Overrides `flamegraph_enabled` If set to `true` will redirect to the flamegraph immediatly. |
|
126
|
+
|
127
|
+
### Storage
|
128
|
+
|
129
|
+
Rails Mini Profiler stores profiling information in your database per default. You can configure various details of how
|
130
|
+
traces and requests are stored.
|
131
|
+
|
132
|
+
| Name | Default | Description |
|
133
|
+
| ------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------- |
|
134
|
+
| `database` | `nil` | Set a custom database to be used for storing profiler information. Uses `connect_to` for profiler records |
|
135
|
+
| `profiled_requests_table` | `rmp_profiled_requests` | The table to be used to store profiled requests. |
|
136
|
+
| `flamegraphs_table` | `rmp_flamegraphs` | The table to be used to store flamegraphs. |
|
137
|
+
| `traces_table` | `rmp_traces` | The table to be used to store traces. |
|
138
|
+
|
139
|
+
Rails Mini Profiler does not offer an automatic way to clean up old profiling information. It is recommended you add a sweeper job to clean up old profiled requests periodically (e.g. using [clockwork](https://github.com/adamwiggins/clockwork). For example, with ActiveJob:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
# Clockwork
|
143
|
+
every(1.month, 'purge rails mini profiler' do
|
144
|
+
ProfiledRequestCleanupJob.perform_later
|
145
|
+
end
|
146
|
+
|
147
|
+
# ActiveJob
|
148
|
+
class ProfiledRequestCleanupJob < ApplicationJob
|
149
|
+
queue_as :default
|
150
|
+
|
151
|
+
def perform
|
152
|
+
RailsMiniProfiler::ProfiledRequest.where('created_at < ?', 1.month.ago).destroy_all
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
### UI
|
158
|
+
|
159
|
+
Rails Mini Profiler allows you to configure various UI features.
|
160
|
+
|
161
|
+
| Name | Default | Description |
|
162
|
+
|------------------|--------------|-------------------------------------------------------------------------------------------------|
|
163
|
+
| `badge_enabled` | `true` | Should the hedgehog 🦔 badge be injected into pages? |
|
164
|
+
| `badge_position` | `'top-left'` | Where to display the badge. Options are `'top-left', 'top-right', 'bottom-left, 'bottom-right'` |
|
165
|
+
| `page_size` | `25` | The page size for lists shown in the UI. |
|
166
|
+
|
167
|
+
### Users
|
168
|
+
|
169
|
+
Profiling information is segregated by user ID. That means users cannot see each other's profiled requests.
|
170
|
+
|
171
|
+
Per default, individual users are identified by their IP address. You may change this by setting a custom user provider:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
config.user_provider = proc { |env| Rack::Request.new(env).ip }
|
175
|
+
```
|
176
|
+
|
177
|
+
You may also explicitly set the user from the application itself:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
class ApplicationController < ActionController::Base
|
181
|
+
before_action do
|
182
|
+
RailsMiniProfiler::User.authorize(current_user.id)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
Note that you **must** set the current user when running Rails Mini Profiler in production. No profiles will be saved otherwise.
|
188
|
+
|
189
|
+
### Profiling in Production
|
190
|
+
|
191
|
+
Rails Mini Profiler is not intended for performance reporting. There are other tools for that ( [Skylight](https://www.skylight.io/),
|
192
|
+
[New Relic](https://newrelic.com/), [DataDog](https://www.datadoghq.com/)...).
|
193
|
+
|
194
|
+
However, you can still use it in production to profile specific requests. Since profiling impacts performance, it is recommended
|
195
|
+
that you limit which requests are being profiled:
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
RailsMiniProfiler.configure do |config|
|
199
|
+
config.enabled = proc { |env| env.headers['RMP_ENABLED'].present? }
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
Only requests by explicitly set users will be stored. To configure how individual users are identified see [Users](#Users)
|
204
|
+
|
205
|
+
## Why Rails Mini Profiler?
|
206
|
+
|
207
|
+
Improving the performance of any application is a 3-step process. You have to answer these questions:
|
208
|
+
|
209
|
+
1. What is slow?
|
210
|
+
2. Why is it slow?
|
211
|
+
3. Did my solution fix the slowness?
|
212
|
+
|
213
|
+
I'm a huge fan of [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler), and AMP tools such as [Skylight](https://www.skylight.io/) or [Scout APM](https://scoutapm.com), and each of these tools has its place.
|
214
|
+
|
215
|
+
APM tools are excellent for profiling your app in production - aka. they show you what is slow - and offer _some_ hints as to what causes the slowdown. `rack-mini-profiler` can do some sampling in production, but excels at providing detailed insight into _why_ something is slow, using Flamegraphs and detailed query information.
|
216
|
+
|
217
|
+
Rails Mini Profiler improves upon `rack-mini-profiler` in the latter regard. It is a developer tool, rather than a monitoring tool, and sets a big focus on developer experience. Simply put, it aims to be the best tool available to help you figure out _why_ specific requests are slow.
|
218
|
+
|
219
|
+
As such, compared to `rack-mini-profiler`, it does not support non-Rails apps (e.g. Sinatra) or production sampling, but provides a much better user experience and better supports API-only applications.
|
220
|
+
|
221
|
+
## Troubleshooting
|
222
|
+
|
223
|
+
### Upgrading
|
224
|
+
|
225
|
+
Rails Mini Profiler is in early development. As such, breaking changes may still be introduced on a regular basis. While Rails Mini Profiler is in pre-release we do not offer upgrade migrations.
|
226
|
+
|
227
|
+
If an upgrade to Rails Mini Profiler breaks your application, we recommend that you clean house and start over. Re-run the initializer and overwrite existing files:
|
228
|
+
|
229
|
+
```bash
|
230
|
+
rails rails_mini_profiler:install
|
231
|
+
```
|
232
|
+
|
233
|
+
If only the DB schema is out of date, drop the offending tables and re-run migrations for the latest version:
|
234
|
+
|
235
|
+
```
|
236
|
+
rails rails_mini_profiler:install:migrations
|
237
|
+
rails db:migrate
|
238
|
+
```
|
239
|
+
|
240
|
+
### Support for API-Only Apps
|
241
|
+
|
242
|
+
Rails Mini Profiler supports API-only apps, but you have to make some small adjustments to use it. At the top of `application.rb` add [Sprockets](https://github.com/rails/sprockets-rails):
|
243
|
+
|
244
|
+
```
|
245
|
+
require "sprockets/railtie"
|
246
|
+
```
|
247
|
+
|
248
|
+
Then, modify `application.rb`:
|
249
|
+
|
250
|
+
```
|
251
|
+
module ApiOnly
|
252
|
+
class Application < Rails::Application
|
253
|
+
|
254
|
+
config.api_only = true # Either set this to false
|
255
|
+
config.middleware.use ActionDispatch::Flash # Or add this
|
256
|
+
end
|
257
|
+
end
|
258
|
+
```
|
259
|
+
|
260
|
+
**Note: Sprockets and flash are currently required for some of Rails Mini Profiler's UI features. These modifications may no longer be needed in the future.
|
261
|
+
|
262
|
+
### No Flamegraphs are being recored?
|
263
|
+
|
264
|
+
Make sure you have added [StackProf](https://github.com/tmm1/stackprof) to your Gemfile.
|
265
|
+
|
266
|
+
```ruby
|
267
|
+
gem 'stackprof'
|
268
|
+
```
|
269
|
+
|
270
|
+
### Flamegraphs are not rendering?
|
271
|
+
|
272
|
+
Flamegraphs are loaded into [Speedscope](https://github.com/jlfwong/speedscope) using an Iframe and URI Encoded blobs (see [source](https://github.com/hschne/rails-mini-profiler/blob/main/app/views/rails_mini_profiler/flamegraphs/show.html.erb))
|
273
|
+
If your browser gives you warnings about blocking content due to CSP you _must_ enable `blob` as default source:
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
Rails.application.config.content_security_policy do |policy|
|
277
|
+
policy.default_src :self, :blob
|
278
|
+
...
|
279
|
+
end
|
280
|
+
```
|
281
|
+
|
282
|
+
### Some requests have no Flamegraphs attached?
|
283
|
+
|
284
|
+
[StackProf](https://github.com/tmm1/stackprof), which is used for recording Flamegraphs, does not work on concurrent requests.
|
285
|
+
Because of this, concurrent requests may skip recording a Flamegraph.
|
286
|
+
|
287
|
+
It is recommended that you resend _only_ the request you wish to build a Flamegraph for.
|
288
|
+
|
289
|
+
## Credit
|
290
|
+
|
291
|
+
This project was heavily inspired by projects such as [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler) and
|
292
|
+
[rack-profiler](https://github.com/dawanda/rack-profiler). [Skylight](https://www.skylight.io/) was also a huge influence.
|
293
|
+
|
294
|
+
[Lena Schnedlitz](https://github.com/LenaSchnedlitz) designed the Logo and provided great support. Without her supreme CSS skills this project would not have been possible 🙌
|
295
|
+
|
296
|
+
## Contributing
|
297
|
+
|
298
|
+
See [Contributing](CONTRIBUTING.md)
|
299
|
+
|
300
|
+
## License
|
301
|
+
|
302
|
+
This gem is available as open source under the terms of the [MIT License](LICENSE).
|
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/rails_mini_profiler .css
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require rails-ujs
|
14
|
+
//= require_tree .
|
15
|
+
//= require rails-mini-profiler
|
@@ -0,0 +1,16 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*= require rails-mini-profiler
|
16
|
+
*/
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsMiniProfiler
|
4
|
+
class ApplicationController < ActionController::Base
|
5
|
+
include Pagy::Backend
|
6
|
+
|
7
|
+
rescue_from ActiveRecord::RecordNotFound, with: ->(error) { handle(error, 404) }
|
8
|
+
|
9
|
+
before_action :check_current_user
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def present(model, presenter_class = nil, **kwargs)
|
14
|
+
klass = presenter_class || "RailsMiniProfiler::#{model.class.to_s.demodulize}Presenter".constantize
|
15
|
+
presenter = klass.new(model, view_context, **kwargs)
|
16
|
+
yield(presenter) if block_given?
|
17
|
+
presenter
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def handle(error, status = 500)
|
23
|
+
respond_to do |format|
|
24
|
+
format.html { redirect_back(fallback_location: profiled_requests_path, alert: error.to_s) }
|
25
|
+
format.json { render status: status, json: { message: error.to_s } }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def check_current_user
|
30
|
+
redirect_back(fallback_location: root_path) unless User.get(request.env).present?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency 'rails_mini_profiler/application_controller'
|
4
|
+
|
5
|
+
module RailsMiniProfiler
|
6
|
+
class FlamegraphsController < ApplicationController
|
7
|
+
layout 'rails_mini_profiler/flamegraph'
|
8
|
+
|
9
|
+
before_action :set_flamegraph, only: %i[show]
|
10
|
+
|
11
|
+
def show; end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def set_flamegraph
|
16
|
+
@flamegraph = Flamegraph.find_by!(rmp_profiled_request_id: params[:id]).json_data
|
17
|
+
end
|
18
|
+
|
19
|
+
def configuration
|
20
|
+
@configuration ||= RailsMiniProfiler.configuration
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency 'rails_mini_profiler/application_controller'
|
4
|
+
|
5
|
+
module RailsMiniProfiler
|
6
|
+
class ProfiledRequestsController < ApplicationController
|
7
|
+
before_action :set_profiled_request, only: %i[show destroy]
|
8
|
+
|
9
|
+
def index
|
10
|
+
@profiled_requests = ProfiledRequest.where(user_id: user_id).order(id: :desc)
|
11
|
+
search = ProfiledRequestSearch.new(index_params, scope: @profiled_requests)
|
12
|
+
@pagy, @profiled_requests = pagy(search.results, items: configuration.ui.page_size)
|
13
|
+
@profiled_requests = @profiled_requests.map { |request| present(request) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def show
|
17
|
+
@traces = @profiled_request.traces
|
18
|
+
@traces = @traces.where("#{payload_column} LIKE ?", "%#{params[:search]}%") if params[:search]
|
19
|
+
@traces = @traces
|
20
|
+
.order(:start)
|
21
|
+
.map { |trace| present(trace, profiled_request: @profiled_request) }
|
22
|
+
@profiled_request = present(@profiled_request)
|
23
|
+
end
|
24
|
+
|
25
|
+
def destroy
|
26
|
+
ProfiledRequest.where(user_id: user_id).destroy(@profiled_request.id)
|
27
|
+
redirect_to profiled_requests_url, notice: 'Profiled request was successfully destroyed.'
|
28
|
+
end
|
29
|
+
|
30
|
+
def destroy_all
|
31
|
+
ProfiledRequest.transaction do
|
32
|
+
profiled_requests = ProfiledRequest.where(user_id: user_id)
|
33
|
+
profiled_requests = ProfiledRequestSearch.new(index_params, scope: profiled_requests).results
|
34
|
+
Flamegraph.joins(:profiled_request).merge(profiled_requests).delete_all
|
35
|
+
Trace.joins(:profiled_request).merge(profiled_requests).delete_all
|
36
|
+
profiled_requests.delete_all
|
37
|
+
end
|
38
|
+
redirect_to profiled_requests_url, notice: 'Profiled requests cleared', status: :see_other
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def index_params
|
44
|
+
params.permit(:path, :duration, id: [], method: [], media_type: [], status: [])
|
45
|
+
end
|
46
|
+
|
47
|
+
def user_id
|
48
|
+
@user_id ||= User.get(request.env)
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_profiled_request
|
52
|
+
@profiled_request = ProfiledRequest.where(user_id: user_id).find(params[:id])
|
53
|
+
end
|
54
|
+
|
55
|
+
def configuration
|
56
|
+
@configuration ||= RailsMiniProfiler.configuration
|
57
|
+
end
|
58
|
+
|
59
|
+
def payload_column
|
60
|
+
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
61
|
+
# Cast json field to text to have access to the LIKE operator
|
62
|
+
'payload::text'
|
63
|
+
else
|
64
|
+
'payload'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|