pghero 2.4.1 → 2.4.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pghero might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +1 -1
- data/app/controllers/pg_hero/home_controller.rb +43 -10
- data/app/helpers/pg_hero/home_helper.rb +11 -0
- data/app/views/pg_hero/home/connections.html.erb +9 -0
- data/app/views/pg_hero/home/index.html.erb +2 -2
- data/app/views/pg_hero/home/space.html.erb +1 -1
- data/lib/pghero.rb +1 -1
- data/lib/pghero/methods/connections.rb +35 -0
- data/lib/pghero/methods/query_stats.rb +1 -1
- data/lib/pghero/methods/suggested_indexes.rb +1 -1
- data/lib/pghero/version.rb +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: 33927c2c6b6d2c286f872adb99d7095f836108872c4f9af3ca180d6a70cb0b48
|
4
|
+
data.tar.gz: 8f2f7565269047b8a351bd712a931e26febc1b6bd96f21b3c1f81ece50807f8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76dd17666d9842cad4a540c519df850cf784d97eeccd9792ff853d90a633628b5615459521bc2f5b382e75ffe35b52023e4cf8cfdbabc2924154a6feb7d8c94e
|
7
|
+
data.tar.gz: c0c5ba7f1823182241ca7c8365969a5f661f2abca55551832ee3e64d61eabb5432ad7dcb3e2b9f81b972c125d80bf22f5a55e2ef13a471889fe393b1976d1e10
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -10,7 +10,7 @@ A performance dashboard for Postgres
|
|
10
10
|
|
11
11
|
---
|
12
12
|
|
13
|
-
[![Screenshot](https://pghero.dokkuapp.com/assets/
|
13
|
+
[![Screenshot](https://pghero.dokkuapp.com/assets/pghero-f8abe426e6bf54bb7dba87b425bb809740ebd386208bcd280a7e802b053a1023.png)](https://pghero.dokkuapp.com/)
|
14
14
|
|
15
15
|
## Installation
|
16
16
|
|
@@ -270,11 +270,41 @@ module PgHero
|
|
270
270
|
|
271
271
|
def connections
|
272
272
|
@title = "Connections"
|
273
|
-
|
274
|
-
|
273
|
+
connections = @database.connections
|
274
|
+
|
275
|
+
@total_connections = connections.count
|
276
|
+
@connection_sources = group_connections(connections, [:database, :user, :source, :ip])
|
277
|
+
@connections_by_database = group_connections_by_key(connections, :database)
|
278
|
+
@connections_by_user = group_connections_by_key(connections, :user)
|
279
|
+
|
280
|
+
if params[:security] && @database.server_version_num >= 90500
|
281
|
+
connections.each do |connection|
|
282
|
+
connection[:ssl_status] =
|
283
|
+
if connection[:ssl]
|
284
|
+
# no way to tell if client used verify-full
|
285
|
+
# so connection may not be actually secure
|
286
|
+
"SSL"
|
287
|
+
else
|
288
|
+
# variety of reasons for no SSL
|
289
|
+
if !connection[:database].present?
|
290
|
+
"Internal Process"
|
291
|
+
elsif !connection[:ip]
|
292
|
+
if connection[:state]
|
293
|
+
"Socket"
|
294
|
+
else
|
295
|
+
# tcp or socket, don't have permission to tell
|
296
|
+
"No SSL"
|
297
|
+
end
|
298
|
+
else
|
299
|
+
# tcp
|
300
|
+
# could separate out localhost since this should be safe
|
301
|
+
"No SSL"
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
275
305
|
|
276
|
-
|
277
|
-
|
306
|
+
@connections_by_ssl_status = group_connections_by_key(connections, :ssl_status)
|
307
|
+
end
|
278
308
|
end
|
279
309
|
|
280
310
|
def maintenance
|
@@ -376,12 +406,15 @@ module PgHero
|
|
376
406
|
@show_details = @historical_query_stats_enabled && @database.supports_query_hash?
|
377
407
|
end
|
378
408
|
|
379
|
-
def group_connections(
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
409
|
+
def group_connections(connections, keys)
|
410
|
+
connections
|
411
|
+
.group_by { |conn| conn.slice(*keys) }
|
412
|
+
.map { |k, v| k.merge(total_connections: v.count) }
|
413
|
+
.sort_by { |v| [-v[:total_connections]] + keys.map { |k| v[k].to_s } }
|
414
|
+
end
|
415
|
+
|
416
|
+
def group_connections_by_key(connections, key)
|
417
|
+
group_connections(connections, [key]).map { |v| [v[key], v[:total_connections]] }.to_h
|
385
418
|
end
|
386
419
|
|
387
420
|
def check_api
|
@@ -15,5 +15,16 @@ module PgHero
|
|
15
15
|
def pghero_js_var(name, value)
|
16
16
|
"var #{name} = #{json_escape(value.to_json(root: false))};".html_safe
|
17
17
|
end
|
18
|
+
|
19
|
+
def pghero_remove_index(query)
|
20
|
+
if query[:columns]
|
21
|
+
columns = query[:columns].map(&:to_sym)
|
22
|
+
columns = columns.first if columns.size == 1
|
23
|
+
end
|
24
|
+
ret = String.new("remove_index #{query[:table].to_sym.inspect}")
|
25
|
+
ret << ", name: #{(query[:name] || query[:index]).to_s.inspect}"
|
26
|
+
ret << ", column: #{columns.inspect}" if columns
|
27
|
+
ret
|
28
|
+
end
|
18
29
|
end
|
19
30
|
end
|
@@ -18,6 +18,15 @@
|
|
18
18
|
new Chartkick.PieChart("chart-2", <%= json_escape(@connections_by_user.to_json).html_safe %>);
|
19
19
|
</script>
|
20
20
|
|
21
|
+
<% if @connections_by_ssl_status %>
|
22
|
+
<h3>By Security</h3>
|
23
|
+
|
24
|
+
<div id="chart-3" class="chart" style="height: 260px; line-height: 260px; margin-bottom: 20px;">Loading...</div>
|
25
|
+
<script>
|
26
|
+
new Chartkick.PieChart("chart-3", <%= json_escape(@connections_by_ssl_status.to_json).html_safe %>);
|
27
|
+
</script>
|
28
|
+
<% end %>
|
29
|
+
|
21
30
|
<%= render partial: "connections_table", locals: {connection_sources: @connection_sources} %>
|
22
31
|
<% end %>
|
23
32
|
</div>
|
@@ -387,7 +387,7 @@
|
|
387
387
|
<pre>rails generate migration remove_unneeded_indexes</pre>
|
388
388
|
<p>And paste</p>
|
389
389
|
<pre style="overflow: scroll; white-space: pre; word-break: normal;"><% @duplicate_indexes.each do |query| %>
|
390
|
-
|
390
|
+
<%= pghero_remove_index(query[:unneeded_index]) %><% end %></pre>
|
391
391
|
</div>
|
392
392
|
|
393
393
|
<table class="table duplicate-indexes">
|
@@ -491,7 +491,7 @@ pg_stat_statements.track = all</pre>
|
|
491
491
|
<pre>rails generate migration remove_unused_indexes</pre>
|
492
492
|
<p>And paste</p>
|
493
493
|
<pre style="overflow: scroll; white-space: pre; word-break: normal;"><% @unused_indexes.each do |query| %>
|
494
|
-
|
494
|
+
<%= pghero_remove_index(query)%><% end %></pre>
|
495
495
|
</div>
|
496
496
|
|
497
497
|
<table class="table">
|
@@ -33,7 +33,7 @@
|
|
33
33
|
<pre>rails generate migration remove_unused_indexes</pre>
|
34
34
|
<p>And paste</p>
|
35
35
|
<pre style="overflow: scroll; white-space: pre; word-break: normal;"><% @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 %>
|
39
39
|
|
data/lib/pghero.rb
CHANGED
@@ -51,7 +51,7 @@ module PgHero
|
|
51
51
|
class << self
|
52
52
|
extend Forwardable
|
53
53
|
def_delegators :primary_database, :access_key_id, :analyze, :analyze_tables, :autoindex, :autovacuum_danger,
|
54
|
-
:best_index, :blocked_queries, :connection_sources, :connection_states, :connection_stats,
|
54
|
+
:best_index, :blocked_queries, :connections, :connection_sources, :connection_states, :connection_stats,
|
55
55
|
:cpu_usage, :create_user, :database_size, :db_instance_identifier, :disable_query_stats, :drop_user,
|
56
56
|
:duplicate_indexes, :enable_query_stats, :explain, :historical_query_stats_enabled?, :index_caching,
|
57
57
|
:index_hit_rate, :index_usage, :indexes, :invalid_constraints, :invalid_indexes, :kill, :kill_all, :kill_long_running_queries,
|
@@ -1,6 +1,41 @@
|
|
1
1
|
module PgHero
|
2
2
|
module Methods
|
3
3
|
module Connections
|
4
|
+
def connections
|
5
|
+
if server_version_num >= 90500
|
6
|
+
select_all <<-SQL
|
7
|
+
SELECT
|
8
|
+
pg_stat_activity.pid,
|
9
|
+
datname AS database,
|
10
|
+
usename AS user,
|
11
|
+
application_name AS source,
|
12
|
+
client_addr AS ip,
|
13
|
+
state,
|
14
|
+
ssl
|
15
|
+
FROM
|
16
|
+
pg_stat_activity
|
17
|
+
LEFT JOIN
|
18
|
+
pg_stat_ssl ON pg_stat_activity.pid = pg_stat_ssl.pid
|
19
|
+
ORDER BY
|
20
|
+
pg_stat_activity.pid
|
21
|
+
SQL
|
22
|
+
else
|
23
|
+
select_all <<-SQL
|
24
|
+
SELECT
|
25
|
+
pid,
|
26
|
+
datname AS database,
|
27
|
+
usename AS user,
|
28
|
+
application_name AS source,
|
29
|
+
client_addr AS ip,
|
30
|
+
state
|
31
|
+
FROM
|
32
|
+
pg_stat_activity
|
33
|
+
ORDER BY
|
34
|
+
pid
|
35
|
+
SQL
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
4
39
|
def total_connections
|
5
40
|
select_one("SELECT COUNT(*) FROM pg_stat_activity")
|
6
41
|
end
|
@@ -2,7 +2,7 @@ module PgHero
|
|
2
2
|
module Methods
|
3
3
|
module QueryStats
|
4
4
|
def query_stats(historical: false, start_at: nil, end_at: nil, min_average_time: nil, min_calls: nil, **options)
|
5
|
-
current_query_stats = historical && end_at && end_at < Time.now ? [] : current_query_stats(options)
|
5
|
+
current_query_stats = historical && end_at && end_at < Time.now ? [] : current_query_stats(**options)
|
6
6
|
historical_query_stats = historical && historical_query_stats_enabled? ? historical_query_stats(start_at: start_at, end_at: end_at, **options) : []
|
7
7
|
|
8
8
|
query_stats = combine_query_stats((current_query_stats + historical_query_stats).group_by { |q| [q[:query_hash], q[:user]] })
|
@@ -48,7 +48,7 @@ module PgHero
|
|
48
48
|
def suggested_indexes(suggested_indexes_by_query: nil, **options)
|
49
49
|
indexes = []
|
50
50
|
|
51
|
-
(suggested_indexes_by_query || self.suggested_indexes_by_query(options)).select { |_s, i| i[:found] && !i[:covering_index] }.group_by { |_s, i| i[:index] }.each do |index, group|
|
51
|
+
(suggested_indexes_by_query || self.suggested_indexes_by_query(**options)).select { |_s, i| i[:found] && !i[:covering_index] }.group_by { |_s, i| i[:index] }.each do |index, group|
|
52
52
|
details = {}
|
53
53
|
group.map(&:second).each do |g|
|
54
54
|
details = details.except(:index).deep_merge(g)
|
data/lib/pghero/version.rb
CHANGED
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: 2.4.
|
4
|
+
version: 2.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -200,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
200
|
- !ruby/object:Gem::Version
|
201
201
|
version: '0'
|
202
202
|
requirements: []
|
203
|
-
rubygems_version: 3.
|
203
|
+
rubygems_version: 3.1.2
|
204
204
|
signing_key:
|
205
205
|
specification_version: 4
|
206
206
|
summary: A performance dashboard for Postgres
|