rack-mini-profiler 2.3.4 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +65 -68
- data/lib/generators/rack_mini_profiler/USAGE +9 -0
- data/lib/generators/rack_mini_profiler/install_generator.rb +13 -0
- data/lib/generators/{rack_profiler/templates/rack_profiler.rb → rack_mini_profiler/templates/rack_mini_profiler.rb} +1 -1
- data/lib/generators/rack_profiler/install_generator.rb +6 -3
- data/lib/mini_profiler/config.rb +7 -4
- data/lib/mini_profiler/storage/abstract_store.rb +30 -57
- data/lib/mini_profiler/storage/file_store.rb +2 -0
- data/lib/mini_profiler/storage/memory_store.rb +56 -12
- data/lib/mini_profiler/storage/redis_store.rb +144 -61
- data/lib/mini_profiler/storage.rb +7 -0
- data/lib/mini_profiler/timer_struct/base.rb +2 -0
- data/lib/mini_profiler/timer_struct/sql.rb +2 -0
- data/lib/mini_profiler/timer_struct.rb +8 -0
- data/lib/mini_profiler/version.rb +1 -1
- data/lib/{mini_profiler/profiler.rb → mini_profiler.rb} +103 -69
- data/lib/patches/net_patches.rb +18 -17
- data/lib/rack-mini-profiler.rb +1 -24
- data/rack-mini-profiler.gemspec +2 -2
- metadata +12 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7544df4d22f5f615b146fb0d63f18098ffd702ac9dec966d8040187f2e8302b9
|
4
|
+
data.tar.gz: 7c39c41a96205c8c7fbd69765ab5f1e0a3a3a37950055fc58d0f27f4a0591e0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e3f5f9a51fc5395dda4a7e793903f998513499d850aeb291fe036171a78617d11c3d8cd6fef57d1144359aa4992055ad54ba878075896c3d0280c426a84e3be
|
7
|
+
data.tar.gz: c4e353c8442db93f29d11d04e2724e6c3f8dacaaf082210acbbb7d47655ffc3a6b5297079750e305fe9f1cd3e7efb1d806aef0ec68bbc1a8e40a0f958de0ec52
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.1.0 - 2023-04-11
|
4
|
+
|
5
|
+
- [FEATURE] The query parameter that RMP uses (by default, pp) is now configurable [#553](https://github.com/MiniProfiler/rack-mini-profiler/pull/553)
|
6
|
+
- [FEATURE] You can now opt-out of the Net::HTTP patch by using RACK_MINI_PROFILER_PATCH_NET_HTTP="false"
|
7
|
+
- [FIX] Error responses now include header values from the app, and stackprof not installed message now has correct content [#547](https://github.com/MiniProfiler/rack-mini-profiler/pull/547)
|
8
|
+
- [FIX] RMP pages now have more valid HTML, with title elements [#562](https://github.com/MiniProfiler/rack-mini-profiler/pull/562)
|
9
|
+
- [BREAKING CHANGE] Ruby 2.4 and Ruby 2.5 are no longer supported.
|
10
|
+
- [FIX] Now works with apps that don't otherwise require erb [#531](https://github.com/MiniProfiler/rack-mini-profiler/pull/531)
|
11
|
+
- [DOCS] Added Heroku Redis instructions
|
12
|
+
- [DEPRECATION] We are changing the name of the generators to `rack_mini_profiler`, e.g. `rack_mini_profiler:install` [#550](https://github.com/MiniProfiler/rack-mini-profiler/pull/550)
|
13
|
+
|
14
|
+
## 3.0.0 - 2022-02-24
|
15
|
+
|
16
|
+
- PERF: Improve snapshots page performance (#518) (introduces breaking changes to the API of `AbstractStore`, `MemoryStore` and `RedisStore`, and removes the `snapshots_limit` config option.)
|
17
|
+
|
3
18
|
## 2.3.4 - 2022-02-23
|
4
19
|
|
5
20
|
- [FEATURE] Add cookie path support for subfolder sites
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# rack-mini-profiler
|
2
2
|
|
3
|
-
Middleware that displays speed badge for every
|
3
|
+
Middleware that displays speed badge for every HTML page, along with (optional) flamegraphs and memory profiling. Designed to work both in production and in development.
|
4
|
+
|
5
|
+
![Screenshot 2023-04-05 at 3 13 52 PM](https://user-images.githubusercontent.com/845662/229996538-0f2d9c48-23d9-4d53-a1de-8b4c84c87fbd.png)
|
4
6
|
|
5
7
|
#### Features
|
6
8
|
|
@@ -27,7 +29,7 @@ If you feel like taking on any of this start an issue and update us on your prog
|
|
27
29
|
|
28
30
|
## Installation
|
29
31
|
|
30
|
-
Install/add to Gemfile in Ruby 2.
|
32
|
+
Install/add to Gemfile in Ruby 2.6+
|
31
33
|
|
32
34
|
```ruby
|
33
35
|
gem 'rack-mini-profiler'
|
@@ -101,7 +103,7 @@ be loaded outright, and an attempt to re-initialize it manually will raise an ex
|
|
101
103
|
Then run the generator which will set up rack-mini-profiler in development:
|
102
104
|
|
103
105
|
```bash
|
104
|
-
bundle exec rails g
|
106
|
+
bundle exec rails g rack_mini_profiler:install
|
105
107
|
```
|
106
108
|
|
107
109
|
#### Rack Builder
|
@@ -164,11 +166,19 @@ export RACK_MINI_PROFILER_PATCH="false"
|
|
164
166
|
# initializers/rack_profiler.rb: SqlPatches.patch %w(mongo)
|
165
167
|
```
|
166
168
|
|
169
|
+
#### Patching Net::HTTP
|
170
|
+
|
171
|
+
Other than databases, `rack-mini-profiler` applies a patch to `Net::HTTP`. You may want to disable this patch:
|
172
|
+
|
173
|
+
```bash
|
174
|
+
export RACK_MINI_PROFILER_PATCH_NET_HTTP="false"
|
175
|
+
```
|
176
|
+
|
167
177
|
### Flamegraphs
|
168
178
|
|
169
179
|
To generate [flamegraphs](http://samsaffron.com/archive/2013/03/19/flame-graphs-in-ruby-miniprofiler), add the [**stackprof**](https://rubygems.org/gems/stackprof) gem to your Gemfile.
|
170
180
|
|
171
|
-
Then, to view the flamegraph as a direct HTML response from your request, just visit any page in your app with `?pp=flamegraph` appended to the URL.
|
181
|
+
Then, to view the flamegraph as a direct HTML response from your request, just visit any page in your app with `?pp=flamegraph` appended to the URL.
|
172
182
|
|
173
183
|
Conversely, if you want your regular response instead (which is specially useful for JSON and/or XHR requests), just append the `?pp=async-flamegraph` parameter to your request/fetch URL; the request will then return as normal, and the flamegraph data will be stored for later *async* viewing, both for this request and for all subsequent requests made by this page (based on the `REFERER` header). For viewing these async flamegraphs, use the 'flamegraph' link that will appear inside the MiniProfiler UI for these requests.
|
174
184
|
|
@@ -207,7 +217,7 @@ After enabling snapshots sampling, you can see the snapshots that have been coll
|
|
207
217
|
|
208
218
|
Access to the snapshots page is restricted to only those who can see the speed badge on their own requests, see the section below this one about access control.
|
209
219
|
|
210
|
-
Mini Profiler will keep a maximum of
|
220
|
+
Mini Profiler will keep a maximum of 50 snapshot groups and a maximum of 15 snapshots per group making the default maximum number of snapshots in the system 750. The default group and per group limits can be changed via the `max_snapshot_groups` and `max_snapshots_per_group` configuration options, see the configurations table below.
|
211
221
|
|
212
222
|
#### Snapshots Transporter
|
213
223
|
|
@@ -406,38 +416,40 @@ Rack::MiniProfiler.config.start_hidden = true
|
|
406
416
|
```
|
407
417
|
The available configuration options are:
|
408
418
|
|
409
|
-
Option|Default|Description
|
410
|
-
|
411
|
-
pre_authorize_cb|Rails: dev only<br>Rack: always on|A lambda callback that returns true to make mini_profiler visible on a given request.
|
412
|
-
position
|
413
|
-
skip_paths
|
414
|
-
skip_schema_queries|Rails dev: `true`<br>Othwerwise: `false
|
415
|
-
auto_inject
|
416
|
-
backtrace_ignores
|
417
|
-
backtrace_includes|Rails: `[/^\/?(app\|config\|lib\|test)/]`<br>Rack: `[]
|
418
|
-
backtrace_remove|rails: `Rails.root`<br>Rack: `nil
|
419
|
-
toggle_shortcut|Alt+P|Keyboard shortcut to toggle the mini_profiler's visibility. See [jquery.hotkeys](https://github.com/jeresig/jquery.hotkeys).
|
420
|
-
start_hidden
|
421
|
-
backtrace_threshold_ms
|
422
|
-
flamegraph_sample_rate
|
423
|
-
flamegraph_mode
|
424
|
-
base_url_path
|
425
|
-
cookie_path
|
426
|
-
collapse_results
|
427
|
-
max_traces_to_show|20|Maximum number of mini profiler timing blocks to show on one page
|
428
|
-
html_container
|
429
|
-
show_total_sql_count
|
430
|
-
enable_advanced_debugging_tools
|
431
|
-
assets_url
|
432
|
-
snapshot_every_n_requests
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
419
|
+
Option | Default | Description
|
420
|
+
------------------------------------|---------------------------------------------------------|------------------------
|
421
|
+
pre_authorize_cb | Rails: dev only<br>Rack: always on | A lambda callback that returns true to make mini_profiler visible on a given request.
|
422
|
+
position | `'top-left'` | Display mini_profiler on `'top-right'`, `'top-left'`, `'bottom-right'` or `'bottom-left'`.
|
423
|
+
skip_paths | `[]` | An array of paths that skip profiling. Both `String` and `Regexp` are acceptable in the array.
|
424
|
+
skip_schema_queries | Rails dev: `true`<br>Othwerwise: `false` | `true` to skip schema queries.
|
425
|
+
auto_inject | `true` | `true` to inject the miniprofiler script in the page.
|
426
|
+
backtrace_ignores | `[]` | Regexes of lines to be removed from backtraces.
|
427
|
+
backtrace_includes | Rails: `[/^\/?(app\|config\|lib\|test)/]`<br>Rack: `[]` | Regexes of lines to keep in backtraces.
|
428
|
+
backtrace_remove | rails: `Rails.root`<br>Rack: `nil` | A string or regex to remove part of each line in the backtrace.
|
429
|
+
toggle_shortcut | Alt+P | Keyboard shortcut to toggle the mini_profiler's visibility. See [jquery.hotkeys](https://github.com/jeresig/jquery.hotkeys).
|
430
|
+
start_hidden | `false` | `false` to make mini_profiler visible on page load.
|
431
|
+
backtrace_threshold_ms | `0` | Minimum SQL query elapsed time before a backtrace is recorded.
|
432
|
+
flamegraph_sample_rate | `0.5` | How often to capture stack traces for flamegraphs in milliseconds.
|
433
|
+
flamegraph_mode | `:wall` | The [StackProf mode](https://github.com/tmm1/stackprof#all-options) to pass to `StackProf.run`.
|
434
|
+
base_url_path | `'/mini-profiler-resources/'` | Path for assets; added as a prefix when naming assets and sought when responding to requests.
|
435
|
+
cookie_path | `'/'` | Set-Cookie header path for profile cookie
|
436
|
+
collapse_results | `true` | If multiple timing results exist in a single page, collapse them till clicked.
|
437
|
+
max_traces_to_show | 20 | Maximum number of mini profiler timing blocks to show on one page
|
438
|
+
html_container | `body` | The HTML container (as a jQuery selector) to inject the mini_profiler UI into
|
439
|
+
show_total_sql_count | `false` | Displays the total number of SQL executions.
|
440
|
+
enable_advanced_debugging_tools | `false` | Enables sensitive debugging tools that can be used via the UI. In production we recommend keeping this disabled as memory and environment debugging tools can expose contents of memory that may contain passwords. Defaults to `true` in development.
|
441
|
+
assets_url | `nil` | See the "Register MiniProfiler's assets in the Rails assets pipeline" section above.
|
442
|
+
snapshot_every_n_requests | `-1` | Determines how frequently snapshots are taken. See the "Snapshots Sampling" above for more details.
|
443
|
+
max_snapshot_groups | `50` | Determines how many snapshot groups Mini Profiler is allowed to keep.
|
444
|
+
max_snapshots_per_group | `15` | Determines how many snapshots per group Mini Profiler is allowed to keep.
|
445
|
+
snapshot_hidden_custom_fields | `[]` | Each snapshot custom field will have a dedicated column in the UI by default. Use this config to exclude certain custom fields from having their own columns.
|
446
|
+
snapshots_transport_destination_url | `nil` | Set this config to a valid URL to enable snapshots transporter which will `POST` snapshots to the given URL. The transporter requires `snapshots_transport_auth_key` config to be set as well.
|
447
|
+
snapshots_transport_auth_key | `nil` | `POST` requests made by the snapshots transporter to the destination URL will have a `Mini-Profiler-Transport-Auth` header with the value of this config. Make sure you use a secure and random key for this config.
|
448
|
+
snapshots_redact_sql_queries | `true` | When this is true, SQL queries will be redacted from sampling snapshots, but the backtrace and duration of each SQL query will be saved with the snapshot to keep debugging performance issues possible.
|
449
|
+
snapshots_transport_gzip_requests | `false` | Make the snapshots transporter gzip the requests it makes to `snapshots_transport_destination_url`.
|
450
|
+
content_security_policy_nonce | Rails: Current nonce<br>Rack: nil | Set the content security policy nonce to use when inserting MiniProfiler's script block.
|
451
|
+
enable_hotwire_turbo_drive_support | `false` | Enable support for Hotwire TurboDrive page transitions.
|
452
|
+
profile_parameter | `'pp'` | The query parameter used to interact with this gem.
|
441
453
|
|
442
454
|
### Using MiniProfiler with `Rack::Deflate` middleware
|
443
455
|
|
@@ -447,41 +459,26 @@ which means it will run after `Rack::Deflate` on response processing. To prevent
|
|
447
459
|
HTML in already compressed response body MiniProfiler will suppress compression by setting
|
448
460
|
`identity` encoding in `Accept-Encoding` request header.
|
449
461
|
|
450
|
-
|
451
|
-
|
452
|
-
If you include the query string `pp=help` at the end of your request you will see the various options available. You can use these options to extend or contract the amount of diagnostics rack-mini-profiler gathers.
|
453
|
-
|
454
|
-
|
455
|
-
## Rails 2.X support
|
462
|
+
### Using MiniProfiler with Heroku Redis
|
456
463
|
|
457
|
-
|
458
|
-
|
459
|
-
Add the following code to your environment.rb (or just in a specific environment such as development.rb) for initialization and configuration of MiniProfiler.
|
464
|
+
If you are using Heroku Redis, you may need to add the following to your `config/initializers/mini_profiler.rb`, in order to get Mini Profiler to work:
|
460
465
|
|
461
466
|
```ruby
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
tmp = Rails.root.to_s + "/tmp/miniprofiler"
|
469
|
-
FileUtils.mkdir_p(tmp) unless File.exist?(tmp)
|
470
|
-
c.storage_options = {:path => tmp}
|
471
|
-
c.storage = ::Rack::MiniProfiler::FileStore
|
472
|
-
config.middleware.use(::Rack::MiniProfiler)
|
473
|
-
::Rack::MiniProfiler.profile_method(ActionController::Base, :process) {|action| "Executing action: #{action}"}
|
474
|
-
::Rack::MiniProfiler.profile_method(ActionView::Template, :render) {|x,y| "Rendering: #{path_without_format_and_extension}"}
|
475
|
-
|
476
|
-
# monkey patch away an activesupport and json_pure incompatability
|
477
|
-
# http://pivotallabs.com/users/alex/blog/articles/1332-monkey-patch-of-the-day-activesupport-vs-json-pure-vs-ruby-1-8
|
478
|
-
if JSON.const_defined?(:Pure)
|
479
|
-
class JSON::Pure::Generator::State
|
480
|
-
include ActiveSupport::CoreExtensions::Hash::Except
|
481
|
-
end
|
467
|
+
if Rails.env.production?
|
468
|
+
Rack::MiniProfiler.config.storage_options = {
|
469
|
+
url: ENV["REDIS_URL"],
|
470
|
+
ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }
|
471
|
+
}
|
472
|
+
Rack::MiniProfiler.config.storage = Rack::MiniProfiler::RedisStore
|
482
473
|
end
|
483
474
|
```
|
484
475
|
|
476
|
+
The above code snippet is [Heroku's officially suggested workaround](https://help.heroku.com/HC0F8CUS/redis-connection-issues).
|
477
|
+
|
478
|
+
## Special query strings
|
479
|
+
|
480
|
+
If you include the query string `pp=help` at the end of your request you will see the various options available. You can use these options to extend or contract the amount of diagnostics rack-mini-profiler gathers.
|
481
|
+
|
485
482
|
## Development
|
486
483
|
|
487
484
|
If you want to contribute to this project, that's great, thank you! You can run the following rake task:
|
@@ -500,8 +497,8 @@ Make sure to prepend `bundle exec` before any Rake tasks you run.
|
|
500
497
|
You need Memcached and Redis services running for the specs.
|
501
498
|
|
502
499
|
```
|
503
|
-
$ rake build
|
504
|
-
$ rake spec
|
500
|
+
$ bundle exec rake build
|
501
|
+
$ bundle exec rake spec
|
505
502
|
```
|
506
503
|
|
507
504
|
## Licence
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Description:
|
2
|
+
Generates an initializer for rack-mini-profiler. Use an initializer when manually
|
3
|
+
requiring rack-mini-profiler in your application (using require: false in your Gemfile).
|
4
|
+
|
5
|
+
Example:
|
6
|
+
`bin/rails generate rack_mini_profiler:install`
|
7
|
+
|
8
|
+
This generates a an initializer that requires and initializes
|
9
|
+
rack-mini-profiler in development mode.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RackMiniProfiler
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < ::Rails::Generators::Base
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
7
|
+
|
8
|
+
def create_initializer_file
|
9
|
+
copy_file "rack_mini_profiler.rb", "config/initializers/rack_mini_profiler.rb"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "generators/rack_mini_profiler/install_generator"
|
4
|
+
|
3
5
|
module RackProfiler
|
4
6
|
module Generators
|
5
|
-
class InstallGenerator < ::
|
6
|
-
source_root File.expand_path("templates", __dir__)
|
7
|
+
class InstallGenerator < RackMiniProfiler::Generators::InstallGenerator
|
8
|
+
source_root File.expand_path("../rack_mini_profiler/templates", __dir__)
|
7
9
|
|
8
10
|
def create_initializer_file
|
9
|
-
|
11
|
+
warn("bin/rails generate rack_profiler:install is deprecated. Please use rack_mini_profiler:install instead.")
|
12
|
+
super
|
10
13
|
end
|
11
14
|
end
|
12
15
|
end
|
data/lib/mini_profiler/config.rb
CHANGED
@@ -40,7 +40,8 @@ module Rack
|
|
40
40
|
@skip_sql_param_names = /password/ # skips parameters with the name password by default
|
41
41
|
@enable_advanced_debugging_tools = false
|
42
42
|
@snapshot_every_n_requests = -1
|
43
|
-
@
|
43
|
+
@max_snapshot_groups = 50
|
44
|
+
@max_snapshots_per_group = 15
|
44
45
|
|
45
46
|
# ui parameters
|
46
47
|
@autorized = true
|
@@ -61,6 +62,8 @@ module Rack
|
|
61
62
|
@snapshots_transport_gzip_requests = false
|
62
63
|
@enable_hotwire_turbo_drive_support = false
|
63
64
|
|
65
|
+
@profile_parameter = "pp"
|
66
|
+
|
64
67
|
self
|
65
68
|
}
|
66
69
|
end
|
@@ -73,7 +76,7 @@ module Rack
|
|
73
76
|
:storage_options, :user_provider, :enable_advanced_debugging_tools,
|
74
77
|
:skip_sql_param_names, :suppress_encoding, :max_sql_param_length,
|
75
78
|
:content_security_policy_nonce, :enable_hotwire_turbo_drive_support,
|
76
|
-
:flamegraph_mode
|
79
|
+
:flamegraph_mode, :profile_parameter
|
77
80
|
|
78
81
|
# ui accessors
|
79
82
|
attr_accessor :collapse_results, :max_traces_to_show, :position,
|
@@ -81,10 +84,10 @@ module Rack
|
|
81
84
|
:start_hidden, :toggle_shortcut, :html_container
|
82
85
|
|
83
86
|
# snapshot related config
|
84
|
-
attr_accessor :snapshot_every_n_requests, :
|
87
|
+
attr_accessor :snapshot_every_n_requests, :max_snapshots_per_group,
|
85
88
|
:snapshot_hidden_custom_fields, :snapshots_transport_destination_url,
|
86
89
|
:snapshots_transport_auth_key, :snapshots_redact_sql_queries,
|
87
|
-
:snapshots_transport_gzip_requests
|
90
|
+
:snapshots_transport_gzip_requests, :max_snapshot_groups
|
88
91
|
|
89
92
|
# Deprecated options
|
90
93
|
attr_accessor :use_existing_jquery
|
@@ -45,80 +45,53 @@ module Rack
|
|
45
45
|
raise NotImplementedError.new("should_take_snapshot? is not implemented")
|
46
46
|
end
|
47
47
|
|
48
|
-
def push_snapshot(page_struct, config)
|
48
|
+
def push_snapshot(page_struct, group_name, config)
|
49
49
|
raise NotImplementedError.new("push_snapshot is not implemented")
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
|
52
|
+
# returns a hash where the keys are group names and the values
|
53
|
+
# are hashes that contain 3 keys:
|
54
|
+
# 1. `:worst_score` => the duration of the worst/slowest snapshot in the group (float)
|
55
|
+
# 2. `:best_score` => the duration of the best/fastest snapshot in the group (float)
|
56
|
+
# 3. `:snapshots_count` => the number of snapshots in the group (integer)
|
57
|
+
def fetch_snapshots_overview
|
58
|
+
raise NotImplementedError.new("fetch_snapshots_overview is not implemented")
|
54
59
|
end
|
55
60
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
groups[group_name][:best_score] = snapshot.duration_ms
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
groups = groups.to_a
|
61
|
+
# @param group_name [String]
|
62
|
+
# @return [Array<Rack::MiniProfiler::TimerStruct::Page>] list of snapshots of the group. Blank array if the group doesn't exist.
|
63
|
+
def fetch_snapshots_group(group_name)
|
64
|
+
raise NotImplementedError.new("fetch_snapshots_group is not implemented")
|
65
|
+
end
|
66
|
+
|
67
|
+
def load_snapshot(id, group_name)
|
68
|
+
raise NotImplementedError.new("load_snapshot is not implemented")
|
69
|
+
end
|
70
|
+
|
71
|
+
def snapshots_overview
|
72
|
+
groups = fetch_snapshots_overview.to_a
|
73
73
|
groups.sort_by! { |name, hash| hash[:worst_score] }
|
74
74
|
groups.reverse!
|
75
75
|
groups.map! { |name, hash| hash.merge(name: name) }
|
76
76
|
groups
|
77
77
|
end
|
78
78
|
|
79
|
-
def
|
79
|
+
def snapshots_group(group_name)
|
80
|
+
snapshots = fetch_snapshots_group(group_name)
|
80
81
|
data = []
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
timestamp: snapshot[:started_at],
|
90
|
-
custom_fields: snapshot[:custom_fields]
|
91
|
-
}
|
92
|
-
end
|
93
|
-
end
|
82
|
+
snapshots.each do |snapshot|
|
83
|
+
data << {
|
84
|
+
id: snapshot[:id],
|
85
|
+
duration: snapshot.duration_ms,
|
86
|
+
sql_count: snapshot[:sql_count],
|
87
|
+
timestamp: snapshot[:started_at],
|
88
|
+
custom_fields: snapshot[:custom_fields]
|
89
|
+
}
|
94
90
|
end
|
95
91
|
data.sort_by! { |s| s[:duration] }
|
96
92
|
data.reverse!
|
97
93
|
data
|
98
94
|
end
|
99
|
-
|
100
|
-
def load_snapshot(id)
|
101
|
-
raise NotImplementedError.new("load_snapshot is not implemented")
|
102
|
-
end
|
103
|
-
|
104
|
-
private
|
105
|
-
|
106
|
-
def default_snapshot_grouping(snapshot)
|
107
|
-
group_name = rails_route_from_path(snapshot[:request_path], snapshot[:request_method])
|
108
|
-
group_name ||= snapshot[:request_path]
|
109
|
-
"#{snapshot[:request_method]} #{group_name}"
|
110
|
-
end
|
111
|
-
|
112
|
-
def rails_route_from_path(path, method)
|
113
|
-
if defined?(Rails) && defined?(ActionController::RoutingError)
|
114
|
-
hash = Rails.application.routes.recognize_path(path, method: method)
|
115
|
-
if hash && hash[:controller] && hash[:action]
|
116
|
-
"#{hash[:controller]}##{hash[:action]}"
|
117
|
-
end
|
118
|
-
end
|
119
|
-
rescue ActionController::RoutingError
|
120
|
-
nil
|
121
|
-
end
|
122
95
|
end
|
123
96
|
end
|
124
97
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'securerandom'
|
4
|
+
|
3
5
|
module Rack
|
4
6
|
class MiniProfiler
|
5
7
|
class MemoryStore < AbstractStore
|
@@ -53,6 +55,7 @@ module Rack
|
|
53
55
|
|
54
56
|
@token1, @token2, @cycle_at = nil
|
55
57
|
@snapshots_cycle = 0
|
58
|
+
@snapshot_groups = {}
|
56
59
|
@snapshots = []
|
57
60
|
|
58
61
|
initialize_locks
|
@@ -152,28 +155,69 @@ module Rack
|
|
152
155
|
end
|
153
156
|
end
|
154
157
|
|
155
|
-
def push_snapshot(page_struct, config)
|
158
|
+
def push_snapshot(page_struct, group_name, config)
|
159
|
+
@snapshots_lock.synchronize do
|
160
|
+
group = @snapshot_groups[group_name]
|
161
|
+
if !group
|
162
|
+
@snapshot_groups[group_name] = {
|
163
|
+
worst_score: page_struct.duration_ms,
|
164
|
+
best_score: page_struct.duration_ms,
|
165
|
+
snapshots: [page_struct]
|
166
|
+
}
|
167
|
+
if @snapshot_groups.size > config.max_snapshot_groups
|
168
|
+
group_keys = @snapshot_groups.keys
|
169
|
+
group_keys.sort_by! do |key|
|
170
|
+
@snapshot_groups[key][:worst_score]
|
171
|
+
end
|
172
|
+
group_keys.reverse!
|
173
|
+
group_keys.pop(group_keys.size - config.max_snapshot_groups)
|
174
|
+
@snapshot_groups = @snapshot_groups.slice(*group_keys)
|
175
|
+
end
|
176
|
+
else
|
177
|
+
snapshots = group[:snapshots]
|
178
|
+
snapshots << page_struct
|
179
|
+
snapshots.sort_by!(&:duration_ms)
|
180
|
+
snapshots.reverse!
|
181
|
+
if snapshots.size > config.max_snapshots_per_group
|
182
|
+
snapshots.pop(snapshots.size - config.max_snapshots_per_group)
|
183
|
+
end
|
184
|
+
group[:worst_score] = snapshots[0].duration_ms
|
185
|
+
group[:best_score] = snapshots[-1].duration_ms
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def fetch_snapshots_overview
|
156
191
|
@snapshots_lock.synchronize do
|
157
|
-
|
158
|
-
@
|
159
|
-
|
160
|
-
|
161
|
-
|
192
|
+
groups = {}
|
193
|
+
@snapshot_groups.each do |name, group|
|
194
|
+
groups[name] = {
|
195
|
+
worst_score: group[:worst_score],
|
196
|
+
best_score: group[:best_score],
|
197
|
+
snapshots_count: group[:snapshots].size
|
198
|
+
}
|
162
199
|
end
|
200
|
+
groups
|
163
201
|
end
|
164
202
|
end
|
165
203
|
|
166
|
-
def
|
204
|
+
def fetch_snapshots_group(group_name)
|
167
205
|
@snapshots_lock.synchronize do
|
168
|
-
|
169
|
-
|
206
|
+
group = @snapshot_groups[group_name]
|
207
|
+
if group
|
208
|
+
group[:snapshots].dup
|
209
|
+
else
|
210
|
+
[]
|
170
211
|
end
|
171
212
|
end
|
172
213
|
end
|
173
214
|
|
174
|
-
def load_snapshot(id)
|
215
|
+
def load_snapshot(id, group_name)
|
175
216
|
@snapshots_lock.synchronize do
|
176
|
-
|
217
|
+
group = @snapshot_groups[group_name]
|
218
|
+
if group
|
219
|
+
group[:snapshots].find { |s| s[:id] == id }
|
220
|
+
end
|
177
221
|
end
|
178
222
|
end
|
179
223
|
|
@@ -182,7 +226,7 @@ module Rack
|
|
182
226
|
# used in tests only
|
183
227
|
def wipe_snapshots_data
|
184
228
|
@snapshots_cycle = 0
|
185
|
-
@
|
229
|
+
@snapshot_groups = {}
|
186
230
|
end
|
187
231
|
end
|
188
232
|
end
|