rails_mini_profiler 0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +302 -0
  4. data/app/assets/config/rails_mini_profiler_manifest.js +1 -0
  5. data/app/assets/javascripts/rails_mini_profiler.js +15 -0
  6. data/app/assets/stylesheets/rails_mini_profiler/application.css +16 -0
  7. data/app/controllers/rails_mini_profiler/application_controller.rb +33 -0
  8. data/app/controllers/rails_mini_profiler/flamegraphs_controller.rb +23 -0
  9. data/app/controllers/rails_mini_profiler/profiled_requests_controller.rb +68 -0
  10. data/app/helpers/rails_mini_profiler/application_helper.rb +23 -0
  11. data/app/helpers/rails_mini_profiler/profiled_requests_helper.rb +16 -0
  12. data/app/javascript/images/bookmark.svg +10 -0
  13. data/app/javascript/images/chart.svg +12 -0
  14. data/app/javascript/images/check.svg +3 -0
  15. data/app/javascript/images/chevron.svg +3 -0
  16. data/app/javascript/images/delete.svg +9 -0
  17. data/app/javascript/images/filter.svg +1 -0
  18. data/app/javascript/images/graph.svg +11 -0
  19. data/app/javascript/images/logo.svg +18 -0
  20. data/app/javascript/images/logo_variant.svg +32 -0
  21. data/app/javascript/images/search.svg +9 -0
  22. data/app/javascript/images/setting.svg +10 -0
  23. data/app/javascript/images/show.svg +11 -0
  24. data/app/javascript/js/checklist_controller.js +48 -0
  25. data/app/javascript/js/enable_controller.js +24 -0
  26. data/app/javascript/js/filter_controller.js +44 -0
  27. data/app/javascript/js/search_controller.js +18 -0
  28. data/app/javascript/js/select_controller.js +47 -0
  29. data/app/javascript/packs/rails-mini-profiler.js +88 -0
  30. data/app/javascript/stylesheets/components/page_header/page_header.scss +3 -0
  31. data/app/javascript/stylesheets/components/pagination.scss +55 -0
  32. data/app/javascript/stylesheets/components/profiled_request_table/placeholder.scss +33 -0
  33. data/app/javascript/stylesheets/components/profiled_request_table/profiled_request_table.scss +179 -0
  34. data/app/javascript/stylesheets/flamegraph.scss +10 -0
  35. data/app/javascript/stylesheets/flashes.scss +15 -0
  36. data/app/javascript/stylesheets/navbar.scss +44 -0
  37. data/app/javascript/stylesheets/profiled_requests.scss +89 -0
  38. data/app/javascript/stylesheets/rails-mini-profiler.scss +205 -0
  39. data/app/javascript/stylesheets/traces.scss +82 -0
  40. data/app/models/rails_mini_profiler/application_record.rb +17 -0
  41. data/app/models/rails_mini_profiler/controller_trace.rb +37 -0
  42. data/app/models/rails_mini_profiler/flamegraph.rb +37 -0
  43. data/app/models/rails_mini_profiler/instantiation_trace.rb +37 -0
  44. data/app/models/rails_mini_profiler/profiled_request.rb +65 -0
  45. data/app/models/rails_mini_profiler/render_partial_trace.rb +37 -0
  46. data/app/models/rails_mini_profiler/render_template_trace.rb +37 -0
  47. data/app/models/rails_mini_profiler/rmp_trace.rb +35 -0
  48. data/app/models/rails_mini_profiler/sequel_trace.rb +37 -0
  49. data/app/models/rails_mini_profiler/trace.rb +46 -0
  50. data/app/presenters/rails_mini_profiler/base_presenter.rb +25 -0
  51. data/app/presenters/rails_mini_profiler/controller_trace_presenter.rb +18 -0
  52. data/app/presenters/rails_mini_profiler/instantiation_trace_presenter.rb +14 -0
  53. data/app/presenters/rails_mini_profiler/profiled_request_presenter.rb +38 -0
  54. data/app/presenters/rails_mini_profiler/render_partial_trace_presenter.rb +11 -0
  55. data/app/presenters/rails_mini_profiler/render_template_trace_presenter.rb +15 -0
  56. data/app/presenters/rails_mini_profiler/rmp_trace_presenter.rb +9 -0
  57. data/app/presenters/rails_mini_profiler/sequel_trace_presenter.rb +69 -0
  58. data/app/presenters/rails_mini_profiler/trace_presenter.rb +61 -0
  59. data/app/search/rails_mini_profiler/base_search.rb +67 -0
  60. data/app/search/rails_mini_profiler/profiled_request_search.rb +34 -0
  61. data/app/views/layouts/rails_mini_profiler/application.html.erb +15 -0
  62. data/app/views/layouts/rails_mini_profiler/flamegraph.html.erb +11 -0
  63. data/app/views/models/_flamegraph.json.jb +3 -0
  64. data/app/views/models/_profiled_request.jb +3 -0
  65. data/app/views/models/_trace.jb +3 -0
  66. data/app/views/rails_mini_profiler/badge.html.erb +37 -0
  67. data/app/views/rails_mini_profiler/flamegraphs/show.html.erb +13 -0
  68. data/app/views/rails_mini_profiler/flamegraphs/show.json.jb +3 -0
  69. data/app/views/rails_mini_profiler/profiled_requests/index.html.erb +9 -0
  70. data/app/views/rails_mini_profiler/profiled_requests/index.json.jb +3 -0
  71. data/app/views/rails_mini_profiler/profiled_requests/shared/_trace.html.erb +40 -0
  72. data/app/views/rails_mini_profiler/profiled_requests/shared/header/_header.erb +20 -0
  73. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_placeholder.erb +12 -0
  74. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table.erb +14 -0
  75. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_head.erb +125 -0
  76. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_row.erb +21 -0
  77. data/app/views/rails_mini_profiler/profiled_requests/show.html.erb +40 -0
  78. data/app/views/rails_mini_profiler/profiled_requests/show.json.jb +5 -0
  79. data/app/views/rails_mini_profiler/shared/_flashes.html.erb +8 -0
  80. data/app/views/rails_mini_profiler/shared/_head.erb +13 -0
  81. data/app/views/rails_mini_profiler/shared/_navbar.html.erb +15 -0
  82. data/config/routes.rb +11 -0
  83. data/db/migrate/20210621185018_create_rmp.rb +46 -0
  84. data/lib/generators/rails_mini_profiler/USAGE +2 -0
  85. data/lib/generators/rails_mini_profiler/install_generator.rb +40 -0
  86. data/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.js.erb +13 -0
  87. data/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.rb.erb +29 -0
  88. data/lib/rails_mini_profiler/badge.rb +84 -0
  89. data/lib/rails_mini_profiler/configuration/storage.rb +47 -0
  90. data/lib/rails_mini_profiler/configuration/user_interface.rb +48 -0
  91. data/lib/rails_mini_profiler/configuration.rb +65 -0
  92. data/lib/rails_mini_profiler/engine.rb +34 -0
  93. data/lib/rails_mini_profiler/flamegraph_guard.rb +47 -0
  94. data/lib/rails_mini_profiler/guard.rb +57 -0
  95. data/lib/rails_mini_profiler/logger.rb +25 -0
  96. data/lib/rails_mini_profiler/middleware.rb +74 -0
  97. data/lib/rails_mini_profiler/models/base_model.rb +23 -0
  98. data/lib/rails_mini_profiler/redirect.rb +33 -0
  99. data/lib/rails_mini_profiler/request_context.rb +86 -0
  100. data/lib/rails_mini_profiler/request_wrapper.rb +69 -0
  101. data/lib/rails_mini_profiler/response_wrapper.rb +32 -0
  102. data/lib/rails_mini_profiler/tracing/controller_tracer.rb +15 -0
  103. data/lib/rails_mini_profiler/tracing/null_trace.rb +7 -0
  104. data/lib/rails_mini_profiler/tracing/sequel_tracer.rb +37 -0
  105. data/lib/rails_mini_profiler/tracing/sequel_tracker.rb +37 -0
  106. data/lib/rails_mini_profiler/tracing/subscriptions.rb +34 -0
  107. data/lib/rails_mini_profiler/tracing/trace.rb +45 -0
  108. data/lib/rails_mini_profiler/tracing/trace_factory.rb +37 -0
  109. data/lib/rails_mini_profiler/tracing/tracer.rb +31 -0
  110. data/lib/rails_mini_profiler/tracing/view_tracer.rb +12 -0
  111. data/lib/rails_mini_profiler/tracing.rb +11 -0
  112. data/lib/rails_mini_profiler/user.rb +40 -0
  113. data/lib/rails_mini_profiler/version.rb +5 -0
  114. data/lib/rails_mini_profiler.rb +79 -0
  115. data/lib/tasks/rails_mini_profiler_tasks.rake +8 -0
  116. data/public/rails_mini_profiler/speedscope/LICENSE +21 -0
  117. data/public/rails_mini_profiler/speedscope/demangle-cpp.1768f4cc.js +4 -0
  118. data/public/rails_mini_profiler/speedscope/demangle-cpp.1768f4cc.js.map +1 -0
  119. data/public/rails_mini_profiler/speedscope/favicon-16x16.f74b3187.png +0 -0
  120. data/public/rails_mini_profiler/speedscope/favicon-32x32.bc503437.png +0 -0
  121. data/public/rails_mini_profiler/speedscope/file-format-schema.json +324 -0
  122. data/public/rails_mini_profiler/speedscope/import.e3a73ef4.js +117 -0
  123. data/public/rails_mini_profiler/speedscope/import.e3a73ef4.js.map +1 -0
  124. data/public/rails_mini_profiler/speedscope/index.html +2 -0
  125. data/public/rails_mini_profiler/speedscope/release.txt +3 -0
  126. data/public/rails_mini_profiler/speedscope/reset.8c46b7a1.css +2 -0
  127. data/public/rails_mini_profiler/speedscope/reset.8c46b7a1.css.map +1 -0
  128. data/public/rails_mini_profiler/speedscope/source-map.438fa06b.js +24 -0
  129. data/public/rails_mini_profiler/speedscope/source-map.438fa06b.js.map +1 -0
  130. data/public/rails_mini_profiler/speedscope/speedscope.026f36b0.js +200 -0
  131. data/public/rails_mini_profiler/speedscope/speedscope.026f36b0.js.map +1 -0
  132. data/vendor/assets/images/bookmark.svg +10 -0
  133. data/vendor/assets/images/chart.svg +12 -0
  134. data/vendor/assets/images/check.svg +3 -0
  135. data/vendor/assets/images/chevron.svg +3 -0
  136. data/vendor/assets/images/delete.svg +9 -0
  137. data/vendor/assets/images/filter.svg +1 -0
  138. data/vendor/assets/images/graph.svg +11 -0
  139. data/vendor/assets/images/logo.svg +18 -0
  140. data/vendor/assets/images/logo_variant.svg +32 -0
  141. data/vendor/assets/images/search.svg +9 -0
  142. data/vendor/assets/images/setting.svg +10 -0
  143. data/vendor/assets/images/show.svg +11 -0
  144. data/vendor/assets/javascripts/rails-mini-profiler.css +1 -0
  145. data/vendor/assets/javascripts/rails-mini-profiler.js +1 -0
  146. 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
+ &nbsp; &nbsp; &nbsp; &nbsp;
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