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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +26 -9
- data/guides/Hosted-Postgres.md +102 -0
- data/lib/dexter/client.rb +20 -15
- data/lib/dexter/indexer.rb +15 -13
- data/lib/dexter/log_parser.rb +2 -10
- data/lib/dexter/logging.rb +1 -1
- data/lib/dexter/processor.rb +7 -3
- data/lib/dexter/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c513808e2cdd9690c477c30548979fad122575a4
|
4
|
+
data.tar.gz: 6f4c605a0b68baa0275a523155b7be4ea9bc4d56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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-
|
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
|
67
|
+
## Connection Options
|
67
68
|
|
68
|
-
|
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
|
-
|
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
|
-
##
|
97
|
+
## Non-Streaming Modes
|
91
98
|
|
92
99
|
You can pass a single statement with:
|
93
100
|
|
94
101
|
```sh
|
95
|
-
dexter <connection-
|
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(
|
15
|
+
Indexer.new(options).process_queries([query])
|
16
16
|
elsif options[:pg_stat_statements]
|
17
|
-
Indexer.new(
|
18
|
-
elsif arguments
|
19
|
-
|
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(
|
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
|
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 "
|
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
|
-
|
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
|
-
|
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,
|
67
|
+
[arguments, options]
|
63
68
|
rescue Slop::Error => e
|
64
69
|
abort e.message
|
65
70
|
end
|
data/lib/dexter/indexer.rb
CHANGED
@@ -2,8 +2,7 @@ module Dexter
|
|
2
2
|
class Indexer
|
3
3
|
include Logging
|
4
4
|
|
5
|
-
def initialize(
|
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
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
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
|
327
|
+
rescue PG::ConnectionBad => e
|
328
|
+
abort e.message
|
327
329
|
end
|
328
330
|
|
329
331
|
def execute(query)
|
data/lib/dexter/log_parser.rb
CHANGED
@@ -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
|
-
|
39
|
-
|
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
|
|
data/lib/dexter/logging.rb
CHANGED
data/lib/dexter/processor.rb
CHANGED
@@ -2,12 +2,12 @@ module Dexter
|
|
2
2
|
class Processor
|
3
3
|
include Logging
|
4
4
|
|
5
|
-
def initialize(
|
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(
|
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
|
-
|
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
|
data/lib/dexter/version.rb
CHANGED
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.
|
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-
|
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
|