pghero 0.1.9 → 0.1.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5dea912ab838c4fae3ac427223c11432f059eec
4
- data.tar.gz: 8615bc4cc2913aa1c639f8e75235985b29f50c76
3
+ metadata.gz: b36df22eb125725ef48c4c9c1cb4094a2cd346b8
4
+ data.tar.gz: d683feef9adc1a6b0b09ed8ea844159e24b250cd
5
5
  SHA512:
6
- metadata.gz: 9f333855160f97440da34cb9395c91139af6d125c7d8c12ef957691478fdbeb9318c403584af294ded8826956b99a63d79b8b6bc6fc62adda88c7fd19afabcca
7
- data.tar.gz: fd3c203da38d5238d493c33eae218403597c21f8791c84edc61f74db9ed20d08b8980cc1c2029873b6ef50ad77e7136823c48e82ba7cee35165d57538a2718c6
6
+ metadata.gz: 42c4d3ccc26df2ac3a0011051acad9f9b06e8f61da89eed183a275d5d3a1752bbcb5a7a756ea26f3bfb20e6e05832c310c1bc87b63cfc6be194eb2b2ce46f247
7
+ data.tar.gz: 1e584dd852a119509488d59f6fb5346d211e43da9cf221000f96899cb71ea9bf8002780b00d1e70586664c435bfea764a09816cfd992ac642ae350fe4a1ccea3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.1.10
2
+
3
+ - Added connections page
4
+ - Added message for insufficient privilege
5
+ - Added `ip` to `connection_sources`
6
+
1
7
  ## 0.1.9
2
8
 
3
9
  - Added tune page
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in pghero.gemspec
4
4
  gemspec
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
3
 
4
- task :default => :test
4
+ task default: :test
5
5
  Rake::TestTask.new do |t|
6
6
  t.libs << "test"
7
7
  t.pattern = "test/**/*_test.rb"
@@ -45,7 +45,7 @@ module PgHero
45
45
 
46
46
  def system_stats
47
47
  @title = "System Stats"
48
- @cpu_usage = PgHero.cpu_usage.map{|k, v| [k, v.round] }
48
+ @cpu_usage = PgHero.cpu_usage.map { |k, v| [k, v.round] }
49
49
  @connection_stats = PgHero.connection_stats
50
50
  end
51
51
 
@@ -54,7 +54,7 @@ module PgHero
54
54
  @query = params[:query]
55
55
  # TODO use get + token instead of post so users can share links
56
56
  # need to prevent CSRF and DoS
57
- if request.post? and @query
57
+ if request.post? && @query
58
58
  begin
59
59
  @explanation = PgHero.explain(@query)
60
60
  rescue ActiveRecord::StatementInvalid => e
@@ -68,6 +68,11 @@ module PgHero
68
68
  @settings = PgHero.settings
69
69
  end
70
70
 
71
+ def connections
72
+ @title = "Connections"
73
+ @total_connections = PgHero.total_connections
74
+ end
75
+
71
76
  def kill
72
77
  if PgHero.kill(params[:pid])
73
78
  redirect_to root_path, notice: "Query killed"
@@ -82,21 +87,17 @@ module PgHero
82
87
  end
83
88
 
84
89
  def enable_query_stats
85
- begin
86
- PgHero.enable_query_stats
87
- redirect_to :back, notice: "Query stats enabled"
88
- rescue ActiveRecord::StatementInvalid => e
89
- redirect_to :back, alert: "The database user does not have permission to enable query stats"
90
- end
90
+ PgHero.enable_query_stats
91
+ redirect_to :back, notice: "Query stats enabled"
92
+ rescue ActiveRecord::StatementInvalid
93
+ redirect_to :back, alert: "The database user does not have permission to enable query stats"
91
94
  end
92
95
 
93
96
  def reset_query_stats
94
- begin
95
- PgHero.reset_query_stats
96
- redirect_to :back, notice: "Query stats reset"
97
- rescue ActiveRecord::StatementInvalid => e
98
- redirect_to :back, alert: "The database user does not have permission to reset query stats"
99
- end
97
+ PgHero.reset_query_stats
98
+ redirect_to :back, notice: "Query stats reset"
99
+ rescue ActiveRecord::StatementInvalid
100
+ redirect_to :back, alert: "The database user does not have permission to reset query stats"
100
101
  end
