pgdexter 0.1.6 → 0.2.0

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
2
  SHA1:
3
- metadata.gz: 496685bbacfac7387182be3ebda3515a492723cc
4
- data.tar.gz: b99548fccab8337b9ff5765a6182472abba9bb06
3
+ metadata.gz: c513808e2cdd9690c477c30548979fad122575a4
4
+ data.tar.gz: 6f4c605a0b68baa0275a523155b7be4ea9bc4d56
5
5
  SHA512:
6
- metadata.gz: 3f9b30e7355c26cf7084b8deee9735206da484cd9f4725a5c1f751db5808dc32d66954341c5be3ba46cd783fa2e360e2b9c32ab0667aa2372213ebca695b29ff
7
- data.tar.gz: 41346b8ed9906e24c68847c26bc9ffe54176eb0e74dc771138ec266ebccfca3e0d18ebd37223b73f1f2b8a9f512320502e4ad9597982bc253846881ea7e93e8d
6
+ metadata.gz: 3b38a53e96516a485394f3ec594ee0418c1a7ab94fe8726b3228cc5443843dd7f7ba2bd1fe4bb0cc5c4dbd877bd9b9b036d5bfd5b4cda275dc7176dbdf9da82c
7
+ data.tar.gz: cbe64d0cf9a40b96bf2644a80519bb837d235d6956ca9b61b24533867130958c95932ffbf4d69672218a10628c32b87a1f1e87f86a4968577f1629fc871ef440
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 0.2.0
2
+
3
+ - Added same connection options as `psql`
4
+ - Added support for multiple files
5
+ - Added `error` log level
6
+ - Better error messages when cannot connect
7
+
8
+ Breaking
9
+
10
+ - `-h` option changed to `--host` instead of `--help` for consistency with `psql`
11
+
1
12
  ## 0.1.6
2
13
 
3
14
  - Significant performance improvements
