pgdexter 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 14bc122b136301535793c29b19336a2d0614f640
4
- data.tar.gz: 624c8c6ae5aabd8a5e2150887aa83efe6e67f9b4
2
+ SHA256:
3
+ metadata.gz: e51c5c9ce5c31760d773177a3b224674752b19de8cc9fa0978e1da2adff9a490
4
+ data.tar.gz: ce9b2e89d2524aafda39bd5a91bb53abde5d0819e0c8751281a5ff7ad10766c2
5
5
  SHA512:
6
- metadata.gz: 44224c687d8590c0441d587b432fde3b85cef77728980059d497ade992cd953e8f8445747de61c984d559f55d74461ac284c6c8423c0f1f8b08e439e361c141d
7
- data.tar.gz: 42ec40ec7527dfc3093853ec013c5b30bacbaee5cbe8d27a1530649bfbdc16c639d9d93d65e72b062d53b33bff1d0a1bec67e971d283f5d5a2e6fea7d884fccd
6
+ metadata.gz: 63cdf589a11ab232f45e26ff8b6a713ef757ce3bc3baf3fecbc51217fb4c3a4bdda0ded52bc631bbb8aaa5fe7ca28d356ab99e200c5af22a3bd1bac9e5efc17b
7
+ data.tar.gz: fcbb680a98f5907a62216ee142fa91b8538965c1fd59c1de48645ee1b5e3525950245d010a128f52b28fda665d0f6fcbf95fa343184b559150646819049f173a
@@ -6,8 +6,9 @@ addons:
6
6
  postgresql: "9.6"
7
7
  before_script:
8
8
  - sudo apt-get install postgresql-server-dev-9.6
9
- - git clone https://github.com/dalibo/hypopg.git
9
+ - git clone https://github.com/HypoPG/hypopg.git
10
10
  - cd hypopg
11
+ - git checkout 1.1.1
11
12
  - make
12
13
  - sudo make install
13
14
  - psql -c 'create database dexter_test;' -U postgres
@@ -1,3 +1,9 @@
1
+ ## 0.3.4
2
+
3
+ - Fixed `--username` option
4
+ - Fixed `JSON::NestingError`
5
+ - Added `--pg-stat-activity` option
6
+
1
7
  ## 0.3.3
2
8
 
3
9
  - Added support for views and materialized views
data/README.md CHANGED
@@ -8,12 +8,12 @@ The automatic indexer for Postgres
8
8
 
9
9
  ## Installation
10
10
 
