pghero 2.0.6 → 2.0.7
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 +7 -0
- data/app/assets/javascripts/pghero/Chart.bundle.js +8930 -6892
- data/app/controllers/pg_hero/home_controller.rb +3 -2
- data/app/views/pg_hero/home/_queries_table.html.erb +1 -1
- data/app/views/pg_hero/home/index.html.erb +1 -1
- data/guides/Contributing.md +16 -0
- data/lib/pghero.rb +1 -1
- data/lib/pghero/methods/query_stats.rb +7 -5
- data/lib/pghero/methods/sequences.rb +25 -10
- data/lib/pghero/version.rb +1 -1
- metadata +4 -2
@@ -155,15 +155,16 @@ module PgHero
|
|
155
155
|
|
156
156
|
def show_query
|
157
157
|
@query_hash = params[:query_hash].to_i
|
158
|
+
@user = params[:user].to_s
|
158
159
|
@title = @query_hash
|
159
160
|
|
160
|
-
stats = @database.query_stats(historical: true, query_hash: @query_hash, start_at: 24.hours.ago).
|
161
|
+
stats = @database.query_stats(historical: true, query_hash: @query_hash, start_at: 24.hours.ago).find { |qs| qs[:user] == @user }
|
161
162
|
if stats
|
162
163
|
@query = stats[:query]
|
163
164
|
@explainable_query = stats[:explainable_query]
|
164
165
|
|
165
166
|
if @show_details
|
166
|
-
query_hash_stats = @database.query_hash_stats(@query_hash)
|
167
|
+
query_hash_stats = @database.query_hash_stats(@query_hash, user: @user)
|
167
168
|
|
168
169
|
@chart_data = [{name: "Value", data: query_hash_stats.map { |r| [r[:captured_at], (r[:total_minutes] * 60 * 1000).round] }, library: chart_library_options}]
|
169
170
|
@chart2_data = [{name: "Value", data: query_hash_stats.map { |r| [r[:captured_at], r[:average_time].round(1)] }, library: chart_library_options}]
|
@@ -51,7 +51,7 @@
|
|
51
51
|
<% end %>
|
52
52
|
<% end %>
|
53
53
|
<% if @show_details && query[:query_hash] %>
|
54
|
-
<%= link_to "details", show_query_path(query[:query_hash]), target: "_blank" %>
|
54
|
+
<%= link_to "details", show_query_path(query[:query_hash], user: query[:user]), target: "_blank" %>
|
55
55
|
<% end %>
|
56
56
|
</span>
|
57
57
|
</td>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
```sh
|
4
|
+
git clone https://github.com/ankane/pghero.git
|
5
|
+
git clone https://github.com/pghero/pghero.git pghero-dev
|
6
|
+
cd pghero-dev
|
7
|
+
git checkout dev
|
8
|
+
createdb pghero_dev
|
9
|
+
export DATABASE_URL=postgres:///pghero_dev
|
10
|
+
bundle exec rails generate pghero:query_stats
|
11
|
+
bundle exec rails generate pghero:space_stats
|
12
|
+
bundle exec rake db:migrate
|
13
|
+
foreman start
|
14
|
+
```
|
15
|
+
|
16
|
+
And visit [http://localhost:5000](http://localhost:5000)
|
data/lib/pghero.rb
CHANGED
@@ -110,7 +110,7 @@ module PgHero
|
|
110
110
|
def capture_query_stats(verbose: false)
|
111
111
|
each_database do |database|
|
112
112
|
puts "Capturing query stats for #{database.id}..." if verbose
|
113
|
-
database.capture_query_stats
|
113
|
+
database.capture_query_stats(raise_errors: true)
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
@@ -56,10 +56,11 @@ module PgHero
|
|
56
56
|
true
|
57
57
|
end
|
58
58
|
|
59
|
-
def reset_query_stats
|
59
|
+
def reset_query_stats(raise_errors: false)
|
60
60
|
execute("SELECT pg_stat_statements_reset()")
|
61
61
|
true
|
62
|
-
rescue ActiveRecord::StatementInvalid
|
62
|
+
rescue ActiveRecord::StatementInvalid => e
|
63
|
+
raise e if raise_errors
|
63
64
|
false
|
64
65
|
end
|
65
66
|
|
@@ -87,7 +88,7 @@ module PgHero
|
|
87
88
|
#
|
88
89
|
# to get around this, we capture queries for every Postgres database before we
|
89
90
|
# reset query stats for the Postgres instance with the `capture_query_stats` option
|
90
|
-
def capture_query_stats
|
91
|
+
def capture_query_stats(raise_errors: false)
|
91
92
|
return if config["capture_query_stats"] && config["capture_query_stats"] != true
|
92
93
|
|
93
94
|
# get all databases that use same query stats and build mapping
|
@@ -105,7 +106,7 @@ module PgHero
|
|
105
106
|
|
106
107
|
supports_query_hash = supports_query_hash?
|
107
108
|
|
108
|
-
if query_stats.any? { |_, v| v.any? } && reset_query_stats
|
109
|
+
if query_stats.any? { |_, v| v.any? } && reset_query_stats(raise_errors: raise_errors)
|
109
110
|
query_stats.each do |db_id, db_query_stats|
|
110
111
|
if db_query_stats.any?
|
111
112
|
values =
|
@@ -133,7 +134,7 @@ module PgHero
|
|
133
134
|
query_stats.select { |q| q[:calls].to_i >= slow_query_calls.to_i && q[:average_time].to_f >= slow_query_ms.to_f }
|
134
135
|
end
|
135
136
|
|
136
|
-
def query_hash_stats(query_hash)
|
137
|
+
def query_hash_stats(query_hash, user: nil)
|
137
138
|
if historical_query_stats_enabled? && supports_query_hash?
|
138
139
|
start_at = 24.hours.ago
|
139
140
|
select_all_stats <<-SQL
|
@@ -149,6 +150,7 @@ module PgHero
|
|
149
150
|
database = #{quote(id)}
|
150
151
|
AND captured_at >= #{quote(start_at)}
|
151
152
|
AND query_hash = #{quote(query_hash)}
|
153
|
+
#{user ? "AND \"user\" = #{quote(user)}" : ""}
|
152
154
|
ORDER BY
|
153
155
|
1 ASC
|
154
156
|
SQL
|
@@ -2,43 +2,58 @@ module PgHero
|
|
2
2
|
module Methods
|
3
3
|
module Sequences
|
4
4
|
def sequences
|
5
|
+
# get columns with default values
|
6
|
+
# use pg_get_expr to get correct default value
|
7
|
+
# it's what information_schema.columns uses
|
5
8
|
sequences = select_all <<-SQL
|
6
9
|
SELECT
|
7
|
-
n.nspname AS
|
10
|
+
n.nspname AS table_schema,
|
8
11
|
c.relname AS table,
|
9
12
|
attname AS column,
|
10
13
|
format_type(a.atttypid, a.atttypmod) AS column_type,
|
11
|
-
|
12
|
-
s.relname AS sequence
|
14
|
+
pg_get_expr(d.adbin, d.adrelid) AS default_value
|
13
15
|
FROM
|
14
16
|
pg_catalog.pg_attribute a
|
15
17
|
INNER JOIN
|
16
18
|
pg_catalog.pg_class c ON c.oid = a.attrelid
|
17
19
|
INNER JOIN
|
18
20
|
pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
19
|
-
LEFT JOIN
|
20
|
-
pg_catalog.pg_attrdef d ON (a.attrelid, a.attnum) = (d.adrelid, d.adnum)
|
21
21
|
INNER JOIN
|
22
|
-
pg_catalog.
|
23
|
-
AND s.relname = regexp_replace(d.adsrc, '^nextval\\(''(.*)''\\:\\:regclass\\)$', '\\1')
|
22
|
+
pg_catalog.pg_attrdef d ON (a.attrelid, a.attnum) = (d.adrelid, d.adnum)
|
24
23
|
WHERE
|
25
24
|
NOT a.attisdropped
|
26
25
|
AND a.attnum > 0
|
27
26
|
AND d.adsrc LIKE 'nextval%'
|
28
|
-
ORDER BY
|
29
|
-
s.relname ASC
|
30
27
|
SQL
|
31
28
|
|
29
|
+
# parse out sequence
|
30
|
+
sequences.each do |column|
|
31
|
+
m = /^nextval\('(.+)'\:\:regclass\)$/.match(column.delete(:default_value))
|
32
|
+
column[:schema], column[:sequence] = unquote_ident(m[1])
|
33
|
+
column[:max_value] = column[:column_type] == 'integer' ? 2147483647 : 9223372036854775807
|
34
|
+
end
|
35
|
+
|
32
36
|
select_all(sequences.map { |s| "SELECT last_value FROM #{quote_ident(s[:schema])}.#{quote_ident(s[:sequence])}" }.join(" UNION ALL ")).each_with_index do |row, i|
|
33
37
|
sequences[i][:last_value] = row[:last_value]
|
34
38
|
end
|
35
39
|
|
36
|
-
sequences
|
40
|
+
sequences.sort_by { |s| s[:sequence] }
|
37
41
|
end
|
38
42
|
|
39
43
|
def sequence_danger(threshold: 0.9)
|
40
44
|
sequences.select { |s| s[:last_value] / s[:max_value].to_f > threshold }.sort_by { |s| s[:max_value] - s[:last_value] }
|
41
45
|
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def unquote_ident(value)
|
50
|
+
schema, seq = value.split(".")
|
51
|
+
unless seq
|
52
|
+
seq = schema
|
53
|
+
schema = 'public'
|
54
|
+
end
|
55
|
+
[unquote(schema), unquote(seq)]
|
56
|
+
end
|
42
57
|
end
|
43
58
|
end
|
44
59
|
end
|
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.0.
|
4
|
+
version: 2.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -153,6 +153,7 @@ files:
|
|
153
153
|
- app/views/pg_hero/home/system.html.erb
|
154
154
|
- app/views/pg_hero/home/tune.html.erb
|
155
155
|
- config/routes.rb
|
156
|
+
- guides/Contributing.md
|
156
157
|
- guides/Docker.md
|
157
158
|
- guides/Heroku.md
|
158
159
|
- guides/Linux.md
|
@@ -221,6 +222,7 @@ signing_key:
|
|
221
222
|
specification_version: 4
|
222
223
|
summary: A performance dashboard for Postgres
|
223
224
|
test_files:
|
225
|
+
- guides/Contributing.md
|
224
226
|
- guides/Docker.md
|
225
227
|
- guides/Heroku.md
|
226
228
|
- guides/Linux.md
|