data/README.md CHANGED
@@ -11,7 +11,8 @@ The automatic indexer for Postgres
11
11
  First, install [HypoPG](https://github.com/dalibo/hypopg) on your database server. This doesn’t require a restart.
12
12
 
13
13
  ```sh
14
- curl -L https://github.com/dalibo/hypopg/archive/1.0.0.tar.gz | tar -x
14
+ cd /tmp
15
+ curl -L https://github.com/dalibo/hypopg/archive/1.0.0.tar.gz | tar xz
15
16
  cd hypopg-1.0.0
16
17
  make
17
18
  make install # may need sudo
@@ -38,7 +39,7 @@ The command line tool is also available as a [Linux package](guides/Linux.md).
38
39
  Dexter needs a connection to your database and a log file to process.
39
40
 
40
41
  ```sh
41
- tail -F -n +1 <log-file> | dexter <connection-string>
42
+ tail -F -n +1 <log-file> | dexter <connection-options>
42
43
  ```
43
44
 
44
45
  This finds slow queries and generates output like:
@@ -63,18 +64,24 @@ To be safe, Dexter will not create indexes unless you pass the `--create` flag.
63
64
  2017-06-25T17:52:37+00:00 Index created: 15243 ms
64
65
  ```
65
66
 
66
- ## Connection String
67
+ ## Connection Options
67
68
 
68
- The connection string is a URI with the format:
69
+ Dexter supports the same connection options as psql.
70
+
71
+ ```
72
+ -h host -U user -p 5432 -d dbname
73
+ ```
74
+
75
+ This includes URIs:
69
76
 
70
77
  ```
71
78
  postgresql://user:pass@host:5432/dbname
72
79
  ```
73
80
 
74
- To connect through a socket, just pass the database name.
81
+ and connection strings:
75
82
 
76
83
  ```
77
- dbname
84
+ host=localhost port=5432 dbname=mydb
78
85
  ```
79
86
 
80
87
  ## Options
@@ -83,16 +90,22 @@ Name | Description | Default
83
90
  --- | --- | ---
84
91
  exclude | prevent specific tables from being indexed | None
85
92
  interval | time to wait between processing queries, in seconds | 60
86
- log-level | `debug` gives additional info for suggested indexes<br />`debug2` gives additional info for processed queries | info
93
+ log-level | `debug` gives additional info for suggested indexes<br />`debug2` gives additional info for processed queries<br />`error` suppresses logging | info
87
94
  log-sql | log SQL statements executed | false
88
95
  min-time | only process queries consuming a min amount of DB time, in minutes | 0
89
96
 
90
- ## Single Statement Mode
97
+ ## Non-Streaming Modes
91
98
 
92
99
  You can pass a single statement with:
93
100
 
94
101
  ```sh
95
- dexter <connection-string> -s "SELECT * FROM ..."
102
+ dexter <connection-options> -s "SELECT * FROM ..."
103
+ ```
104
+
105
+ or files with:
106
+
107
+ ```sh
108
+ dexter <connection-options> <file1> <file2>
96
109
  ```
97
110
 
98
111
  ## Examples
@@ -109,6 +122,10 @@ Homebrew on Mac
109
122
  tail -F -n +1 /usr/local/var/postgres/server.log | dexter dbname
110
123
  ```
111
124
 
125
+ ## Hosted Postgres
126
+
127
+ Some hosted providers like Amazon RDS and Heroku do not support the HypoPG extension, which Dexter needs to run. See [how to use Dexter](guides/Hosted-Postgres.md) in these cases.
128
+
112
129
  ## Future Work
113
130
 
114
131
  [Here are some ideas](https://github.com/ankane/dexter/issues/1)
@@ -0,0 +1,102 @@
1
+ # Hosted Postgres
2
+
3
+ Some hosted providers like Amazon RDS and Heroku do not support the HypoPG extension, which Dexter needs to run. Hopefully this will change with time. For now, we can spin up a separate database instance to run Dexter. It’s not super convenient, but can be useful to do from time to time.
4
+
5
+ ### Install Postgres and Ruby
6
+
7
+ Linux
8
+
9
+ ```sh
10
+ sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
11
+ sudo apt-get install wget ca-certificates
12
+ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
13
+ sudo apt-get update
14
+ sudo apt-get install postgresql-9.6 postgresql-server-dev-9.6
15
+ sudo -u postgres createuser $(whoami) -s
16
+ sudo apt-get install ruby2.2 ruby2.2-dev
17
+ ```
18
+
19
+ Mac
20
+
21
+ ```sh
22
+ brew install postgresql
23
+ brew install ruby
24
+ ```
25
+
26
+ ### Install HypoPG and Dexter
27
+
28
+ HypoPG
29
+
30
+ ```sh
31
+ cd /tmp
32
+ curl -L https://github.com/dalibo/hypopg/archive/1.0.0.tar.gz | tar xz
33
+ cd hypopg-1.0.0
34
+ make
35
+ make install # may need sudo
36
+ ```
37
+
38
+ Dexter
39
+
40
+ ```sh
41
+ gem install pgdexter # may need sudo
42
+ ```
43
+
44
+ ### Download logs
45
+
46
+ #### Amazon RDS
47
+
48
+ Create an IAM user with the policy below:
49
+
50
+ ```
51
+ {
52
+ "Statement": [
53
+ {
54
+ "Action": [
55
+ "rds:DescribeDBLogFiles",
56
+ "rds:DownloadDBLogFilePortion"
57
+ ],
58
+ "Effect": "Allow",
59
+ "Resource": "*"
60
+ }
61
+ ]
62
+ }
63
+ ```
64
+
65
+ And run:
66
+
67
+ ```sh
68
+ aws configure
69
+ gem install pghero_logs # may need sudo
70
+ pghero_logs download <instance-id>
71
+ ```
72
+
73
+ #### Heroku
74
+
75
+ Production-tier databases only
76
+
77
+ ```sh
78
+ heroku logs -p postgres > postgresql.log
79
+ ```
80
+
81
+ ### Dump and restore
82
+
83
+ We recommend creating a new instance from a snapshot for the dump to avoid affecting customers.
84
+
85
+ ```sh
86
+ pg_dump -v -j 8 -Fd -f /tmp/newout.dir <connection-string>
87
+ ```
88
+
89
+ Then shutdown the dump instance. Restore with:
90
+
91
+ ```sh
92
+ createdb dexter_restore
93
+ pg_restore -v -j 8 -x -O --format=d -d dexter_restore /tmp/newout.dir/
94
+ ```
95
+
96
+ ### Run Dexter
97
+
98
+ ```sh
99
+ dexter dexter_restore postgresql.log*
100
+ ```
101
+
102
+ :tada:
data/lib/dexter/client.rb CHANGED
@@ -12,20 +12,21 @@ module Dexter
12
12
 
13
13
  if options[:statement]
14
14
  query = Query.new(options[:statement])
15
- Indexer.new(arguments[0], options).process_queries([query])
15
+ Indexer.new(options).process_queries([query])
16
16
  elsif options[:pg_stat_statements]
17
- Indexer.new(arguments[0], options).process_stat_statements
18
- elsif arguments[1]
19
- Processor.new(arguments[0], arguments[1], options).perform
17
+ Indexer.new(options).process_stat_statements
18
+ elsif arguments.any?
19
+ ARGV.replace(arguments)
20
+ Processor.new(ARGF, options).perform
20
21
  else
21
- Processor.new(arguments[0], STDIN, options).perform
22
+ Processor.new(STDIN, options).perform
22
23
  end
23
24
  end
24
25
 
25
26
  def parse_args(args)
26
27
  opts = Slop.parse(args) do |o|
27
28
  o.banner = %(Usage:
28
- dexter <database-url> [options]
29
+ dexter [options]
29
30
 
30
31
  Options:)
31
32
  o.boolean "--create", "create indexes", default: false
@@ -38,28 +39,32 @@ Options:)
38
39
  o.string "--log-level", "log level", default: "info"
39
40
  o.boolean "--log-sql", "log sql", default: false
40
41
  o.string "-s", "--statement", "process a single statement"
42
+ o.separator ""
43
+ o.separator "Connection options:"
41
44
  o.on "-v", "--version", "print the version" do
42
45
  log Dexter::VERSION
43
46
  exit
44
47
  end
45
- o.on "-h", "--help", "prints help" do
48
+ o.on "--help", "prints help" do
46
49
  log o
47
50
  exit
48
51
  end
52
+ o.string "-U", "--username"
53
+ o.string "-d", "--dbname"
54
+ o.string "-h", "--host"
55
+ o.integer "-p", "--port"
49
56
  end
50
57
 
51
58
  arguments = opts.arguments
59
+ options = opts.to_hash
52
60
 
53
- if arguments.empty?
54
- log opts
55
- exit
56
- end
57
-
58
- abort "Too many arguments" if arguments.size > 2
61
+ options[:dbname] = arguments.shift unless options[:dbname]
59
62
 
60
- abort "Unknown log level" unless ["info", "debug", "debug2"].include?(opts.to_hash[:log_level].to_s.downcase)
63
+ # TODO don't use global var
64
+ $log_level = options[:log_level].to_s.downcase
65
+ abort "Unknown log level" unless ["error", "info", "debug", "debug2"].include?($log_level)
61
66
 
62
- [arguments, opts.to_hash]
67
+ [arguments, options]
63
68
  rescue Slop::Error => e
64
69
  abort e.message
65
70
  end
@@ -2,8 +2,7 @@ module Dexter
2
2
  class Indexer
3
3
  include Logging
4
4
 
5
- def initialize(database_url, options)
6
- @database_url = database_url
5
+ def initialize(options)
7
6
  @create = options[:create]
8
7
  @log_level = options[:log_level]
9
8
  @exclude_tables = options[:exclude]
@@ -11,6 +10,7 @@ module Dexter
11
10
  @log_sql = options[:log_sql]
12
11
  @log_explain = options[:log_explain]
13
12
  @min_time = options[:min_time] || 0
13
+ @options = options
14
14
 
15
15
  create_extension unless extension_exists?
16
16
  execute("SET lock_timeout = '5s'")
@@ -311,19 +311,21 @@ module Dexter
311
311
 
312
312
  def conn
313
313
  @conn ||= begin
314
- uri = URI.parse(@database_url)
315
- config = {
316
- host: uri.host,
317
- port: uri.port,
318
- dbname: uri.path.sub(/\A\//, ""),
319
- user: uri.user,
320
- password: uri.password,
321
- connect_timeout: 3
322
- }.reject { |_, value| value.to_s.empty? }
314
+ if @options[:dbname] =~ /\Apostgres(ql)?:\/\//
315
+ config = @options[:dbname]
316
+ else
317
+ config = {
318
+ host: @options[:host],
319
+ port: @options[:port],
320
+ dbname: @options[:dbname],
321
+ user: @options[:user]
322
+ }.reject { |_, value| value.to_s.empty? }
323
+ config = config[:dbname] if config.keys == [:dbname] && config[:dbname].include?("=")
324
+ end
323
325
  PG::Connection.new(config)
324
326
  end
325
- rescue PG::ConnectionBad
326
- abort "Can't connect to database"
327
+ rescue PG::ConnectionBad => e
328
+ abort e.message
327
329
  end
328
330
 
329
331
  def execute(query)
@@ -6,8 +6,6 @@ module Dexter
6
6
  def initialize(logfile, collector)
7
7
  @logfile = logfile
8
8
  @collector = collector
9
-
10
- abort "Log file not found" unless File.exist?(logfile)
11
9
  end
12
10
 
13
11
  def perform
@@ -35,14 +33,8 @@ module Dexter
35
33
  private
36
34
 
37
35
  def each_line
38
- if @logfile == STDIN
39
- STDIN.each_line do |line|
40
- yield line
41
- end
42
- else
43
- File.foreach(@logfile) do |line|
44
- yield line
45
- end
36
+ @logfile.each_line do |line|
37
+ yield line
46
38
  end
47
39
  end
48
40
 
@@ -1,7 +1,7 @@
1
1
  module Dexter
2
2
  module Logging
3
3
  def log(message)
4
- puts "#{Time.now.iso8601} #{message}"
4
+ puts "#{Time.now.iso8601} #{message}" unless $log_level == "error"
5
5
  end
6
6
  end
7
7
  end
@@ -2,12 +2,12 @@ module Dexter
2
2
  class Processor
3
3
  include Logging
4
4
 
5
- def initialize(database_url, logfile, options)
5
+ def initialize(logfile, options)
6
6
  @logfile = logfile
7
7
 
8
8
  @collector = Collector.new(min_time: options[:min_time])
9
9
  @log_parser = LogParser.new(logfile, @collector)
10
- @indexer = Indexer.new(database_url, options)
10
+ @indexer = Indexer.new(options)
11
11
 
12
12
  @starting_interval = 3
13
13
  @interval = options[:interval]
@@ -34,7 +34,11 @@ module Dexter
34
34
  end
35
35
  end
36
36
 
37
- @log_parser.perform
37
+ begin
38
+ @log_parser.perform
39
+ rescue Errno::ENOENT => e
40
+ abort e.message
41
+ end
38
42
 
39
43
  process_queries
40
44
  end
@@ -1,3 +1,3 @@
1
1
  module Dexter
2
- VERSION = "0.1.6"
2
+ VERSION = "0.2.0"
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.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-26 00:00:00.000000000 Z
11
+ date: 2017-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop
@@ -110,6 +110,7 @@ files:
110
110
  - README.md
111
111
  - Rakefile
112
112
  - exe/dexter
113
+ - guides/Hosted-Postgres.md
113
114
  - guides/Linux.md
114
115
  - lib/dexter.rb
115
116
  - lib/dexter/client.rb