101
102
 
102
103
  protected
@@ -105,6 +106,5 @@ module PgHero
105
106
  @query_stats_enabled = PgHero.query_stats_enabled?
106
107
  @system_stats_enabled = PgHero.system_stats_enabled?
107
108
  end
108
-
109
109
  end
110
110
  end
@@ -362,6 +362,7 @@
362
362
  <li class="<%= controller.action_name == "space" ? "active" : "" %>"><%= link_to "Space", space_path %></li>
363
363
  <li class="<%= controller.action_name == "explain" ? "active" : "" %>"><%= link_to "Explain", explain_path %></li>
364
364
  <li class="<%= controller.action_name == "queries" ? "active" : "" %>"><%= link_to "Live Queries", queries_path %></li>
365
+ <li class="<%= controller.action_name == "connections" ? "active" : "" %>"><%= link_to "Connections", connections_path %></li>
365
366
  <li class="<%= controller.action_name == "tune" ? "active" : "" %>"><%= link_to "Tune", tune_path %></li>
366
367
  </ul>
367
368
  </div>
@@ -0,0 +1,23 @@
1
+ <p><%= pluralize(total_connections, "connection") %></p>
2
+ <% if show_message %>
3
+ <p>
4
+ <%= link_to "Use connection pooling", "http://www.craigkerstiens.com/2014/05/22/on-connection-pooling/", target: "_blank" %> for better performance. <%= link_to "PgBouncer", "https://wiki.postgresql.org/wiki/PgBouncer", target: "_blank" %> is a solid option.
5
+ </p>
6
+ <% end %>
7
+
8
+ <table class="table">
9
+ <thead>
10
+ <tr>
11
+ <th>Top Sources</th>
12
+ <th>Connections</th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <% PgHero.connection_sources.first(10).each do |source| %>
17
+ <tr>
18
+ <td><%= source["source"] %> <span class="text-muted"><%= source["ip"] %></span></td>
19
+ <td style="width: 20%;"><%= number_with_delimiter(source["total_connections"]) %></td>
20
+ </tr>
21
+ <% end %>
22
+ </tbody>
23
+ </table>
@@ -26,7 +26,12 @@
26
26
  <td><%= number_with_delimiter(query["calls"].to_i) %></td>
27
27
  </tr>
28
28
  <tr>
29
- <td colspan="3" style="border-top: none; padding: 0;"><pre><%= query["query"] %></pre></td>
29
+ <td colspan="3" style="border-top: none; padding: 0;">
30
+ <pre><%= query["query"] %></pre>
31
+ <% if query["query"] == "<insufficient privilege>" %>
32
+ <p class="text-muted">For security reasons, only superusers can see queries executed by other users.</p>
33
+ <% end %>
34
+ </td>
30
35
  </tr>
31
36
  <% end %>
32
37
  </tbody>
@@ -0,0 +1,5 @@
1
+ <div class="content">
2
+ <h1>Connections</h1>
3
+
4
+ <%= render partial: "connections_table", locals: {total_connections: @total_connections, show_message: false} %>
5
+ </div>
@@ -73,27 +73,7 @@
73
73
  <% if !@good_total_connections %>
74
74
  <div class="content">
75
75
  <h1>High Number of Connections</h1>
76
- <p><%= pluralize(@total_connections, "connection") %></p>
77
- <p>
78
- <%= link_to "Use connection pooling", "http://www.craigkerstiens.com/2014/05/22/on-connection-pooling/", target: "_blank" %> for better performance. <%= link_to "PgBouncer", "https://wiki.postgresql.org/wiki/PgBouncer", target: "_blank" %> is a solid option.
79
- </p>
80
-
81
- <table class="table">
82
- <thead>
83
- <tr>
84
- <th>Top Sources</th>
85
- <th>Connections</th>
86
- </tr>
87
- </thead>
88
- <tbody>
89
- <% PgHero.connection_sources.first(10).each do |source| %>
90
- <tr>
91
- <td><%= source["source"] %></td>
92
- <td style="width: 20%;"><%= number_with_delimiter(source["total_connections"]) %></td>
93
- </tr>
94
- <% end %>
95
- </tbody>
96
- </table>
76
+ <%= render partial: "connections_table", locals: {total_connections: @total_connections, show_message: true} %>
97
77
  </div>
98
78
  <% end %>
