pghero 3.5.0 → 3.6.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/app/assets/javascripts/pghero/application.js +14 -0
- data/app/assets/stylesheets/pghero/application.css +101 -1
- data/app/controllers/pg_hero/home_controller.rb +3 -1
- data/app/helpers/pg_hero/home_helper.rb +1 -1
- data/app/views/layouts/pg_hero/application.html.erb +3 -3
- data/app/views/pg_hero/home/_connections_table.html.erb +1 -1
- data/app/views/pg_hero/home/_live_queries_table.html.erb +8 -8
- data/app/views/pg_hero/home/_queries_table.html.erb +5 -5
- data/app/views/pg_hero/home/_query_stats_slider.html.erb +2 -2
- data/app/views/pg_hero/home/_suggested_index.html.erb +6 -5
- data/app/views/pg_hero/home/connections.html.erb +6 -6
- data/app/views/pg_hero/home/explain.html.erb +2 -2
- data/app/views/pg_hero/home/index.html.erb +19 -19
- data/app/views/pg_hero/home/index_bloat.html.erb +6 -6
- data/app/views/pg_hero/home/maintenance.html.erb +3 -3
- data/app/views/pg_hero/home/queries.html.erb +4 -4
- data/app/views/pg_hero/home/relation_space.html.erb +3 -3
- data/app/views/pg_hero/home/show_query.html.erb +19 -19
- data/app/views/pg_hero/home/space.html.erb +11 -11
- data/app/views/pg_hero/home/system.html.erb +12 -12
- data/app/views/pg_hero/home/tune.html.erb +2 -2
- data/lib/pghero/database.rb +2 -2
- data/lib/pghero/engine.rb +2 -2
- data/lib/pghero/methods/basic.rb +22 -24
- data/lib/pghero/methods/explain.rb +1 -1
- data/lib/pghero/methods/query_stats.rb +1 -1
- data/lib/pghero/methods/suggested_indexes.rb +4 -2
- data/lib/pghero/methods/system.rb +2 -2
- data/lib/pghero/version.rb +1 -1
- data/lib/pghero.rb +3 -5
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7dc52d94fbdd96a3efcef37d4739855cb5e9ab0da76c53d345141c3a0f28021
|
4
|
+
data.tar.gz: 6e1640fb5ff339f5d0523d7acebb4655c0426b877a2a6545e53fb0af386769da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1ad10cfe918c2ab278af7aa96fcf5b08ccce3b6454f9630d7a628c9be0d54d0d3f5110d9ec4ab9248ee42556bba66166347412d284074820ed35069292ce72f
|
7
|
+
data.tar.gz: 4a7cc686fb1074c827a21e5b9ee8ce5a82119926b05e9ea8cdacd31759765932767df2638bd0790543e5f252507c97863c9572be7112be22244927396d93dce7
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 3.6.1 (2024-10-14)
|
2
|
+
|
3
|
+
- Fixed error when Propshaft is installed but not used
|
4
|
+
|
5
|
+
## 3.6.0 (2024-07-10)
|
6
|
+
|
7
|
+
- Improved CSP support
|
8
|
+
- Dropped support for Linux packages for Ubuntu 18.04, CentOS 7, and SLES 12
|
9
|
+
- Dropped support for Ruby < 3.1 and Rails < 6.1
|
10
|
+
|
1
11
|
## 3.5.0 (2024-05-21)
|
2
12
|
|
3
13
|
- Added materialized views to space page and `relation_sizes` method
|
@@ -157,3 +157,17 @@ function initSlider() {
|
|
157
157
|
refreshStats(false);
|
158
158
|
});
|
159
159
|
}
|
160
|
+
|
161
|
+
$(document).on("click", ".query-code", function () {
|
162
|
+
this.style.maxHeight = "none";
|
163
|
+
});
|
164
|
+
|
165
|
+
$(document).on("click", ".migration-link", function (e) {
|
166
|
+
e.preventDefault();
|
167
|
+
$(this).parent().next(".migration").css("display", "block");
|
168
|
+
});
|
169
|
+
|
170
|
+
$(document).on("click", ".show-details", function () {
|
171
|
+
$(this).nextAll(".details").css("display", "block");
|
172
|
+
$(this).css("display", "none");
|
173
|
+
});
|
@@ -483,12 +483,12 @@ body {
|
|
483
483
|
line-height: 300px;
|
484
484
|
text-align: center;
|
485
485
|
color: #999;
|
486
|
+
margin-bottom: 20px;
|
486
487
|
}
|
487
488
|
|
488
489
|
.pie-chart {
|
489
490
|
height: 260px;
|
490
491
|
line-height: 260px;
|
491
|
-
margin-bottom: 20px;
|
492
492
|
}
|
493
493
|
|
494
494
|
.unused-index {
|
@@ -503,8 +503,18 @@ body {
|
|
503
503
|
font-weight: bold;
|
504
504
|
}
|
505
505
|
|
506
|
+
.origins-table {
|
507
|
+
table-layout: auto;
|
508
|
+
}
|
509
|
+
|
506
510
|
.origin {
|
507
511
|
word-break: break-word;
|
512
|
+
width: 90%;
|
513
|
+
}
|
514
|
+
|
515
|
+
.origin-pct {
|
516
|
+
text-align: right;
|
517
|
+
width: 10%;
|
508
518
|
}
|
509
519
|
|
510
520
|
.duplicate-indexes td {
|
@@ -518,3 +528,93 @@ body {
|
|
518
528
|
.no-outline:focus {
|
519
529
|
outline: none;
|
520
530
|
}
|
531
|
+
|
532
|
+
.width-10 {
|
533
|
+
width: 10%;
|
534
|
+
}
|
535
|
+
|
536
|
+
.width-15 {
|
537
|
+
width: 15%;
|
538
|
+
}
|
539
|
+
|
540
|
+
.width-20 {
|
541
|
+
width: 20%;
|
542
|
+
}
|
543
|
+
|
544
|
+
.width-25 {
|
545
|
+
width: 25%;
|
546
|
+
}
|
547
|
+
|
548
|
+
.width-33 {
|
549
|
+
width: 33.33%;
|
550
|
+
}
|
551
|
+
|
552
|
+
.right-5 {
|
553
|
+
margin-right: 5px;
|
554
|
+
}
|
555
|
+
|
556
|
+
.query-row {
|
557
|
+
border-top: none;
|
558
|
+
padding: 0;
|
559
|
+
}
|
560
|
+
|
561
|
+
.query-pre {
|
562
|
+
margin-top: 1em;
|
563
|
+
}
|
564
|
+
|
565
|
+
.query-code {
|
566
|
+
max-height: 230px;
|
567
|
+
overflow: hidden;
|
568
|
+
}
|
569
|
+
|
570
|
+
.break-all {
|
571
|
+
word-break: break-all;
|
572
|
+
}
|
573
|
+
|
574
|
+
.migration {
|
575
|
+
display: none;
|
576
|
+
}
|
577
|
+
|
578
|
+
.migration pre {
|
579
|
+
overflow: scroll;
|
580
|
+
white-space: pre;
|
581
|
+
word-break: normal;
|
582
|
+
}
|
583
|
+
|
584
|
+
.space-index {
|
585
|
+
font-style: italic;
|
586
|
+
}
|
587
|
+
|
588
|
+
a.relation-link {
|
589
|
+
color: inherit;
|
590
|
+
}
|
591
|
+
|
592
|
+
.push-left {
|
593
|
+
float: left;
|
594
|
+
}
|
595
|
+
|
596
|
+
.clear-both {
|
597
|
+
clear: both;
|
598
|
+
}
|
599
|
+
|
600
|
+
.create-index {
|
601
|
+
color: #eee;
|
602
|
+
background-color: #333;
|
603
|
+
}
|
604
|
+
|
605
|
+
.hide {
|
606
|
+
display: none;
|
607
|
+
}
|
608
|
+
|
609
|
+
.show-details {
|
610
|
+
float: right;
|
611
|
+
color: #f0ad4e;
|
612
|
+
margin-top: 0px;
|
613
|
+
padding: 10px;
|
614
|
+
cursor: pointer;
|
615
|
+
}
|
616
|
+
|
617
|
+
.details pre {
|
618
|
+
color: #f0ad4e;
|
619
|
+
background-color: #333;
|
620
|
+
}
|
@@ -166,6 +166,8 @@ module PgHero
|
|
166
166
|
|
167
167
|
if !@historical_query_stats_enabled || request.xhr?
|
168
168
|
set_suggested_indexes
|
169
|
+
else
|
170
|
+
@debug = params[:debug].present?
|
169
171
|
end
|
170
172
|
|
171
173
|
# fix back button issue with caching
|
@@ -274,7 +276,7 @@ module PgHero
|
|
274
276
|
|
275
277
|
def free_space_stats
|
276
278
|
render json: [
|
277
|
-
{name: "Free Space", data: @database.free_space_stats(duration: 14.days, period: 1.hour), library: chart_library_options}
|
279
|
+
{name: "Free Space", data: @database.free_space_stats(duration: 14.days, period: 1.hour), library: chart_library_options}
|
278
280
|
]
|
279
281
|
end
|
280
282
|
|
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
<meta charset="utf-8" />
|
7
7
|
<%= favicon_link_tag "pghero/favicon.png" %>
|
8
|
-
<% if defined?(Propshaft::Railtie) %>
|
8
|
+
<% if defined?(Propshaft::Railtie) && Rails.application.assets.is_a?(Propshaft::Assembly) %>
|
9
9
|
<%= stylesheet_link_tag "pghero/nouislider", "pghero/arduino-light", "pghero/application" %>
|
10
|
-
<%= javascript_include_tag "pghero/jquery", "pghero/nouislider", "pghero/Chart.bundle", "pghero/chartkick", "pghero/highlight.min", "pghero/application" %>
|
10
|
+
<%= javascript_include_tag "pghero/jquery", "pghero/nouislider", "pghero/Chart.bundle", "pghero/chartkick", "pghero/highlight.min", "pghero/application", nonce: true %>
|
11
11
|
<% else %>
|
12
12
|
<%= stylesheet_link_tag "pghero/application" %>
|
13
|
-
<%= javascript_include_tag "pghero/application" %>
|
13
|
+
<%= javascript_include_tag "pghero/application", nonce: true %>
|
14
14
|
<% end %>
|
15
15
|
</head>
|
16
16
|
<body>
|
@@ -1,10 +1,10 @@
|
|
1
1
|
<table class="table queries">
|
2
2
|
<thead>
|
3
3
|
<tr>
|
4
|
-
<th
|
5
|
-
<th
|
6
|
-
<th
|
7
|
-
<th
|
4
|
+
<th class="width-25">Pid</th>
|
5
|
+
<th class="width-25">Duration</th>
|
6
|
+
<th class="width-25">State</th>
|
7
|
+
<th class="width-25"></th>
|
8
8
|
</tr>
|
9
9
|
</thead>
|
10
10
|
<tbody>
|
@@ -39,15 +39,15 @@
|
|
39
39
|
</td>
|
40
40
|
</tr>
|
41
41
|
<tr>
|
42
|
-
<td colspan="
|
42
|
+
<td colspan="4" class="query-row">
|
43
43
|
<%= query[:source] %> <span class="text-muted"><%= query[:user] %></span>
|
44
|
-
<pre
|
44
|
+
<pre class="query-pre"><code><%= query[:query] %></code></pre>
|
45
45
|
</td>
|
46
46
|
</tr>
|
47
47
|
<% end %>
|
48
48
|
</tbody>
|
49
49
|
</table>
|
50
50
|
|
51
|
-
|
51
|
+
<%= javascript_tag nonce: true do %>
|
52
52
|
highlightQueries();
|
53
|
-
|
53
|
+
<% end %>
|
@@ -2,9 +2,9 @@
|
|
2
2
|
<% unless local_assigns[:xhr] %>
|
3
3
|
<thead>
|
4
4
|
<tr>
|
5
|
-
<th
|
6
|
-
<th
|
7
|
-
<th
|
5
|
+
<th class="width-33"><%= local_assigns[:sort_headers] ? link_to("Total Time", {sort: nil}, data: {sort: nil}) : "Total Time" %></th>
|
6
|
+
<th class="width-33"><%= local_assigns[:sort_headers] ? link_to("Average Time", {sort: "average_time"}, data: {sort: "average_time"}) : "Average Time" %></th>
|
7
|
+
<th class="width-33"><%= local_assigns[:sort_headers] ? link_to("Calls", {sort: "calls"}, data: {sort: "calls"}) : "Calls" %></th>
|
8
8
|
</tr>
|
9
9
|
</thead>
|
10
10
|
<% end %>
|
@@ -57,8 +57,8 @@
|
|
57
57
|
</td>
|
58
58
|
</tr>
|
59
59
|
<tr>
|
60
|
-
<td colspan="3"
|
61
|
-
<pre><code
|
60
|
+
<td colspan="3" class="query-row">
|
61
|
+
<pre><code class="query-code"><%= query[:query] %></code></pre>
|
62
62
|
<% if query[:query] == "<insufficient privilege>" %>
|
63
63
|
<p class="text-muted">For security reasons, only superusers can see queries executed by other users.</p>
|
64
64
|
<% end %>
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<div id="range-start"></div>
|
5
5
|
</div>
|
6
6
|
|
7
|
-
|
7
|
+
<%= javascript_tag nonce: true do %>
|
8
8
|
var sort = <%= pghero_js_value(@sort) %>;
|
9
9
|
var minAverageTime = <%= pghero_js_value(@min_average_time) %>;
|
10
10
|
var minCalls = <%= pghero_js_value(@min_calls) %>;
|
@@ -13,4 +13,4 @@
|
|
13
13
|
var endAt = <%= pghero_js_value(@end_at.to_i * 1000) %>;
|
14
14
|
|
15
15
|
initSlider();
|
16
|
-
|
16
|
+
<% end %>
|
@@ -1,13 +1,14 @@
|
|
1
1
|
<% if index && !details[:covering_index] %>
|
2
2
|
<% unless @debug %>
|
3
|
-
<div
|
3
|
+
<div class="show-details">Details</div>
|
4
4
|
<% end %>
|
5
|
-
<code><pre
|
5
|
+
<code><pre class="create-index">CREATE INDEX CONCURRENTLY ON <%= index[:table] %><% if index[:using] %> USING <%= index[:using] %><% end %> (<%= index[:columns].join(", ") %>)</pre></code>
|
6
6
|
<% end %>
|
7
|
-
<div
|
8
|
-
<code><pre
|
7
|
+
<div class="details<%= " hide" unless @debug %>">
|
8
|
+
<code><pre><% if details[:explanation] %><%= details[:explanation] %>
|
9
9
|
<% end %><% if details[:row_estimates] %>Rows: <%= details[:rows] %>
|
10
|
-
Row progression: <%= details[:row_progression].to_a.join(", ") %>
|
10
|
+
<% if details[:row_progression] %>Row progression: <%= details[:row_progression].to_a.join(", ") %>
|
11
|
+
<% end %>
|
11
12
|
|
12
13
|
Row estimates
|
13
14
|
<%= details[:row_estimates].to_a.map { |k, v| "- #{k}: #{v}" }.join("\n") %><% end %><% if details[:table_indexes] %>
|
@@ -7,24 +7,24 @@
|
|
7
7
|
<h3>By Database</h3>
|
8
8
|
|
9
9
|
<div id="chart-1" class="chart pie-chart">Loading...</div>
|
10
|
-
|
10
|
+
<%= javascript_tag nonce: true do %>
|
11
11
|
new Chartkick.PieChart("chart-1", <%= pghero_js_value(@connections_by_database) %>);
|
12
|
-
|
12
|
+
<% end %>
|
13
13
|
|
14
14
|
<h3>By User</h3>
|
15
15
|
|
16
16
|
<div id="chart-2" class="chart pie-chart">Loading...</div>
|
17
|
-
|
17
|
+
<%= javascript_tag nonce: true do %>
|
18
18
|
new Chartkick.PieChart("chart-2", <%= pghero_js_value(@connections_by_user) %>);
|
19
|
-
|
19
|
+
<% end %>
|
20
20
|
|
21
21
|
<% if @connections_by_ssl_status %>
|
22
22
|
<h3>By Security</h3>
|
23
23
|
|
24
24
|
<div id="chart-3" class="chart pie-chart">Loading...</div>
|
25
|
-
|
25
|
+
<%= javascript_tag nonce: true do %>
|
26
26
|
new Chartkick.PieChart("chart-3", <%= pghero_js_value(@connections_by_ssl_status) %>);
|
27
|
-
|
27
|
+
<% end %>
|
28
28
|
<% end %>
|
29
29
|
|
30
30
|
<%= render partial: "connections_table", locals: {connection_sources: @connection_sources} %>
|
@@ -4,9 +4,9 @@
|
|
4
4
|
<%= form_tag explain_path do %>
|
5
5
|
<div class="field"><%= text_area_tag :query, @query, placeholder: "Enter a SQL query" %></div>
|
6
6
|
<p>
|
7
|
-
<%= submit_tag "Explain", class: "btn btn-info
|
7
|
+
<%= submit_tag "Explain", class: "btn btn-info right-5" %>
|
8
8
|
<% if @explain_analyze_enabled %>
|
9
|
-
<%= submit_tag "Analyze", class: "btn btn-danger
|
9
|
+
<%= submit_tag "Analyze", class: "btn btn-danger right-5" %>
|
10
10
|
<% end %>
|
11
11
|
<%= submit_tag "Visualize", class: "btn btn-danger" %>
|
12
12
|
</p>
|
@@ -127,7 +127,7 @@
|
|
127
127
|
<table class="table">
|
128
128
|
<thead>
|
129
129
|
<tr>
|
130
|
-
<th
|
130
|
+
<th class="width-33">Column</th>
|
131
131
|
<th>Sequence</th>
|
132
132
|
</tr>
|
133
133
|
</thead>
|
@@ -251,7 +251,7 @@
|
|
251
251
|
<thead>
|
252
252
|
<tr>
|
253
253
|
<th>Table</th>
|
254
|
-
<th
|
254
|
+
<th class="width-20">Transactions Left</th>
|
255
255
|
</tr>
|
256
256
|
</thead>
|
257
257
|
<tbody>
|
@@ -279,9 +279,9 @@
|
|
279
279
|
<thead>
|
280
280
|
<tr>
|
281
281
|
<th>Column</th>
|
282
|
-
<th
|
283
|
-
<th
|
284
|
-
<th
|
282
|
+
<th class="width-20">Type</th>
|
283
|
+
<th class="width-20">Values Left</th>
|
284
|
+
<th class="width-10">% Left</th>
|
285
285
|
</tr>
|
286
286
|
</thead>
|
287
287
|
<tbody>
|
@@ -332,7 +332,7 @@
|
|
332
332
|
</td>
|
333
333
|
</tr>
|
334
334
|
<tr>
|
335
|
-
<td
|
335
|
+
<td class="query-row">
|
336
336
|
<pre><code>DROP INDEX CONCURRENTLY <%= pghero_pretty_ident(index[:name], schema: index[:schema]) %>;
|
337
337
|
<%= index[:definition].sub("CREATE INDEX ", "CREATE INDEX CONCURRENTLY ") %>;</code></pre>
|
338
338
|
</td>
|
@@ -366,7 +366,7 @@
|
|
366
366
|
</td>
|
367
367
|
</tr>
|
368
368
|
<tr>
|
369
|
-
<td
|
369
|
+
<td class="query-row">
|
370
370
|
<pre><code>ALTER TABLE <%= pghero_pretty_ident(constraint[:table], schema: constraint[:schema]) %> VALIDATE CONSTRAINT <%= pghero_pretty_ident(constraint[:name]) %>;</code></pre>
|
371
371
|
</td>
|
372
372
|
</tr>
|
@@ -383,15 +383,15 @@
|
|
383
383
|
<p>
|
384
384
|
These indexes exist, but aren’t needed. Remove them
|
385
385
|
<% if @show_migrations %>
|
386
|
-
<a href="
|
386
|
+
<a href="#" class="migration-link">with a migration</a>
|
387
387
|
<% end %>
|
388
388
|
for faster writes.
|
389
389
|
</p>
|
390
390
|
|
391
|
-
<div
|
391
|
+
<div class="migration">
|
392
392
|
<pre>rails generate migration remove_unneeded_indexes</pre>
|
393
393
|
<p>And paste</p>
|
394
|
-
<pre
|
394
|
+
<pre><% @duplicate_indexes.each do |query| %>
|
395
395
|
<%= pghero_remove_index(query[:unneeded_index]) %><% end %></pre>
|
396
396
|
</div>
|
397
397
|
|
@@ -426,14 +426,14 @@
|
|
426
426
|
Add indexes to speed up queries.
|
427
427
|
<% if @show_migrations %>
|
428
428
|
Here’s a
|
429
|
-
<a href="
|
429
|
+
<a href="#" class="migration-link">migration</a> to help.
|
430
430
|
<% end %>
|
431
431
|
</p>
|
432
432
|
|
433
|
-
<div
|
433
|
+
<div class="migration">
|
434
434
|
<pre>rails generate migration add_suggested_indexes</pre>
|
435
435
|
<p>And paste</p>
|
436
|
-
<pre
|
436
|
+
<pre>commit_db_transaction
|
437
437
|
<% @suggested_indexes.each do |index| %>
|
438
438
|
<% if index[:using] && index[:using] != "btree" %>
|
439
439
|
add_index <%= index[:table].to_sym.inspect %>, <%= index[:columns].first.inspect %>, using: <%= index[:using].inspect %>, algorithm: :concurrently
|
@@ -487,15 +487,15 @@ pg_stat_statements.track = all</pre>
|
|
487
487
|
<p>
|
488
488
|
Unused indexes cause unnecessary overhead. Remove them
|
489
489
|
<% if @show_migrations %>
|
490
|
-
<a href="
|
490
|
+
<a href="#" class="migration-link">with a migration</a>
|
491
491
|
<% end %>
|
492
492
|
for faster writes.
|
493
493
|
</p>
|
494
494
|
|
495
|
-
<div
|
495
|
+
<div class="migration">
|
496
496
|
<pre>rails generate migration remove_unused_indexes</pre>
|
497
497
|
<p>And paste</p>
|
498
|
-
<pre
|
498
|
+
<pre><% @unused_indexes.each do |query| %>
|
499
499
|
<%= pghero_remove_index(query)%><% end %></pre>
|
500
500
|
</div>
|
501
501
|
|
@@ -503,7 +503,7 @@ pg_stat_statements.track = all</pre>
|
|
503
503
|
<thead>
|
504
504
|
<tr>
|
505
505
|
<th>Name</th>
|
506
|
-
<th
|
506
|
+
<th class="width-20">Index Size</th>
|
507
507
|
</tr>
|
508
508
|
</thead>
|
509
509
|
<tbody>
|
@@ -518,6 +518,6 @@ pg_stat_statements.track = all</pre>
|
|
518
518
|
</div>
|
519
519
|
<% end %>
|
520
520
|
|
521
|
-
|
521
|
+
<%= javascript_tag nonce: true do %>
|
522
522
|
highlightQueries();
|
523
|
-
|
523
|
+
<% end %>
|
@@ -25,15 +25,15 @@ ALTER INDEX new_index RENAME TO index;</code></pre>
|
|
25
25
|
<thead>
|
26
26
|
<tr>
|
27
27
|
<th>Index</th>
|
28
|
-
<th
|
29
|
-
<th
|
28
|
+
<th class="width-15">Bloat</th>
|
29
|
+
<th class="width-15">Size</th>
|
30
30
|
</tr>
|
31
31
|
</thead>
|
32
32
|
<tbody>
|
33
33
|
<% @index_bloat.each do |index| %>
|
34
34
|
<tr>
|
35
35
|
<td>
|
36
|
-
<span
|
36
|
+
<span class="break-all"><%= index[:index] %></span>
|
37
37
|
<% if index[:primary] %>
|
38
38
|
<span class="primary-key">PRIMARY</span>
|
39
39
|
<% end %>
|
@@ -43,7 +43,7 @@ ALTER INDEX new_index RENAME TO index;</code></pre>
|
|
43
43
|
</tr>
|
44
44
|
<% if @show_sql && !index[:primary] %>
|
45
45
|
<tr>
|
46
|
-
<td colspan="3"
|
46
|
+
<td colspan="3" class="query-row">
|
47
47
|
<% new_index = "new_#{index[:index]}".first(63) %>
|
48
48
|
<pre><code><%= index[:definition].sub(" INDEX ", " INDEX CONCURRENTLY \n ").sub(index[:index], new_index) %>;
|
49
49
|
|
@@ -67,6 +67,6 @@ ALTER INDEX <%= pghero_pretty_ident(new_index) %>
|
|
67
67
|
<% end %>
|
68
68
|
</div>
|
69
69
|
|
70
|
-
|
70
|
+
<%= javascript_tag nonce: true do %>
|
71
71
|
highlightQueries();
|
72
|
-
|
72
|
+
<% end %>
|
@@ -5,10 +5,10 @@
|
|
5
5
|
<thead>
|
6
6
|
<tr>
|
7
7
|
<th>Table</th>
|
8
|
-
<th
|
9
|
-
<th
|
8
|
+
<th class="width-20">Last Vacuum</th>
|
9
|
+
<th class="width-20">Last Analyze</th>
|
10
10
|
<% if @show_dead_rows %>
|
11
|
-
<th
|
11
|
+
<th class="width-20">Dead Rows</th>
|
12
12
|
<% end %>
|
13
13
|
</tr>
|
14
14
|
</thead>
|
@@ -4,13 +4,13 @@
|
|
4
4
|
<% end %>
|
5
5
|
|
6
6
|
<% if !@historical_query_stats_enabled %>
|
7
|
-
<h1
|
7
|
+
<h1 class="push-left">Queries</h1>
|
8
8
|
<% end %>
|
9
9
|
|
10
10
|
<% if @historical_query_stats_enabled %>
|
11
11
|
<%= render partial: "query_stats_slider" %>
|
12
12
|
<% elsif @database.query_stats_table_exists? && (columns = @database.missing_query_stats_columns).any? %>
|
13
|
-
<div
|
13
|
+
<div class="clear-both">
|
14
14
|
<p>Add missing columns to re-enable historical query stats.</p>
|
15
15
|
<pre><code><% @database.missing_query_stats_columns.each do |column| %>ALTER TABLE pghero_query_stats ADD COLUMN "<%= column %>" <%= column == "query_hash" ? "bigint" : "text" %>;
|
16
16
|
<% end %></code></pre>
|
@@ -23,9 +23,9 @@
|
|
23
23
|
<div class="alert alert-danger">Cannot understand start or end time.</div>
|
24
24
|
<% elsif @query_stats.any? || @historical_query_stats_enabled %>
|
25
25
|
<%= render partial: "queries_table", locals: {queries: @query_stats, sort_headers: true} %>
|
26
|
-
|
26
|
+
<%= javascript_tag nonce: true do %>
|
27
27
|
highlightQueries();
|
28
|
-
|
28
|
+
<% end %>
|
29
29
|
<% else %>
|
30
30
|
<p>Stats are not available yet. Come back soon!</p>
|
31
31
|
<% end %>
|
@@ -7,8 +7,8 @@
|
|
7
7
|
</h1>
|
8
8
|
|
9
9
|
<h1>Size</h1>
|
10
|
-
<div id="chart-1" class="chart"
|
11
|
-
|
10
|
+
<div id="chart-1" class="chart">Loading...</div>
|
11
|
+
<%= javascript_tag nonce: true do %>
|
12
12
|
new Chartkick.LineChart("chart-1", <%= pghero_js_value(@chart_data) %>, {colors: ["#5bc0de"], legend: false, min: null, bytes: true, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
|
13
|
-
|
13
|
+
<% end %>
|
14
14
|
</div>
|
@@ -1,8 +1,8 @@
|
|
1
1
|
<div class="content">
|
2
|
-
<pre><code
|
3
|
-
|
2
|
+
<pre><code class="query-code"><%= @query %></code></pre>
|
3
|
+
<%= javascript_tag nonce: true do %>
|
4
4
|
highlightQueries()
|
5
|
-
|
5
|
+
<% end %>
|
6
6
|
|
7
7
|
<% if @explain_enabled && @explainable_query %>
|
8
8
|
<p>
|
@@ -11,11 +11,11 @@
|
|
11
11
|
<% end %>
|
12
12
|
|
13
13
|
<% if @origins && @origins.keys.select { |k| k.length > 0 }.any? %>
|
14
|
-
<table
|
14
|
+
<table class="origins-table">
|
15
15
|
<thead>
|
16
16
|
<tr>
|
17
17
|
<th colspan="2">
|
18
|
-
<div
|
18
|
+
<div class="push-right">Approx. Time</div>
|
19
19
|
Origin
|
20
20
|
</th>
|
21
21
|
</tr>
|
@@ -23,14 +23,14 @@
|
|
23
23
|
<tbody>
|
24
24
|
<% @origins.sort_by { |o, c| [-c, o.to_s] }.each do |origin, count| %>
|
25
25
|
<tr>
|
26
|
-
<td class="origin"
|
26
|
+
<td class="origin">
|
27
27
|
<% if origin.length > 0 %>
|
28
28
|
<%= origin %>
|
29
29
|
<% else %>
|
30
30
|
<span class="text-muted">Unknown</span>
|
31
31
|
<% end %>
|
32
32
|
</td>
|
33
|
-
<td
|
33
|
+
<td class="origin-pct">
|
34
34
|
<% pct = (100.0 * count / @total_count).round %>
|
35
35
|
<% if pct == 0 %>
|
36
36
|
< 1%
|
@@ -47,22 +47,22 @@
|
|
47
47
|
<!-- chart -->
|
48
48
|
<% if @chart_data %>
|
49
49
|
<h1>Total Time <small>ms</small></h1>
|
50
|
-
<div id="chart-1" class="chart"
|
51
|
-
|
50
|
+
<div id="chart-1" class="chart">Loading...</div>
|
51
|
+
<%= javascript_tag nonce: true do %>
|
52
52
|
new Chartkick.LineChart("chart-1", <%= pghero_js_value(@chart_data) %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
|
53
|
-
|
53
|
+
<% end %>
|
54
54
|
|
55
55
|
<h1>Average Time <small>ms</small></h1>
|
56
|
-
<div id="chart-2" class="chart"
|
57
|
-
|
56
|
+
<div id="chart-2" class="chart">Loading...</div>
|
57
|
+
<%= javascript_tag nonce: true do %>
|
58
58
|
new Chartkick.LineChart("chart-2", <%= pghero_js_value(@chart2_data) %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
|
59
|
-
|
59
|
+
<% end %>
|
60
60
|
|
61
61
|
<h1>Calls</h1>
|
62
|
-
<div id="chart-3" class="chart"
|
63
|
-
|
62
|
+
<div id="chart-3" class="chart">Loading...</div>
|
63
|
+
<%= javascript_tag nonce: true do %>
|
64
64
|
new Chartkick.LineChart("chart-3", <%= pghero_js_value(@chart3_data) %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
|
65
|
-
|
65
|
+
<% end %>
|
66
66
|
<% else %>
|
67
67
|
<p>
|
68
68
|
Enable
|
@@ -77,8 +77,8 @@
|
|
77
77
|
<table>
|
78
78
|
<thead>
|
79
79
|
<tr>
|
80
|
-
<th
|
81
|
-
<th
|
80
|
+
<th class="width-25">Name</th>
|
81
|
+
<th class="width-25">Rows</th>
|
82
82
|
<th>Indexes</th>
|
83
83
|
</tr>
|
84
84
|
</thead>
|
@@ -86,7 +86,7 @@
|
|
86
86
|
<% @tables.each do |table| %>
|
87
87
|
<tr>
|
88
88
|
<td><%= table %></td>
|
89
|
-
<td><%= @row_counts[table] %></td>
|
89
|
+
<td><%= number_with_delimiter(@row_counts[table]) if @row_counts[table] %></td>
|
90
90
|
<td>
|
91
91
|
<% if @indexes_timeout %>
|
92
92
|
Not available
|
@@ -4,10 +4,10 @@
|
|
4
4
|
<p>Database Size: <%= @database_size %></p>
|
5
5
|
|
6
6
|
<% if @system_stats_enabled %>
|
7
|
-
<div id="chart-1" class="chart"
|
8
|
-
|
7
|
+
<div id="chart-1" class="chart">Loading...</div>
|
8
|
+
<%= javascript_tag nonce: true do %>
|
9
9
|
new Chartkick.LineChart("chart-1", <%= pghero_js_value(free_space_stats_path) %>, {colors: ["#5bc0de"], bytes: true, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
|
10
|
-
|
10
|
+
<% end %>
|
11
11
|
<% end %>
|
12
12
|
|
13
13
|
<!--
|
@@ -20,7 +20,7 @@
|
|
20
20
|
<p>
|
21
21
|
<%= pluralize(@unused_indexes.size, "unused index") %>. Remove them
|
22
22
|
<% if @show_migrations %>
|
23
|
-
<a href="
|
23
|
+
<a href="#" class="migration-link">with a migration</a>
|
24
24
|
<% end %>
|
25
25
|
for faster writes.
|
26
26
|
|
@@ -29,10 +29,10 @@
|
|
29
29
|
<% end %>
|
30
30
|
</p>
|
31
31
|
|
32
|
-
<div
|
32
|
+
<div class="migration">
|
33
33
|
<pre>rails generate migration remove_unused_indexes</pre>
|
34
34
|
<p>And paste</p>
|
35
|
-
<pre
|
35
|
+
<pre><% @unused_indexes.sort_by { |q| [-q[:size_bytes], q[:index]] }.each do |query| %>
|
36
36
|
<%= pghero_remove_index(query) %><% end %></pre>
|
37
37
|
</div>
|
38
38
|
<% end %>
|
@@ -44,20 +44,20 @@
|
|
44
44
|
<thead>
|
45
45
|
<tr>
|
46
46
|
<th><%= link_to (@only_tables ? "Table" : "Relation"), @header_options.merge(sort: "name") %></th>
|
47
|
-
<th
|
47
|
+
<th class="width-15"><%= link_to "Size", @header_options %></th>
|
48
48
|
<% if @space_stats_enabled %>
|
49
|
-
<th
|
49
|
+
<th class="width-15"><%= link_to "#{@days}d Growth", @header_options.merge(sort: "growth") %></th>
|
50
50
|
<% end %>
|
51
51
|
</tr>
|
52
52
|
</thead>
|
53
53
|
<tbody>
|
54
54
|
<% @relation_sizes.each do |query| %>
|
55
55
|
<tr>
|
56
|
-
<td
|
57
|
-
<span
|
56
|
+
<td class="<%= query[:type] == "index" ? "space-index" : "" %>">
|
57
|
+
<span class="break-all">
|
58
58
|
<% name = query[:relation] || query[:table] %>
|
59
59
|
<% if @space_stats_enabled %>
|
60
|
-
<%= link_to name, relation_space_path(name, schema: query[:schema]), target: "_blank",
|
60
|
+
<%= link_to name, relation_space_path(name, schema: query[:schema]), target: "_blank", class: "relation-link" %>
|
61
61
|
<% else %>
|
62
62
|
<%= name %>
|
63
63
|
<% end %>
|
@@ -7,28 +7,28 @@
|
|
7
7
|
<% path_options = {params: {duration: @duration, period: @period}} %>
|
8
8
|
|
9
9
|
<h1>CPU</h1>
|
10
|
-
<div id="chart-1" class="chart"
|
11
|
-
|
10
|
+
<div id="chart-1" class="chart">Loading...</div>
|
11
|
+
<%= javascript_tag nonce: true do %>
|
12
12
|
new Chartkick.LineChart("chart-1", <%= pghero_js_value(cpu_usage_path(path_options)) %>, {max: 100, colors: ["#5bc0de"], suffix: "%", library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
|
13
|
-
|
13
|
+
<% end %>
|
14
14
|
|
15
15
|
<h1>Load</h1>
|
16
|
-
<div id="chart-2" class="chart"
|
17
|
-
|
16
|
+
<div id="chart-2" class="chart">Loading...</div>
|
17
|
+
<%= javascript_tag nonce: true do %>
|
18
18
|
new Chartkick.LineChart("chart-2", <%= pghero_js_value(load_stats_path(path_options)) %>, {colors: ["#5bc0de", "#d9534f"], library: {plugins: {tooltip: {intersect: false, mode: "nearest"}}}})
|
19
|
-
|
19
|
+
<% end %>
|
20
20
|
|
21
21
|
<h1>Connections</h1>
|
22
|
-
<div id="chart-3" class="chart"
|
23
|
-
|
22
|
+
<div id="chart-3" class="chart">Loading...</div>
|
23
|
+
<%= javascript_tag nonce: true do %>
|
24
24
|
new Chartkick.LineChart("chart-3", <%= pghero_js_value(connection_stats_path(path_options)) %>, {colors: ["#5bc0de"], library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
|
25
|
-
|
25
|
+
<% end %>
|
26
26
|
|
27
27
|
<% if @database.replica? %>
|
28
28
|
<h1>Replication Lag</h1>
|
29
|
-
<div id="chart-4" class="chart"
|
30
|
-
|
29
|
+
<div id="chart-4" class="chart">Loading...</div>
|
30
|
+
<%= javascript_tag nonce: true do %>
|
31
31
|
new Chartkick.LineChart("chart-4", <%= pghero_js_value(replication_lag_stats_path(path_options)) %>, {colors: ["#5bc0de"], library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
|
32
|
-
|
32
|
+
<% end %>
|
33
33
|
<% end %>
|
34
34
|
</div>
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<thead>
|
6
6
|
<tr>
|
7
7
|
<th>Setting</th>
|
8
|
-
<th
|
8
|
+
<th class="width-20">Value</th>
|
9
9
|
</tr>
|
10
10
|
</thead>
|
11
11
|
<tbody>
|
@@ -30,7 +30,7 @@
|
|
30
30
|
<thead>
|
31
31
|
<tr>
|
32
32
|
<th>Setting</th>
|
33
|
-
<th
|
33
|
+
<th class="width-20">Value</th>
|
34
34
|
</tr>
|
35
35
|
</thead>
|
36
36
|
<tbody>
|
data/lib/pghero/database.rb
CHANGED
@@ -126,7 +126,7 @@ module PgHero
|
|
126
126
|
# rough check for Postgres adapter
|
127
127
|
# keep this message generic so it's useful
|
128
128
|
# when empty url set in Docker image pghero.yml
|
129
|
-
unless @connection_model.
|
129
|
+
unless @connection_model.connection_db_config.adapter.to_s.match?(/postg/i)
|
130
130
|
raise Error, "Invalid connection URL"
|
131
131
|
end
|
132
132
|
@adapter_checked = true
|
@@ -145,7 +145,7 @@ module PgHero
|
|
145
145
|
config_options = {env_name: PgHero.env, PgHero.spec_name_key => config["spec"], PgHero.include_replicas_key => true}
|
146
146
|
resolved = ActiveRecord::Base.configurations.configs_for(**config_options)
|
147
147
|
raise Error, "Spec not found: #{config["spec"]}" unless resolved
|
148
|
-
url =
|
148
|
+
url = resolved.configuration_hash
|
149
149
|
end
|
150
150
|
|
151
151
|
url = url.dup
|
data/lib/pghero/engine.rb
CHANGED
@@ -4,8 +4,8 @@ module PgHero
|
|
4
4
|
|
5
5
|
initializer "pghero", group: :all do |app|
|
6
6
|
# check if Rails api mode
|
7
|
-
if app.config.respond_to?(:assets)
|
8
|
-
if
|
7
|
+
if app.config.respond_to?(:assets) && defined?(Sprockets)
|
8
|
+
if Sprockets::VERSION.to_i >= 4
|
9
9
|
app.config.assets.precompile << "pghero/application.js"
|
10
10
|
app.config.assets.precompile << "pghero/application.css"
|
11
11
|
app.config.assets.precompile << "pghero/favicon.png"
|
data/lib/pghero/methods/basic.rb
CHANGED
@@ -31,21 +31,26 @@ module PgHero
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def quote_ident(value)
|
34
|
-
|
34
|
+
with_connection { |c| c.quote_column_name(value) }
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
-
def select_all(sql,
|
40
|
-
|
39
|
+
def select_all(sql, stats: false, query_columns: [])
|
40
|
+
with_connection(stats: stats) do |conn|
|
41
|
+
select_all_leased(sql, conn: conn, query_columns: query_columns)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def select_all_leased(sql, conn:, query_columns:)
|
41
46
|
# squish for logs
|
42
47
|
retries = 0
|
43
48
|
begin
|
44
49
|
result = conn.select_all(add_source(squish(sql)))
|
45
|
-
if ActiveRecord::VERSION::
|
46
|
-
result = result.map(&:symbolize_keys)
|
50
|
+
if ActiveRecord::VERSION::MAJOR >= 8
|
51
|
+
result = result.to_a.map(&:symbolize_keys)
|
47
52
|
else
|
48
|
-
result = result.map
|
53
|
+
result = result.map(&:symbolize_keys)
|
49
54
|
end
|
50
55
|
if filter_data
|
51
56
|
query_columns.each do |column|
|
@@ -81,7 +86,7 @@ module PgHero
|
|
81
86
|
end
|
82
87
|
|
83
88
|
def select_all_stats(sql, **options)
|
84
|
-
select_all(sql, **options,
|
89
|
+
select_all(sql, **options, stats: true)
|
85
90
|
end
|
86
91
|
|
87
92
|
def select_all_size(sql)
|
@@ -92,24 +97,17 @@ module PgHero
|
|
92
97
|
result
|
93
98
|
end
|
94
99
|
|
95
|
-
def select_one(sql
|
96
|
-
select_all(sql
|
97
|
-
end
|
98
|
-
|
99
|
-
def select_one_stats(sql)
|
100
|
-
select_one(sql, conn: stats_connection)
|
100
|
+
def select_one(sql)
|
101
|
+
select_all(sql).first.values.first
|
101
102
|
end
|
102
103
|
|
103
104
|
def execute(sql)
|
104
|
-
|
105
|
-
end
|
106
|
-
|
107
|
-
def connection
|
108
|
-
connection_model.connection
|
105
|
+
with_connection { |c| c.execute(add_source(sql)) }
|
109
106
|
end
|
110
107
|
|
111
|
-
def
|
112
|
-
::PgHero::Stats
|
108
|
+
def with_connection(stats: false, &block)
|
109
|
+
model = stats ? ::PgHero::Stats : connection_model
|
110
|
+
model.connection_pool.with_connection(&block)
|
113
111
|
end
|
114
112
|
|
115
113
|
def squish(str)
|
@@ -121,15 +119,15 @@ module PgHero
|
|
121
119
|
end
|
122
120
|
|
123
121
|
def quote(value)
|
124
|
-
|
122
|
+
with_connection { |c| c.quote(value) }
|
125
123
|
end
|
126
124
|
|
127
125
|
def quote_table_name(value)
|
128
|
-
|
126
|
+
with_connection { |c| c.quote_table_name(value) }
|
129
127
|
end
|
130
128
|
|
131
129
|
def quote_column_name(value)
|
132
|
-
|
130
|
+
with_connection { |c| c.quote_column_name(value) }
|
133
131
|
end
|
134
132
|
|
135
133
|
def unquote(part)
|
@@ -150,7 +148,7 @@ module PgHero
|
|
150
148
|
end
|
151
149
|
|
152
150
|
def table_exists?(table)
|
153
|
-
|
151
|
+
with_connection(stats: true) { |c| c.table_exists?(table) }
|
154
152
|
end
|
155
153
|
end
|
156
154
|
end
|
@@ -9,7 +9,7 @@ module PgHero
|
|
9
9
|
|
10
10
|
# use transaction for safety
|
11
11
|
with_transaction(statement_timeout: (explain_timeout_sec * 1000).round, rollback: true) do
|
12
|
-
if (sql.
|
12
|
+
if (sql.delete_suffix(";").include?(";") || sql.upcase.include?("COMMIT")) && !explain_safe?
|
13
13
|
raise ActiveRecord::StatementInvalid, "Unsafe statement"
|
14
14
|
end
|
15
15
|
explanation = execute("EXPLAIN #{sql}").map { |v| v["QUERY PLAN"] }.join("\n")
|
@@ -322,7 +322,7 @@ module PgHero
|
|
322
322
|
all_queries_total_minutes: stats2.sum { |s| s[:all_queries_total_minutes] }
|
323
323
|
}
|
324
324
|
value[:total_percent] = value[:total_minutes] * 100.0 / value[:all_queries_total_minutes]
|
325
|
-
value[:explainable_query] = stats2.map { |s| s[:explainable_query] }.
|
325
|
+
value[:explainable_query] = stats2.map { |s| s[:explainable_query] }.find { |q| q && explainable?(q) }
|
326
326
|
query_stats << value
|
327
327
|
end
|
328
328
|
query_stats
|
@@ -46,7 +46,7 @@ module PgHero
|
|
46
46
|
indexes += existing_columns["brin"][index[:table]]
|
47
47
|
end
|
48
48
|
|
49
|
-
covering_index = indexes.find { |e| index_covers?(e.map { |v| v.
|
49
|
+
covering_index = indexes.find { |e| index_covers?(e.map { |v| v.delete_suffix(" inet_ops") }, index[:columns]) }
|
50
50
|
if covering_index
|
51
51
|
best_index[:covering_index] = covering_index
|
52
52
|
best_index[:explanation] = "Covered by index on (#{covering_index.join(", ")})"
|
@@ -79,7 +79,9 @@ module PgHero
|
|
79
79
|
suggested_indexes.each do |index|
|
80
80
|
p index
|
81
81
|
if create
|
82
|
-
|
82
|
+
with_connection do |connection|
|
83
|
+
connection.execute("CREATE INDEX CONCURRENTLY ON #{quote_table_name(index[:table])} (#{index[:columns].map { |c| quote_column_name(c) }.join(",")})")
|
84
|
+
end
|
83
85
|
end
|
84
86
|
end
|
85
87
|
end
|
@@ -136,8 +136,8 @@ module PgHero
|
|
136
136
|
start_time = end_time - duration
|
137
137
|
|
138
138
|
# validate input since we need to interpolate below
|
139
|
-
raise Error, "Invalid metric name" unless
|
140
|
-
raise Error, "Invalid database id" unless
|
139
|
+
raise Error, "Invalid metric name" unless /\A[a-z\/_]+\z/i.match?(metric_name)
|
140
|
+
raise Error, "Invalid database id" unless /\A[a-z0-9\-:]+\z/i.match?(gcp_database_id)
|
141
141
|
|
142
142
|
# we handle four situations:
|
143
143
|
# 1. google-cloud-monitoring-v3
|
data/lib/pghero/version.rb
CHANGED
data/lib/pghero.rb
CHANGED
@@ -64,7 +64,7 @@ module PgHero
|
|
64
64
|
:query_stats_available?, :query_stats_enabled?, :query_stats_extension_enabled?, :query_stats_readable?,
|
65
65
|
:rds_stats, :read_iops_stats, :aws_region, :relation_sizes, :replica?, :replication_lag, :replication_lag_stats,
|
66
66
|
:reset_query_stats, :reset_stats, :running_queries, :aws_secret_access_key, :sequence_danger, :sequences, :settings,
|
67
|
-
:slow_queries, :space_growth, :ssl_used?, :
|
67
|
+
:slow_queries, :space_growth, :ssl_used?, :suggested_indexes, :suggested_indexes_by_query,
|
68
68
|
:suggested_indexes_enabled?, :system_stats_enabled?, :table_caching, :table_hit_rate, :table_stats,
|
69
69
|
:total_connections, :transaction_id_danger, :unused_indexes, :unused_tables, :write_iops_stats
|
70
70
|
|
@@ -243,14 +243,12 @@ module PgHero
|
|
243
243
|
|
244
244
|
# private
|
245
245
|
def connection_config(model)
|
246
|
-
|
246
|
+
model.connection_db_config.configuration_hash
|
247
247
|
end
|
248
248
|
|
249
249
|
# private
|
250
|
-
# Rails 6.1 deprecates `spec_name` for `name`
|
251
|
-
# https://github.com/rails/rails/pull/38536
|
252
250
|
def spec_name_key
|
253
|
-
|
251
|
+
:name
|
254
252
|
end
|
255
253
|
|
256
254
|
# private
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pghero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '6'
|
19
|
+
version: '6.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '6'
|
26
|
+
version: '6.1'
|
27
27
|
description:
|
28
28
|
email: andrew@ankane.org
|
29
29
|
executables: []
|
@@ -117,14 +117,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
117
|
requirements:
|
118
118
|
- - ">="
|
119
119
|
- !ruby/object:Gem::Version
|
120
|
-
version: '
|
120
|
+
version: '3.1'
|
121
121
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
122
|
requirements:
|
123
123
|
- - ">="
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
126
|
requirements: []
|
127
|
-
rubygems_version: 3.5.
|
127
|
+
rubygems_version: 3.5.16
|
128
128
|
signing_key:
|
129
129
|
specification_version: 4
|
130
130
|
summary: A performance dashboard for Postgres
|