rack-mini-profiler 2.3.2 → 2.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +13 -4
- data/lib/html/includes.css +9 -11
- data/lib/html/includes.js +24 -1
- data/lib/html/includes.scss +3 -11
- data/lib/html/includes.tmpl +2 -2
- data/lib/html/profile_handler.js +1 -1
- data/lib/html/vendor.js +1 -1
- data/lib/mini_profiler/asset_version.rb +1 -1
- data/lib/mini_profiler/config.rb +5 -1
- data/lib/mini_profiler/profiler.rb +20 -4
- data/lib/mini_profiler/version.rb +2 -1
- data/lib/patches/db/riak.rb +1 -1
- data/rack-mini-profiler.gemspec +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ff9200889e574b3f90f901b90b88fe05f0c48993c945fc5dac37c2f1d86e693
|
4
|
+
data.tar.gz: bdca4fb3ada1b7c56525753b9eaa6430389f309a76152e3f8a7e0c9297463bea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43b8c69b37ba90c80c31d8d410b05dda421322d5c6d1f45654807b526f7d990bec54eaa711aa34bbf43141831453a75543b3a27189103ea3f3bcbac7f3f4101a
|
7
|
+
data.tar.gz: bed607b319c32d85838767f7de608031411d7513fcbd8866d2d67feb44253b997e389671a903b192be07e04d1c018069ab835536de47ada14ad3af8bf89739d9
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 2.3.3 - 2021-08-30
|
4
|
+
|
5
|
+
- [FEATURE] Introduce `pp=flamegraph_mode`
|
6
|
+
- [FEATURE] Richer CSP configuration options
|
7
|
+
- [FEATURE] Add support for Hotwire Turbo Drive
|
8
|
+
|
3
9
|
## 2.3.2 - 2021-04-30
|
4
10
|
|
5
11
|
- [FEATURE] Introduce `pp=async-flamegraph` for asynchronous flamegraphs
|
data/README.md
CHANGED
@@ -175,6 +175,9 @@ To store flamegraph data for later viewing, append the `?pp=async-flamegraph` pa
|
|
175
175
|
Flamegraph data for this request, and all subsequent requests made by this page (based on the `REFERER` header) will be stored.
|
176
176
|
'flamegraph' links will appear for these requests in the MiniProfiler UI.
|
177
177
|
|
178
|
+
Note: Mini Profiler will not record SQL timings for a request if it asks for a flamegraph. The rationale behind this is to keep
|
179
|
+
Mini Profiler's methods that are responsible for generating the timings data out of the flamegraph.
|
180
|
+
|
178
181
|
### Memory Profiling
|
179
182
|
|
180
183
|
Memory allocations can be measured (using the [memory_profiler](https://github.com/SamSaffron/memory_profiler) gem)
|
@@ -398,6 +401,7 @@ toggle_shortcut|Alt+P|Keyboard shortcut to toggle the mini_profiler's visibility
|
|
398
401
|
start_hidden|`false`|`false` to make mini_profiler visible on page load.
|
399
402
|
backtrace_threshold_ms|`0`|Minimum SQL query elapsed time before a backtrace is recorded.
|
400
403
|
flamegraph_sample_rate|`0.5`|How often to capture stack traces for flamegraphs in milliseconds.
|
404
|
+
flamegraph_mode|`:wall`|The [StackProf mode](https://github.com/tmm1/stackprof#all-options) to pass to `StackProf.run`.
|
401
405
|
base_url_path|`'/mini-profiler-resources/'`|Path for assets; added as a prefix when naming assets and sought when responding to requests.
|
402
406
|
collapse_results|`true`|If multiple timing results exist in a single page, collapse them till clicked.
|
403
407
|
max_traces_to_show|20|Maximum number of mini profiler timing blocks to show on one page
|
@@ -412,13 +416,15 @@ snapshots_transport_destination_url|`nil`|Set this config to a valid URL to enab
|
|
412
416
|
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.
|
413
417
|
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.
|
414
418
|
snapshots_transport_gzip_requests|`false`|Make the snapshots transporter gzip the requests it makes to `snapshots_transport_destination_url`.
|
419
|
+
content_security_policy_nonce|Rails: Current nonce<br>Rack: nil|Set the content security policy nonce to use when inserting MiniProfiler's script block.
|
420
|
+
enable_hotwire_turbo_drive_support| `false` | Enable support for Hotwire TurboDrive page transitions.
|
415
421
|
|
416
422
|
### Using MiniProfiler with `Rack::Deflate` middleware
|
417
423
|
|
418
424
|
If you are using `Rack::Deflate` with Rails and `rack-mini-profiler` in its default configuration,
|
419
425
|
`Rack::MiniProfiler` will be injected (as always) at position 0 in the middleware stack,
|
420
426
|
which means it will run after `Rack::Deflate` on response processing. To prevent attempting to inject
|
421
|
-
HTML in already compressed response body MiniProfiler will suppress compression by setting
|
427
|
+
HTML in already compressed response body MiniProfiler will suppress compression by setting
|
422
428
|
`identity` encoding in `Accept-Encoding` request header.
|
423
429
|
|
424
430
|
## Special query strings
|
@@ -461,20 +467,23 @@ end
|
|
461
467
|
If you want to contribute to this project, that's great, thank you! You can run the following rake task:
|
462
468
|
|
463
469
|
```
|
470
|
+
$ BUNDLE_GEMFILE=website/Gemfile bundle install
|
464
471
|
$ bundle exec rake client_dev
|
465
472
|
```
|
466
473
|
|
467
|
-
|
474
|
+
This will start a local Sinatra server at `http://localhost:9292` where you'll be able to preview your changes. Refreshing the page should be enough to see any changes you make to files in the `lib/html` directory.
|
475
|
+
|
476
|
+
Make sure to prepend `bundle exec` before any Rake tasks you run.
|
468
477
|
|
469
478
|
## Running the Specs
|
470
479
|
|
480
|
+
You need Memcached and Redis services running for the specs.
|
481
|
+
|
471
482
|
```
|
472
483
|
$ rake build
|
473
484
|
$ rake spec
|
474
485
|
```
|
475
486
|
|
476
|
-
Additionally you can also run `autotest` if you like.
|
477
|
-
|
478
487
|
## Licence
|
479
488
|
|
480
489
|
The MIT License (MIT)
|
data/lib/html/includes.css
CHANGED
@@ -69,8 +69,16 @@
|
|
69
69
|
.profiler-result .custom-fields-title,
|
70
70
|
.profiler-queries .custom-fields-title {
|
71
71
|
color: #555;
|
72
|
-
font: Helvetica, Arial, sans-serif;
|
72
|
+
font-family: Helvetica, Arial, sans-serif;
|
73
73
|
font-size: 14px; }
|
74
|
+
.mp-snapshots .ta-left,
|
75
|
+
.profiler-result .ta-left,
|
76
|
+
.profiler-queries .ta-left {
|
77
|
+
text-align: left; }
|
78
|
+
.mp-snapshots .ta-right,
|
79
|
+
.profiler-result .ta-right,
|
80
|
+
.profiler-queries .ta-right {
|
81
|
+
text-align: right; }
|
74
82
|
|
75
83
|
.profiler-result {
|
76
84
|
font-family: Helvetica, Arial, sans-serif; }
|
@@ -233,8 +241,6 @@
|
|
233
241
|
left: 0px; }
|
234
242
|
.profiler-results.profiler-top.profiler-left.profiler-no-controls .profiler-totals, .profiler-results.profiler-top.profiler-left.profiler-no-controls .profiler-result:last-child .profiler-button,
|
235
243
|
.profiler-results.profiler-top.profiler-left .profiler-controls {
|
236
|
-
-webkit-border-bottom-right-radius: 10px;
|
237
|
-
-moz-border-radius-bottomright: 10px;
|
238
244
|
border-bottom-right-radius: 10px; }
|
239
245
|
.profiler-results.profiler-top.profiler-left .profiler-button,
|
240
246
|
.profiler-results.profiler-top.profiler-left .profiler-controls {
|
@@ -243,8 +249,6 @@
|
|
243
249
|
right: 0px; }
|
244
250
|
.profiler-results.profiler-top.profiler-right.profiler-no-controls .profiler-totals, .profiler-results.profiler-top.profiler-right.profiler-no-controls .profiler-result:last-child .profiler-button,
|
245
251
|
.profiler-results.profiler-top.profiler-right .profiler-controls {
|
246
|
-
-webkit-border-bottom-left-radius: 10px;
|
247
|
-
-moz-border-radius-bottomleft: 10px;
|
248
252
|
border-bottom-left-radius: 10px; }
|
249
253
|
.profiler-results.profiler-top.profiler-right .profiler-button,
|
250
254
|
.profiler-results.profiler-top.profiler-right .profiler-controls {
|
@@ -255,8 +259,6 @@
|
|
255
259
|
left: 0px; }
|
256
260
|
.profiler-results.profiler-bottom.profiler-left.profiler-no-controls .profiler-totals, .profiler-results.profiler-bottom.profiler-left.profiler-no-controls .profiler-result:first-child .profiler-button,
|
257
261
|
.profiler-results.profiler-bottom.profiler-left .profiler-controls {
|
258
|
-
-webkit-border-top-right-radius: 10px;
|
259
|
-
-moz-border-radius-topright: 10px;
|
260
262
|
border-top-right-radius: 10px; }
|
261
263
|
.profiler-results.profiler-bottom.profiler-left .profiler-button,
|
262
264
|
.profiler-results.profiler-bottom.profiler-left .profiler-controls {
|
@@ -265,8 +267,6 @@
|
|
265
267
|
right: 0px; }
|
266
268
|
.profiler-results.profiler-bottom.profiler-right.profiler-no-controls .profiler-totals, .profiler-results.profiler-bottom.profiler-right.profiler-no-controls .profiler-result:first-child .profiler-button,
|
267
269
|
.profiler-results.profiler-bottom.profiler-right .profiler-controls {
|
268
|
-
-webkit-border-bottom-top-radius: 10px;
|
269
|
-
-moz-border-radius-topleft: 10px;
|
270
270
|
border-top-left-radius: 10px; }
|
271
271
|
.profiler-results.profiler-bottom.profiler-right .profiler-button,
|
272
272
|
.profiler-results.profiler-bottom.profiler-right .profiler-controls {
|
@@ -324,8 +324,6 @@
|
|
324
324
|
text-align: left;
|
325
325
|
line-height: 18px;
|
326
326
|
overflow: auto;
|
327
|
-
-moz-box-shadow: 0px 1px 15px #555;
|
328
|
-
-webkit-box-shadow: 0px 1px 15px #555;
|
329
327
|
box-shadow: 0px 1px 15px #555; }
|
330
328
|
.profiler-results .profiler-popup .profiler-info {
|
331
329
|
margin-bottom: 3px;
|
data/lib/html/includes.js
CHANGED
@@ -495,6 +495,19 @@ var _MiniProfiler = (function() {
|
|
495
495
|
}, 3000);
|
496
496
|
};
|
497
497
|
|
498
|
+
var onTurboBeforeVisit = function onTurboBeforeVisit(e) {
|
499
|
+
if(!e.defaultPrevented) {
|
500
|
+
window.MiniProfilerContainer = document.querySelector('body > .profiler-results')
|
501
|
+
window.MiniProfiler.pageTransition()
|
502
|
+
}
|
503
|
+
}
|
504
|
+
|
505
|
+
var onTurboLoad = function onTurboLoad(e) {
|
506
|
+
if(window.MiniProfilerContainer) {
|
507
|
+
document.body.appendChild(window.MiniProfilerContainer)
|
508
|
+
}
|
509
|
+
}
|
510
|
+
|
498
511
|
var onClickEvents = function onClickEvents(e) {
|
499
512
|
// this happens on every keystroke, and :visible is crazy expensive in IE <9
|
500
513
|
// and in this case, the display:none check is sufficient.
|
@@ -652,6 +665,11 @@ var _MiniProfiler = (function() {
|
|
652
665
|
turbolinksSkipResultsFetch
|
653
666
|
);
|
654
667
|
}
|
668
|
+
|
669
|
+
if (options.hotwireTurboDriveSupport) {
|
670
|
+
document.addEventListener("turbo:before-visit", onTurboBeforeVisit)
|
671
|
+
document.addEventListener("turbo:load", onTurboLoad)
|
672
|
+
}
|
655
673
|
};
|
656
674
|
|
657
675
|
var unbindDocumentEvents = function unbindDocumentEvents() {
|
@@ -664,6 +682,8 @@ var _MiniProfiler = (function() {
|
|
664
682
|
"turbolinks:request-start",
|
665
683
|
turbolinksSkipResultsFetch
|
666
684
|
);
|
685
|
+
document.removeEventListener("turbo:before-visit", onTurboBeforeVisit);
|
686
|
+
document.removeEventListener("turbo:load", onTurboLoad);
|
667
687
|
};
|
668
688
|
|
669
689
|
var initFullView = function initFullView() {
|
@@ -1033,6 +1053,8 @@ var _MiniProfiler = (function() {
|
|
1033
1053
|
.getAttribute("data-hidden-custom-fields")
|
1034
1054
|
.toLowerCase()
|
1035
1055
|
.split(",");
|
1056
|
+
var hotwireTurboDriveSupport = script
|
1057
|
+
.getAttribute('data-turbo-permanent') === "true";
|
1036
1058
|
return {
|
1037
1059
|
ids: ids,
|
1038
1060
|
path: path,
|
@@ -1051,7 +1073,8 @@ var _MiniProfiler = (function() {
|
|
1051
1073
|
collapseResults: collapseResults,
|
1052
1074
|
htmlContainer: htmlContainer,
|
1053
1075
|
cssUrl: cssUrl,
|
1054
|
-
hiddenCustomFields: hiddenCustomFields
|
1076
|
+
hiddenCustomFields: hiddenCustomFields,
|
1077
|
+
hotwireTurboDriveSupport: hotwireTurboDriveSupport
|
1055
1078
|
};
|
1056
1079
|
})();
|
1057
1080
|
|
data/lib/html/includes.scss
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
@mixin box-shadow($dx, $dy, $radius, $color) {
|
2
|
-
-moz-box-shadow: $dx $dy $radius $color;
|
3
|
-
-webkit-box-shadow: $dx $dy $radius $color;
|
4
2
|
box-shadow: $dx $dy $radius $color;
|
5
3
|
}
|
6
4
|
|
@@ -58,9 +56,11 @@ $zindex: 2147483640; // near 32bit max 2147483647
|
|
58
56
|
}
|
59
57
|
.custom-fields-title {
|
60
58
|
color: $textColor;
|
61
|
-
font: $normalFonts;
|
59
|
+
font-family: $normalFonts;
|
62
60
|
font-size: 14px;
|
63
61
|
}
|
62
|
+
.ta-left { text-align: left; }
|
63
|
+
.ta-right { text-align: right; }
|
64
64
|
}
|
65
65
|
|
66
66
|
// styles shared between popup view and full view
|
@@ -326,8 +326,6 @@ $zindex: 2147483640; // near 32bit max 2147483647
|
|
326
326
|
&.profiler-no-controls .profiler-totals,
|
327
327
|
&.profiler-no-controls .profiler-result:last-child .profiler-button,
|
328
328
|
.profiler-controls {
|
329
|
-
-webkit-border-bottom-right-radius: $radius;
|
330
|
-
-moz-border-radius-bottomright: $radius;
|
331
329
|
border-bottom-right-radius: $radius;
|
332
330
|
}
|
333
331
|
|
@@ -343,8 +341,6 @@ $zindex: 2147483640; // near 32bit max 2147483647
|
|
343
341
|
&.profiler-no-controls .profiler-totals,
|
344
342
|
&.profiler-no-controls .profiler-result:last-child .profiler-button,
|
345
343
|
.profiler-controls {
|
346
|
-
-webkit-border-bottom-left-radius: $radius;
|
347
|
-
-moz-border-radius-bottomleft: $radius;
|
348
344
|
border-bottom-left-radius: $radius;
|
349
345
|
}
|
350
346
|
|
@@ -364,8 +360,6 @@ $zindex: 2147483640; // near 32bit max 2147483647
|
|
364
360
|
&.profiler-no-controls .profiler-totals,
|
365
361
|
&.profiler-no-controls .profiler-result:first-child .profiler-button,
|
366
362
|
.profiler-controls {
|
367
|
-
-webkit-border-top-right-radius: $radius;
|
368
|
-
-moz-border-radius-topright: $radius;
|
369
363
|
border-top-right-radius: $radius;
|
370
364
|
}
|
371
365
|
|
@@ -381,8 +375,6 @@ $zindex: 2147483640; // near 32bit max 2147483647
|
|
381
375
|
&.profiler-no-controls .profiler-totals,
|
382
376
|
&.profiler-no-controls .profiler-result:first-child .profiler-button,
|
383
377
|
.profiler-controls {
|
384
|
-
-webkit-border-bottom-top-radius: $radius;
|
385
|
-
-moz-border-radius-topleft: $radius;
|
386
378
|
border-top-left-radius: $radius;
|
387
379
|
}
|
388
380
|
|
data/lib/html/includes.tmpl
CHANGED
@@ -117,8 +117,8 @@
|
|
117
117
|
<table>
|
118
118
|
<thead>
|
119
119
|
<tr>
|
120
|
-
<th
|
121
|
-
<th
|
120
|
+
<th class="ta-right">step<br />time from start<br />query type<br />duration</th>
|
121
|
+
<th class="ta-left">call stack<br />query</th>
|
122
122
|
</tr>
|
123
123
|
</thead>
|
124
124
|
<tbody>
|
data/lib/html/profile_handler.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<script async type="text/javascript" id="mini-profiler" src="{url}" data-css-url="{cssUrl}" data-version="{version}" data-path="{path}" data-current-id="{currentId}" data-ids="{ids}" data-horizontal-position="{horizontalPosition}" data-vertical-position="{verticalPosition}" data-trivial="{showTrivial}" data-children="{showChildren}" data-max-traces="{maxTracesToShow}" data-controls="{showControls}" data-total-sql-count="{showTotalSqlCount}" data-authorized="{authorized}" data-toggle-shortcut="{toggleShortcut}" data-start-hidden="{startHidden}" data-collapse-results="{collapseResults}" data-html-container="{htmlContainer}" data-hidden-custom-fields="{hiddenCustomFields}"></script>
|
1
|
+
<script async nonce="{cspNonce}" type="text/javascript" id="mini-profiler" src="{url}" data-css-url="{cssUrl}" data-version="{version}" data-path="{path}" data-current-id="{currentId}" data-ids="{ids}" data-horizontal-position="{horizontalPosition}" data-vertical-position="{verticalPosition}" data-trivial="{showTrivial}" data-children="{showChildren}" data-max-traces="{maxTracesToShow}" data-controls="{showControls}" data-total-sql-count="{showTotalSqlCount}" data-authorized="{authorized}" data-toggle-shortcut="{toggleShortcut}" data-start-hidden="{startHidden}" data-collapse-results="{collapseResults}" data-html-container="{htmlContainer}" data-hidden-custom-fields="{hiddenCustomFields}" data-turbo-permanent="{hotwireTurboDriveSupport}"></script>
|
data/lib/html/vendor.js
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
MiniProfiler.templates = {};
|
8
8
|
MiniProfiler.templates["profilerTemplate"] = function anonymous(it
|
9
9
|
) {
|
10
|
-
var out=' <div class="profiler-result"> <div class="profiler-button ';if(it.has_duplicate_sql_timings){out+='profiler-warning';}out+='"> ';if(it.has_duplicate_sql_timings){out+='<span class="profiler-nuclear">!</span>';}out+=' <span class="profiler-number"> '+( MiniProfiler.formatDuration(it.duration_milliseconds))+' <span class="profiler-unit">ms</span> </span> ';if(MiniProfiler.showTotalSqlCount()){out+=' <span class="profiler-number"> '+( it.sql_count)+' <span class="profiler-unit">sql</span> </span> ';}out+=' </div> <div class="profiler-popup"> <div class="profiler-info"> <span class="profiler-name"> '+( it.name)+' <span class="profiler-overall-duration">('+( MiniProfiler.formatDuration(it.duration_milliseconds))+' ms)</span> </span> <span class="profiler-server-time">'+( it.machine_name)+' on '+( MiniProfiler.renderDate(it.started_formatted))+'</span> </div> <div class="profiler-output"> <table class="profiler-timings"> <thead> <tr> <th>event</th> <th>duration (ms)</th> <th class="profiler-duration-with-children">with children (ms)</th> <th class="time-from-start">from start (ms)</th> ';if(it.has_sql_timings){out+=' <th colspan="2">query time (ms)</th> ';}out+=' ';var arr1=it.custom_timing_names;if(arr1){var value,i1=-1,l1=arr1.length-1;while(i1<l1){value=arr1[i1+=1];out+=' <th colspan="2">'+( value.toLowerCase() )+' (ms)</th> ';} } out+=' </tr> </thead> <tbody> '+( MiniProfiler.templates.timingTemplate({timing: it.root, page: it}) )+' </tbody> <tfoot> <tr> <td colspan="3"> ';if(!it.client_timings){out+=' '+( MiniProfiler.templates.linksTemplate({timing: it.root, page: it}) )+' ';}out+=' <a class="profiler-toggle-duration-with-children" title="toggles column with aggregate child durations">show time with children</a> <a class="profiler-snapshots-page-link" title="Go to snapshots page" href="'+( MiniProfiler.options.path )+'snapshots">snapshots</a> </td> ';if(it.has_sql_timings){out+=' <td colspan="2" class="profiler-number profiler-percent-in-sql" title="'+( MiniProfiler.getSqlTimingsCount(it.root) )+' queries spent '+( MiniProfiler.formatDuration(it.duration_milliseconds_in_sql) )+' ms of total request time"> '+( MiniProfiler.formatDuration(it.duration_milliseconds_in_sql / it.duration_milliseconds * 100) )+' <span class="profiler-unit">% in sql</span> </td> ';}out+=' ';var arr2=it.custom_timing_names;if(arr2){var value,i2=-1,l2=arr2.length-1;while(i2<l2){value=arr2[i2+=1];out+=' <td colspan="2" class="profiler-number profiler-percentage-in-sql" title="'+( it.custom_timing_stats[value].count )+' '+( value.toLowerCase() )+' invocations spent '+( MiniProfiler.formatDuration(it.custom_timing_stats[value].duration) )+' ms of total request time"> '+( MiniProfiler.formatDuration(it.custom_timing_stats[value].duration / it.duration_milliseconds * 100) )+' <span class="profiler-unit">% in '+( value.toLowerCase() )+'</span> </td> ';} } out+=' </tr> </tfoot> </table> ';if(it.client_timings){out+=' <table class="profiler-timings profiler-client-timings"> <thead> <tr> <th>client event</th> <th>duration (ms)</th> <th>from start (ms)</th> </tr> </thead> <tbody> ';var arr3=MiniProfiler.getClientTimings(it.client_timings);if(arr3){var value,i3=-1,l3=arr3.length-1;while(i3<l3){value=arr3[i3+=1];out+=' <tr class="';if(value.isTrivial){out+='profiler-trivial';}out+='"> <td class="profiler-label">'+( value.name )+'</td> <td class="profiler-duration"> ';if(value.duration >= 0){out+=' <span class="profiler-unit"></span>'+( MiniProfiler.formatDuration(value.duration) )+' ';}out+=' </td> <td class="profiler-duration time-from-start"> <span class="profiler-unit">+</span>'+( MiniProfiler.formatDuration(value.start) )+' </td> </tr> ';} } out+=' </tbody> <tfoot> <td colspan="3"> '+( MiniProfiler.templates.linksTemplate({timing: it.root, page: it}) )+' </td> </tfoot> </table> ';}out+=' ';if(it.custom_fields && Object.keys(it.custom_fields).length > 0){out+=' <p class="custom-fields-title">Snapshot custom fields</p> <table class="profiler-timings"> <tbody> ';var arr4=Object.keys(it.custom_fields);if(arr4){var key,i4=-1,l4=arr4.length-1;while(i4<l4){key=arr4[i4+=1];out+=' <tr> <td class="profiler-label">'+( key )+'</td> <td class="profiler-label">'+( it.custom_fields[key] )+'</td> </tr> ';} } out+=' </tbody> </table> ';}out+=' </div> </div> ';if(it.has_sql_timings){out+=' <div class="profiler-queries"> <table> <thead> <tr> <th
|
10
|
+
var out=' <div class="profiler-result"> <div class="profiler-button ';if(it.has_duplicate_sql_timings){out+='profiler-warning';}out+='"> ';if(it.has_duplicate_sql_timings){out+='<span class="profiler-nuclear">!</span>';}out+=' <span class="profiler-number"> '+( MiniProfiler.formatDuration(it.duration_milliseconds))+' <span class="profiler-unit">ms</span> </span> ';if(MiniProfiler.showTotalSqlCount()){out+=' <span class="profiler-number"> '+( it.sql_count)+' <span class="profiler-unit">sql</span> </span> ';}out+=' </div> <div class="profiler-popup"> <div class="profiler-info"> <span class="profiler-name"> '+( it.name)+' <span class="profiler-overall-duration">('+( MiniProfiler.formatDuration(it.duration_milliseconds))+' ms)</span> </span> <span class="profiler-server-time">'+( it.machine_name)+' on '+( MiniProfiler.renderDate(it.started_formatted))+'</span> </div> <div class="profiler-output"> <table class="profiler-timings"> <thead> <tr> <th>event</th> <th>duration (ms)</th> <th class="profiler-duration-with-children">with children (ms)</th> <th class="time-from-start">from start (ms)</th> ';if(it.has_sql_timings){out+=' <th colspan="2">query time (ms)</th> ';}out+=' ';var arr1=it.custom_timing_names;if(arr1){var value,i1=-1,l1=arr1.length-1;while(i1<l1){value=arr1[i1+=1];out+=' <th colspan="2">'+( value.toLowerCase() )+' (ms)</th> ';} } out+=' </tr> </thead> <tbody> '+( MiniProfiler.templates.timingTemplate({timing: it.root, page: it}) )+' </tbody> <tfoot> <tr> <td colspan="3"> ';if(!it.client_timings){out+=' '+( MiniProfiler.templates.linksTemplate({timing: it.root, page: it}) )+' ';}out+=' <a class="profiler-toggle-duration-with-children" title="toggles column with aggregate child durations">show time with children</a> <a class="profiler-snapshots-page-link" title="Go to snapshots page" href="'+( MiniProfiler.options.path )+'snapshots">snapshots</a> </td> ';if(it.has_sql_timings){out+=' <td colspan="2" class="profiler-number profiler-percent-in-sql" title="'+( MiniProfiler.getSqlTimingsCount(it.root) )+' queries spent '+( MiniProfiler.formatDuration(it.duration_milliseconds_in_sql) )+' ms of total request time"> '+( MiniProfiler.formatDuration(it.duration_milliseconds_in_sql / it.duration_milliseconds * 100) )+' <span class="profiler-unit">% in sql</span> </td> ';}out+=' ';var arr2=it.custom_timing_names;if(arr2){var value,i2=-1,l2=arr2.length-1;while(i2<l2){value=arr2[i2+=1];out+=' <td colspan="2" class="profiler-number profiler-percentage-in-sql" title="'+( it.custom_timing_stats[value].count )+' '+( value.toLowerCase() )+' invocations spent '+( MiniProfiler.formatDuration(it.custom_timing_stats[value].duration) )+' ms of total request time"> '+( MiniProfiler.formatDuration(it.custom_timing_stats[value].duration / it.duration_milliseconds * 100) )+' <span class="profiler-unit">% in '+( value.toLowerCase() )+'</span> </td> ';} } out+=' </tr> </tfoot> </table> ';if(it.client_timings){out+=' <table class="profiler-timings profiler-client-timings"> <thead> <tr> <th>client event</th> <th>duration (ms)</th> <th>from start (ms)</th> </tr> </thead> <tbody> ';var arr3=MiniProfiler.getClientTimings(it.client_timings);if(arr3){var value,i3=-1,l3=arr3.length-1;while(i3<l3){value=arr3[i3+=1];out+=' <tr class="';if(value.isTrivial){out+='profiler-trivial';}out+='"> <td class="profiler-label">'+( value.name )+'</td> <td class="profiler-duration"> ';if(value.duration >= 0){out+=' <span class="profiler-unit"></span>'+( MiniProfiler.formatDuration(value.duration) )+' ';}out+=' </td> <td class="profiler-duration time-from-start"> <span class="profiler-unit">+</span>'+( MiniProfiler.formatDuration(value.start) )+' </td> </tr> ';} } out+=' </tbody> <tfoot> <td colspan="3"> '+( MiniProfiler.templates.linksTemplate({timing: it.root, page: it}) )+' </td> </tfoot> </table> ';}out+=' ';if(it.custom_fields && Object.keys(it.custom_fields).length > 0){out+=' <p class="custom-fields-title">Snapshot custom fields</p> <table class="profiler-timings"> <tbody> ';var arr4=Object.keys(it.custom_fields);if(arr4){var key,i4=-1,l4=arr4.length-1;while(i4<l4){key=arr4[i4+=1];out+=' <tr> <td class="profiler-label">'+( key )+'</td> <td class="profiler-label">'+( it.custom_fields[key] )+'</td> </tr> ';} } out+=' </tbody> </table> ';}out+=' </div> </div> ';if(it.has_sql_timings){out+=' <div class="profiler-queries"> <table> <thead> <tr> <th class="ta-right">step<br />time from start<br />query type<br />duration</th> <th class="ta-left">call stack<br />query</th> </tr> </thead> <tbody> ';var arr5=MiniProfiler.getSqlTimings(it.root);if(arr5){var value,index=-1,l5=arr5.length-1;while(index<l5){value=arr5[index+=1];out+=' '+( MiniProfiler.templates.sqlGapTemplate({g: value.prevGap}) )+' '+( MiniProfiler.templates.sqlTimingTemplate({i: index, s: value}) )+' ';if(value.nextGap){out+=' '+( MiniProfiler.templates.sqlGapTemplate({g: value.nextGap}) )+' ';}out+=' ';} } out+=' </tbody> </table> <p class="profiler-trivial-gap-container"> <a class="profiler-toggle-trivial-gaps">show trivial gaps</a> </p> </div> ';}out+=' </div>';return out;
|
11
11
|
}
|
12
12
|
MiniProfiler.templates["linksTemplate"] = function anonymous(it
|
13
13
|
) {
|
data/lib/mini_profiler/config.rb
CHANGED
@@ -28,6 +28,7 @@ module Rack
|
|
28
28
|
@authorization_mode = :allow_all
|
29
29
|
@backtrace_threshold_ms = 0
|
30
30
|
@flamegraph_sample_rate = 0.5
|
31
|
+
@flamegraph_mode = :wall
|
31
32
|
@storage_failure = Proc.new do |exception|
|
32
33
|
if @logger
|
33
34
|
@logger.warn("MiniProfiler storage failure: #{exception.message}")
|
@@ -57,6 +58,7 @@ module Rack
|
|
57
58
|
@snapshots_transport_auth_key = nil
|
58
59
|
@snapshots_redact_sql_queries = true
|
59
60
|
@snapshots_transport_gzip_requests = false
|
61
|
+
@enable_hotwire_turbo_drive_support = false
|
60
62
|
|
61
63
|
self
|
62
64
|
}
|
@@ -68,7 +70,9 @@ module Rack
|
|
68
70
|
:flamegraph_sample_rate, :logger, :pre_authorize_cb, :skip_paths,
|
69
71
|
:skip_schema_queries, :storage, :storage_failure, :storage_instance,
|
70
72
|
:storage_options, :user_provider, :enable_advanced_debugging_tools,
|
71
|
-
:skip_sql_param_names, :suppress_encoding, :max_sql_param_length
|
73
|
+
:skip_sql_param_names, :suppress_encoding, :max_sql_param_length,
|
74
|
+
:content_security_policy_nonce, :enable_hotwire_turbo_drive_support,
|
75
|
+
:flamegraph_mode
|
72
76
|
|
73
77
|
# ui accessors
|
74
78
|
attr_accessor :collapse_results, :max_traces_to_show, :position,
|
@@ -362,8 +362,17 @@ module Rack
|
|
362
362
|
else
|
363
363
|
sample_rate = config.flamegraph_sample_rate
|
364
364
|
end
|
365
|
+
|
366
|
+
mode_match_data = query_string.match(/flamegraph_mode=([a-zA-Z]+)/)
|
367
|
+
|
368
|
+
if mode_match_data && [:cpu, :wall, :object, :custom].include?(mode_match_data[1].to_sym)
|
369
|
+
mode = mode_match_data[1].to_sym
|
370
|
+
else
|
371
|
+
mode = config.flamegraph_mode
|
372
|
+
end
|
373
|
+
|
365
374
|
flamegraph = StackProf.run(
|
366
|
-
mode:
|
375
|
+
mode: mode,
|
367
376
|
raw: true,
|
368
377
|
aggregate: false,
|
369
378
|
interval: (sample_rate * 1000).to_i
|
@@ -630,7 +639,7 @@ module Rack
|
|
630
639
|
end
|
631
640
|
|
632
641
|
def text_result(body)
|
633
|
-
headers = { 'Content-Type' => 'text/plain' }
|
642
|
+
headers = { 'Content-Type' => 'text/plain; charset=utf-8' }
|
634
643
|
[200, headers, [body]]
|
635
644
|
end
|
636
645
|
|
@@ -643,7 +652,7 @@ module Rack
|
|
643
652
|
headers = { 'Content-Type' => 'text/html' }
|
644
653
|
body = "<html><body>
|
645
654
|
<pre style='line-height: 30px; font-size: 16px;'>
|
646
|
-
|
655
|
+
This is the help menu of the <a href='#{Rack::MiniProfiler::SOURCE_CODE_URI}'>rack-mini-profiler</a> gem, append the following to your query string for more options:
|
647
656
|
|
648
657
|
#{make_link "help", env} : display this screen
|
649
658
|
#{make_link "env", env} : display the rack environment
|
@@ -658,6 +667,7 @@ Append the following to your query string:
|
|
658
667
|
#{make_link "flamegraph", env} : a graph representing sampled activity (requires the stackprof gem).
|
659
668
|
#{make_link "async-flamegraph", env} : store flamegraph data for this page and all its AJAX requests. Flamegraph links will be available in the mini-profiler UI (requires the stackprof gem).
|
660
669
|
#{make_link "flamegraph&flamegraph_sample_rate=1", env}: creates a flamegraph with the specified sample rate (in ms). Overrides value set in config
|
670
|
+
#{make_link "flamegraph&flamegraph_mode=cpu", env}: creates a flamegraph with the specified mode (one of cpu, wall, object, or custom). Overrides value set in config
|
661
671
|
#{make_link "flamegraph_embed", env} : a graph representing sampled activity (requires the stackprof gem), embedded resources for use on an intranet.
|
662
672
|
#{make_link "trace-exceptions", env} : will return all the spots where your application raises exceptions
|
663
673
|
#{make_link "analyze-memory", env} : will perform basic memory analysis of heap
|
@@ -728,6 +738,10 @@ Append the following to your query string:
|
|
728
738
|
url = "#{path}includes.js?v=#{version}" if !url
|
729
739
|
css_url = "#{path}includes.css?v=#{version}" if !css_url
|
730
740
|
|
741
|
+
content_security_policy_nonce = @config.content_security_policy_nonce ||
|
742
|
+
env["action_dispatch.content_security_policy_nonce"] ||
|
743
|
+
env["secure_headers_content_security_policy_nonce"]
|
744
|
+
|
731
745
|
settings = {
|
732
746
|
path: path,
|
733
747
|
url: url,
|
@@ -745,7 +759,9 @@ Append the following to your query string:
|
|
745
759
|
startHidden: @config.start_hidden,
|
746
760
|
collapseResults: @config.collapse_results,
|
747
761
|
htmlContainer: @config.html_container,
|
748
|
-
hiddenCustomFields: @config.snapshot_hidden_custom_fields.join(',')
|
762
|
+
hiddenCustomFields: @config.snapshot_hidden_custom_fields.join(','),
|
763
|
+
cspNonce: content_security_policy_nonce,
|
764
|
+
hotwireTurboDriveSupport: @config.enable_hotwire_turbo_drive_support,
|
749
765
|
}
|
750
766
|
|
751
767
|
if current && current.page_struct
|
data/lib/patches/db/riak.rb
CHANGED
data/rack-mini-profiler.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.required_ruby_version = '>= 2.4.0'
|
25
25
|
|
26
26
|
s.metadata = {
|
27
|
-
'source_code_uri' =>
|
27
|
+
'source_code_uri' => Rack::MiniProfiler::SOURCE_CODE_URI,
|
28
28
|
'changelog_uri' => 'https://github.com/MiniProfiler/rack-mini-profiler/blob/master/CHANGELOG.md'
|
29
29
|
}
|
30
30
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-mini-profiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-08-30 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rack
|
@@ -354,7 +354,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
354
354
|
- !ruby/object:Gem::Version
|
355
355
|
version: '0'
|
356
356
|
requirements: []
|
357
|
-
rubygems_version: 3.
|
357
|
+
rubygems_version: 3.1.6
|
358
358
|
signing_key:
|
359
359
|
specification_version: 4
|
360
360
|
summary: Profiles loading speed for rack applications.
|