99
79
 
data/config/routes.rb CHANGED
@@ -7,6 +7,7 @@ PgHero::Engine.routes.draw do
7
7
  get "system_stats", to: "home#system_stats"
8
8
  get "explain", to: "home#explain"
9
9
  get "tune", to: "home#tune"
10
+ get "connections", to: "home#connections"
10
11
 
11
12
  post "kill", to: "home#kill"
12
13
  post "kill_all", to: "home#kill_all"
data/lib/pghero.rb CHANGED
@@ -17,7 +17,6 @@ module PgHero
17
17
  self.total_connections_threshold = 100
18
18
 
19
19
  class << self
20
-
21
20
  def running_queries
22
21
  select_all <<-SQL
23
22
  SELECT
@@ -206,16 +205,19 @@ module PgHero
206
205
  select_all <<-SQL
207
206
  SELECT
208
207
  application_name AS source,
208
+ client_addr AS ip,
209
209
  COUNT(*) AS total_connections
210
210
  FROM
211
211
  pg_stat_activity
212
212
  WHERE
213
213
  pid <> pg_backend_pid()
214
214
  GROUP BY
215
- application_name
215
+ application_name,
216
+ ip
216
217
  ORDER BY
217
218
  COUNT(*) DESC,
218
- application_name ASC
219
+ application_name ASC,
220
+ client_addr ASC
219
221
  SQL
220
222
  end
221
223
 
@@ -315,12 +317,9 @@ module PgHero
315
317
  end
316
318
 
317
319
  def query_stats_readable?
318
- begin
319
- # ensure the user has access to the table
320
- select_all("SELECT has_table_privilege(current_user, 'pg_stat_statements', 'SELECT')").first["has_table_privilege"] == "t"
321
- rescue ActiveRecord::StatementInvalid
322
- false
323
- end
320
+ select_all("SELECT has_table_privilege(current_user, 'pg_stat_statements', 'SELECT')").first["has_table_privilege"] == "t"
321
+ rescue ActiveRecord::StatementInvalid
322
+ false
324
323
  end
325
324
 
326
325
  def enable_query_stats
@@ -363,7 +362,7 @@ module PgHero
363
362
  statistics: ["Average"]
364
363
  )
365
364
  data = {}
366
- resp[:datapoints].sort_by{|d| d[:timestamp] }.each do |d|
365
+ resp[:datapoints].sort_by { |d| d[:timestamp] }.each do |d|
367
366
  data[d[:timestamp]] = d[:average]
368
367
  end
369
368
  data
@@ -459,10 +458,10 @@ module PgHero
459
458
 
460
459
  # use transaction for safety
461
460
  Connection.transaction do
462
- if !explain_safe and (sql.sub(/;\z/, "").include?(";") or sql.upcase.include?("COMMIT"))
461
+ if !explain_safe && (sql.sub(/;\z/, "").include?(";") || sql.upcase.include?("COMMIT"))
463
462
  raise ActiveRecord::StatementInvalid, "Unsafe statement"
464
463
  end
465
- explanation = select_all("EXPLAIN #{sql}").map{|v| v["QUERY PLAN"] }.join("\n")
464
+ explanation = select_all("EXPLAIN #{sql}").map { |v| v["QUERY PLAN"] }.join("\n")
466
465
  raise ActiveRecord::Rollback
467
466
  end
468
467
 
@@ -470,26 +469,24 @@ module PgHero
470
469
  end
471
470
 
472
471
  def explain_safe?
473
- begin
474
- select_all("SELECT 1; SELECT 1")
475
- false
476
- rescue ActiveRecord::StatementInvalid
477
- true
478
- end
472
+ select_all("SELECT 1; SELECT 1")
473
+ false
474
+ rescue ActiveRecord::StatementInvalid
475
+ true
479
476
  end
480
477
 
481
478
  def settings