11
- First, install [HypoPG](https://github.com/dalibo/hypopg) on your database server. This doesn’t require a restart.
11
+ First, install [HypoPG](https://github.com/HypoPG/hypopg) on your database server. This doesn’t require a restart.
12
12
 
13
13
  ```sh
14
14
  cd /tmp
15
- curl -L https://github.com/dalibo/hypopg/archive/1.1.0.tar.gz | tar xz
16
- cd hypopg-1.1.0
15
+ curl -L https://github.com/HypoPG/hypopg/archive/1.1.1.tar.gz | tar xz
16
+ cd hypopg-1.1.1
17
17
  make
18
18
  make install # may need sudo
19
19
  ```
@@ -104,13 +104,19 @@ or pass files:
104
104
  dexter <connection-options> <file1> <file2>
105
105
  ```
106
106
 
107
+ or collect running queries with: [master]
108
+
109
+ ```sh
110
+ dexter <connection-options> --pg-stat-activity
111
+ ```
112
+
107
113
  or use the [pg_stat_statements](https://www.postgresql.org/docs/current/static/pgstatstatements.html) extension:
108
114
 
109
115
  ```sh
110
116
  dexter <connection-options> --pg-stat-statements
111
117
  ```
112
118
 
113
- > Note: Logs are highly preferred over pg_stat_statements, as pg_stat_statements often doesn’t store enough information to optimize queries.
119
+ > Note: Logs or running queries are highly preferred over pg_stat_statements, as pg_stat_statements often doesn’t store enough information to optimize queries.
114
120
 
115
121
  ### Collection Options
116
122
 
@@ -32,6 +32,7 @@ sudo apt-get install dexter
32
32
  ### Debian 9 (Stretch)
33
33
 
34
34
  ```sh
35
+ sudo apt-get -y install apt-transport-https
35
36
  wget -qO- https://dl.packager.io/srv/pghero/dexter/key | sudo apt-key add -
36
37
  sudo wget -O /etc/apt/sources.list.d/dexter.list \
37
38
  https://dl.packager.io/srv/pghero/dexter/master/installer/debian/9.repo
@@ -42,6 +43,7 @@ sudo apt-get install dexter
42
43
  ### Debian 8 (Jesse)
43
44
 
44
45
  ```sh
46
+ sudo apt-get -y install apt-transport-https
45
47
  wget -qO- https://dl.packager.io/srv/pghero/dexter/key | sudo apt-key add -
46
48
  sudo wget -O /etc/apt/sources.list.d/dexter.list \
47
49
  https://dl.packager.io/srv/pghero/dexter/master/installer/debian/8.repo
@@ -11,6 +11,7 @@ require "dexter/collector"
11
11
  require "dexter/indexer"
12
12
  require "dexter/log_parser"
13
13
  require "dexter/csv_log_parser"
14
+ require "dexter/pg_stat_activity_parser"
14
15
  require "dexter/processor"
15
16
  require "dexter/query"
16
17
 
@@ -18,6 +18,8 @@ module Dexter
18
18
  elsif options[:pg_stat_statements]
19
19
  # TODO support streaming option
20
20
  Indexer.new(options).process_stat_statements
21
+ elsif options[:pg_stat_activity]
22
+ Processor.new(:pg_stat_activity, options).perform
21
23
  elsif arguments.any?
22
24
  ARGV.replace(arguments)
23
25
  Processor.new(ARGF, options).perform
@@ -44,6 +46,7 @@ Options:)
44
46
  o.float "--min-calls", "only process queries that have been called a certain number of times", default: 0
45
47
  o.float "--min-time", "only process queries that have consumed a certain amount of DB time, in minutes", default: 0
46
48
  o.integer "--min-cost-savings-pct", default: 50, help: false
49
+ o.boolean "--pg-stat-activity", "use pg_stat_activity", default: false, help: false
47
50
  o.boolean "--pg-stat-statements", "use pg_stat_statements", default: false, help: false
48
51
  o.string "-s", "--statement", "process a single statement"
49
52
  # separator must go here to show up correctly - slop bug?
@@ -25,6 +25,23 @@ module Dexter
25
25
  process_queries(queries)
26
26
  end
27
27
 
28
+ def stat_activity
29
+ execute <<-SQL
30
+ SELECT
31
+ pid || ':' || COALESCE(query_start, xact_start) AS id,
32
+ query,
33
+ EXTRACT(EPOCH FROM NOW() - COALESCE(query_start, xact_start)) * 1000.0 AS duration_ms
34
+ FROM
35
+ pg_stat_activity
36
+ WHERE
37
+ datname = current_database()
38
+ AND state = 'active'
39
+ AND pid != pg_backend_pid()
40
+ ORDER BY
41
+ 1
42
+ SQL
43
+ end
44
+
28
45
  def process_queries(queries)
29
46
  # reset hypothetical indexes
30
47
  reset_hypothetical_indexes
@@ -166,7 +183,7 @@ module Dexter
166
183
  # Pass format to prevent ANALYZE
167
184
  puts execute("EXPLAIN (FORMAT TEXT) #{safe_statement(query.statement)}").map { |r| r["QUERY PLAN"] }.join("\n")
168
185
  end
169
- rescue PG::Error => e
186
+ rescue PG::Error, JSON::NestingError => e
170
187
  if @log_explain
171
188
  log e.message
172
189
  end
@@ -479,6 +496,9 @@ module Dexter
479
496
 
480
497
  def conn
481
498
  @conn ||= begin
499
+ # set connect timeout if none set
500
+ ENV["PGCONNECT_TIMEOUT"] ||= "2"
501
+
482
502
  if @options[:dbname] =~ /\Apostgres(ql)?:\/\//
483
503
  config = @options[:dbname]
484
504
  else
@@ -486,7 +506,7 @@ module Dexter
486
506
  host: @options[:host],
487
507
  port: @options[:port],
488
508
  dbname: @options[:dbname],
489
- user: @options[:user]
509
+ user: @options[:username]
490
510
  }.reject { |_, value| value.to_s.empty? }
491
511
  config = config[:dbname] if config.keys == [:dbname] && config[:dbname].include?("=")
492
512
  end
@@ -511,7 +531,7 @@ module Dexter
511
531
 
512
532
  def plan(query)
513
533
  # strip semi-colons as another measure of defense
514
- JSON.parse(execute("EXPLAIN (FORMAT JSON) #{safe_statement(query)}").first["QUERY PLAN"]).first["Plan"]
534
+ JSON.parse(execute("EXPLAIN (FORMAT JSON) #{safe_statement(query)}").first["QUERY PLAN"], max_nesting: 1000).first["Plan"]
515
535
  end
516
536
 
517
537
  # TODO for multicolumn indexes, use ordering
@@ -0,0 +1,25 @@
1
+ module Dexter
2
+ class PgStatActivityParser < LogParser
3
+ def perform
4
+ queries = {}
5
+
6
+ loop do
7
+ new_queries = {}
8
+ @logfile.stat_activity.each do |row|
9
+ new_queries[row["id"]] = row
10
+ end
11
+
12
+ # store queries after they complete
13
+ queries.each do |id, row|
14
+ unless new_queries[id]
15
+ process_entry(row["query"], row["duration_ms"].to_f)
16
+ end
17
+ end
18
+
19
+ queries = new_queries
20
+
21
+ sleep(5)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -6,15 +6,17 @@ module Dexter
6
6
  @logfile = logfile
7
7
 
8
8
  @collector = Collector.new(min_time: options[:min_time], min_calls: options[:min_calls])
9
+ @indexer = Indexer.new(options)
10
+
9
11
  @log_parser =
10
- if options[:input_format] == "csv"
12
+ if @logfile == :pg_stat_activity
13
+ PgStatActivityParser.new(@indexer, @collector)
14
+ elsif options[:input_format] == "csv"
11
15
  CsvLogParser.new(logfile, @collector)
12
16
  else
13
17
  LogParser.new(logfile, @collector)
14
18
  end
15
19
 
16
- @indexer = Indexer.new(options)
17
-
18
20
  @starting_interval = 3
19
21
  @interval = options[:interval]
20
22
 
@@ -25,7 +27,7 @@ module Dexter
25
27
  end
26
28
 
27
29
  def perform
28
- if @logfile == STDIN
30
+ if [STDIN, :pg_stat_activity].include?(@logfile)
29
31
  Thread.abort_on_exception = true
30
32
  Thread.new do
31
33
  sleep(@starting_interval)
@@ -1,3 +1,3 @@
1
1
  module Dexter
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgdexter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-23 00:00:00.000000000 Z
11
+ date: 2018-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop
@@ -119,6 +119,7 @@ files:
119
119
  - lib/dexter/indexer.rb
120
120
  - lib/dexter/log_parser.rb
121
121
  - lib/dexter/logging.rb
122
+ - lib/dexter/pg_stat_activity_parser.rb
122
123
  - lib/dexter/processor.rb
123
124
  - lib/dexter/query.rb
124
125
  - lib/dexter/version.rb
@@ -142,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
143
  version: '0'
143
144
  requirements: []
144
145
  rubyforge_project:
145
- rubygems_version: 2.6.13
146
+ rubygems_version: 2.7.6
146
147
  signing_key:
147
148
  specification_version: 4
148
149
  summary: The automatic indexer for Postgres