482
- names = %w[
479
+ names = %w(
483
480
  max_connections shared_buffers effective_cache_size work_mem
484
481
  maintenance_work_mem checkpoint_segments checkpoint_completion_target
485
482
  wal_buffers default_statistics_target
486
- ]
487
- values = Hash[ select_all(Connection.send(:sanitize_sql_array, ["SELECT name, setting, unit FROM pg_settings WHERE name IN (?)", names])).sort_by{|row| names.index(row["name"]) }.map{|row| [row["name"], friendly_value(row["setting"], row["unit"])] } ]
488
- Hash[ names.map{|name| [name, values[name]] } ]
483
+ )
484
+ values = Hash[select_all(Connection.send(:sanitize_sql_array, ["SELECT name, setting, unit FROM pg_settings WHERE name IN (?)", names])).sort_by { |row| names.index(row["name"]) }.map { |row| [row["name"], friendly_value(row["setting"], row["unit"])] }]
485
+ Hash[names.map { |name| [name, values[name]] }]
489
486
  end
490
487
 
491
488
  def friendly_value(setting, unit)
492
- if %w[kB 8kB].include?(unit)
489
+ if %w(kB 8kB).include?(unit)
493
490
  value = setting.to_i
494
491
  value *= 8 if unit == "8kB"
495
492
 
@@ -520,8 +517,7 @@ module PgHero
520
517
 
521
518
  # from ActiveSupport
522
519
  def squish(str)
523
- str.to_s.gsub(/\A[[:space:]]+/, '').gsub(/[[:space:]]+\z/, '').gsub(/[[:space:]]+/, ' ')
520
+ str.to_s.gsub(/\A[[:space:]]+/, "").gsub(/[[:space:]]+\z/, "").gsub(/[[:space:]]+/, " ")
524
521
  end
525
-
526
522
  end
527
523
  end
@@ -1,3 +1,3 @@
1
1
  module PgHero
2
- VERSION = "0.1.9"
2
+ VERSION = "0.1.10"
3
3
  end
data/pghero.gemspec CHANGED
@@ -1,15 +1,15 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
2
+ lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'pghero/version'
4
+ require "pghero/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "pghero"
8
8
  spec.version = PgHero::VERSION
9
9
  spec.authors = ["Andrew Kane"]
10
10
  spec.email = ["andrew@chartkick.com"]
11
- spec.summary = %q{Database insights made easy}
12
- spec.description = %q{Database insights made easy}
11
+ spec.summary = "Database insights made easy"
12
+ spec.description = "Database insights made easy"
13
13
  spec.homepage = "https://github.com/ankane/pghero"
14
14
  spec.license = "MIT"
15
15
 
data/test/pghero_test.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require_relative "test_helper"
2
2
 
3
3
  class TestPgHero < Minitest::Test
4
-
5
4
  def setup
6
5
  User.delete_all
7
6
  end
@@ -14,7 +13,6 @@ class TestPgHero < Minitest::Test
14
13
 
15
14
  def test_explain_multiple_statements
16
15
  User.create!
17
- assert_raises(ActiveRecord::StatementInvalid){ PgHero.explain("ANALYZE DELETE FROM users; DELETE FROM users; COMMIT") }
16
+ assert_raises(ActiveRecord::StatementInvalid) { PgHero.explain("ANALYZE DELETE FROM users; DELETE FROM users; COMMIT") }
18
17
  end
19
-
20
18
  end
data/test/test_helper.rb CHANGED
@@ -8,7 +8,7 @@ Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
8
8
 
9
9
  ActiveRecord::Base.establish_connection adapter: "postgresql", database: "pghero_test"
10
10
 
11
- ActiveRecord::Migration.create_table :users, force: true do |t|
11
+ ActiveRecord::Migration.create_table :users, force: true do
12
12
  # just id
13
13
  end
14
14
 
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: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-26 00:00:00.000000000 Z
11
+ date: 2015-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -95,8 +95,10 @@ files:
95
95
  - Rakefile
96
96
  - app/controllers/pg_hero/home_controller.rb
97
97
  - app/views/layouts/pg_hero/application.html.erb
98
+ - app/views/pg_hero/home/_connections_table.html.erb
98
99
  - app/views/pg_hero/home/_queries_table.html.erb
99
100
  - app/views/pg_hero/home/_query_stats_table.html.erb
101
+ - app/views/pg_hero/home/connections.html.erb
100
102
  - app/views/pg_hero/home/explain.html.erb
101
103
  - app/views/pg_hero/home/index.html.erb
102
104
  - app/views/pg_hero/home/indexes.html.erb
@@ -142,3 +144,4 @@ summary: Database insights made easy
142
144
  test_files:
143
145
  - test/pghero_test.rb
144
146
  - test/test_helper.rb
147
+ has_rdoc: