sensu-plugins-postgres-mrtrotl 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +277 -0
- data/LICENSE +22 -0
- data/README.md +125 -0
- data/bin/check-postgres-alive.rb +94 -0
- data/bin/check-postgres-connections.rb +142 -0
- data/bin/check-postgres-query.rb +142 -0
- data/bin/check-postgres-replication.rb +160 -0
- data/bin/metric-postgres-connections.rb +130 -0
- data/bin/metric-postgres-dbsize.rb +105 -0
- data/bin/metric-postgres-graphite.rb +140 -0
- data/bin/metric-postgres-locks.rb +114 -0
- data/bin/metric-postgres-relation-size.rb +119 -0
- data/bin/metric-postgres-statsbgwriter.rb +113 -0
- data/bin/metric-postgres-statsdb.rb +124 -0
- data/bin/metric-postgres-statsio.rb +122 -0
- data/bin/metric-postgres-statstable.rb +124 -0
- data/bin/metric-postgres-vaccum.rb +125 -0
- data/bin/metrics-postgres-query.rb +132 -0
- data/lib/sensu-plugins-postgres/pgpass.rb +27 -0
- data/lib/sensu-plugins-postgres/pgutil.rb +15 -0
- data/lib/sensu-plugins-postgres/version.rb +11 -0
- data/lib/sensu-plugins-postgres.rb +4 -0
- metadata +330 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
#
|
5
|
+
# metric-postgres-statstable
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
#
|
9
|
+
# This plugin collects postgres database metrics from the pg_stat tables
|
10
|
+
#
|
11
|
+
# OUTPUT:
|
12
|
+
# metric data
|
13
|
+
#
|
14
|
+
# PLATFORMS:
|
15
|
+
# Linux
|
16
|
+
#
|
17
|
+
# DEPENDENCIES:
|
18
|
+
# gem: sensu-plugin
|
19
|
+
# gem: pg
|
20
|
+
#
|
21
|
+
# USAGE:
|
22
|
+
# ./metric-postgres-statstable.rb -u db_user -p db_pass -h db_host -d db -s scope
|
23
|
+
#
|
24
|
+
# NOTES:
|
25
|
+
# Requires PSQL `track_counts` enabled
|
26
|
+
#
|
27
|
+
# LICENSE:
|
28
|
+
# Copyright (c) 2012 Kwarter, Inc <platforms@kwarter.com>
|
29
|
+
# Author Gilles Devaux <gilles.devaux@gmail.com>
|
30
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
31
|
+
# for details.
|
32
|
+
#
|
33
|
+
|
34
|
+
require 'sensu-plugins-postgres/pgpass'
|
35
|
+
require 'sensu-plugin/metric/cli'
|
36
|
+
require 'pg'
|
37
|
+
require 'socket'
|
38
|
+
|
39
|
+
class PostgresStatsTableMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
40
|
+
option :pgpass,
|
41
|
+
description: 'Pgpass file',
|
42
|
+
short: '-f FILE',
|
43
|
+
long: '--pgpass',
|
44
|
+
default: ENV['PGPASSFILE'] || "#{ENV['HOME']}/.pgpass"
|
45
|
+
|
46
|
+
option :user,
|
47
|
+
description: 'Postgres User',
|
48
|
+
short: '-u USER',
|
49
|
+
long: '--user USER'
|
50
|
+
|
51
|
+
option :password,
|
52
|
+
description: 'Postgres Password',
|
53
|
+
short: '-p PASS',
|
54
|
+
long: '--password PASS'
|
55
|
+
|
56
|
+
option :hostname,
|
57
|
+
description: 'Hostname to login to',
|
58
|
+
short: '-h HOST',
|
59
|
+
long: '--hostname HOST'
|
60
|
+
|
61
|
+
option :port,
|
62
|
+
description: 'Database port',
|
63
|
+
short: '-P PORT',
|
64
|
+
long: '--port PORT'
|
65
|
+
|
66
|
+
option :database,
|
67
|
+
description: 'Database name',
|
68
|
+
short: '-d DB',
|
69
|
+
long: '--db DB'
|
70
|
+
|
71
|
+
option :scope,
|
72
|
+
description: 'Scope, see http://www.postgresql.org/docs/9.2/static/monitoring-stats.html',
|
73
|
+
short: '-s SCOPE',
|
74
|
+
long: '--scope SCOPE',
|
75
|
+
default: 'user'
|
76
|
+
|
77
|
+
option :scheme,
|
78
|
+
description: 'Metric naming scheme, text to prepend to $queue_name.$metric',
|
79
|
+
long: '--scheme SCHEME',
|
80
|
+
default: "#{Socket.gethostname}.postgresql"
|
81
|
+
|
82
|
+
option :timeout,
|
83
|
+
description: 'Connection timeout (seconds)',
|
84
|
+
short: '-T TIMEOUT',
|
85
|
+
long: '--timeout TIMEOUT',
|
86
|
+
default: 10,
|
87
|
+
proc: proc(&:to_i)
|
88
|
+
|
89
|
+
include Pgpass
|
90
|
+
|
91
|
+
def run
|
92
|
+
timestamp = Time.now.to_i
|
93
|
+
pgpass
|
94
|
+
con = PG.connect(host: config[:hostname],
|
95
|
+
dbname: config[:database],
|
96
|
+
user: config[:user],
|
97
|
+
password: config[:password],
|
98
|
+
port: config[:port],
|
99
|
+
connect_timeout: config[:timeout])
|
100
|
+
request = [
|
101
|
+
'select sum(seq_scan) as seq_scan, sum(seq_tup_read) as seq_tup_read,',
|
102
|
+
'sum(idx_scan) as idx_scan, sum(idx_tup_fetch) as idx_tup_fetch,',
|
103
|
+
'sum(n_tup_ins) as n_tup_ins, sum(n_tup_upd) as n_tup_upd, sum(n_tup_del) as n_tup_del,',
|
104
|
+
'sum(n_tup_hot_upd) as n_tup_hot_upd, sum(n_live_tup) as n_live_tup, sum(n_dead_tup) as n_dead_tup',
|
105
|
+
"from pg_stat_#{config[:scope]}_tables"
|
106
|
+
]
|
107
|
+
con.exec(request.join(' ')) do |result|
|
108
|
+
result.each do |row|
|
109
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.seq_scan", row['seq_scan'], timestamp
|
110
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.seq_tup_read", row['seq_tup_read'], timestamp
|
111
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.idx_scan", row['idx_scan'], timestamp
|
112
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.idx_tup_fetch", row['idx_tup_fetch'], timestamp
|
113
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.n_tup_ins", row['n_tup_ins'], timestamp
|
114
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.n_tup_upd", row['n_tup_upd'], timestamp
|
115
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.n_tup_del", row['n_tup_del'], timestamp
|
116
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.n_tup_hot_upd", row['n_tup_hot_upd'], timestamp
|
117
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.n_live_tup", row['n_live_tup'], timestamp
|
118
|
+
output "#{config[:scheme]}.statstable.#{config[:database]}.n_dead_tup", row['n_dead_tup'], timestamp
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
ok
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# DEPENDENCIES:
|
5
|
+
# gem: sensu-plugin
|
6
|
+
# gem: pg
|
7
|
+
#
|
8
|
+
# USAGE:
|
9
|
+
# ./metric-postgres-vaccum.rb -u db_user -p db_pass -h db_host -d db
|
10
|
+
#
|
11
|
+
# NOTES:
|
12
|
+
# Requires PSQL `track_counts` `track_io_timing` for some metrics enabled
|
13
|
+
#
|
14
|
+
# LICENSE:
|
15
|
+
# Copyright (c) 2020 Airbrake Technologies, Inc <support@airbrake.io>
|
16
|
+
# Author Patrick Humpal <patrick@netvilla.net>
|
17
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
18
|
+
# for details.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'sensu-plugins-postgres/pgpass'
|
22
|
+
require 'sensu-plugin/metric/cli'
|
23
|
+
require 'pg'
|
24
|
+
require 'socket'
|
25
|
+
|
26
|
+
class PostgresVacuumDBMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
27
|
+
option :pgpass,
|
28
|
+
description: 'Pgpass file',
|
29
|
+
short: '-f FILE',
|
30
|
+
long: '--pgpass',
|
31
|
+
default: ENV['PGPASSFILE'] || "#{ENV['HOME']}/.pgpass"
|
32
|
+
|
33
|
+
option :user,
|
34
|
+
description: 'Postgres User',
|
35
|
+
short: '-u USER',
|
36
|
+
long: '--user USER'
|
37
|
+
|
38
|
+
option :password,
|
39
|
+
description: 'Postgres Password',
|
40
|
+
short: '-p PASS',
|
41
|
+
long: '--password PASS'
|
42
|
+
|
43
|
+
option :hostname,
|
44
|
+
description: 'Hostname to login to',
|
45
|
+
short: '-h HOST',
|
46
|
+
long: '--hostname HOST'
|
47
|
+
|
48
|
+
option :port,
|
49
|
+
description: 'Database port',
|
50
|
+
short: '-P PORT',
|
51
|
+
long: '--port PORT'
|
52
|
+
|
53
|
+
option :database,
|
54
|
+
description: 'Database to connect on',
|
55
|
+
short: '-d DB',
|
56
|
+
long: '--db DB',
|
57
|
+
default: 'postgres'
|
58
|
+
|
59
|
+
option :all_databases,
|
60
|
+
description: 'Get stats for all available databases',
|
61
|
+
short: '-a',
|
62
|
+
long: '--all-databases',
|
63
|
+
boolean: true,
|
64
|
+
default: false
|
65
|
+
|
66
|
+
option :scheme,
|
67
|
+
description: 'Metric naming scheme, text to prepend to $queue_name.$metric',
|
68
|
+
long: '--scheme SCHEME',
|
69
|
+
default: "#{Socket.gethostname}.postgresql"
|
70
|
+
|
71
|
+
option :timeout,
|
72
|
+
description: 'Connection timeout (seconds)',
|
73
|
+
short: '-T TIMEOUT',
|
74
|
+
long: '--timeout TIMEOUT',
|
75
|
+
default: 10,
|
76
|
+
proc: proc(&:to_i)
|
77
|
+
|
78
|
+
include Pgpass
|
79
|
+
|
80
|
+
def phase_mapping(vacuum_phase)
|
81
|
+
['initializing',
|
82
|
+
'scanning heap',
|
83
|
+
'vacuuming indexes',
|
84
|
+
'vacuuming heap',
|
85
|
+
'cleaning up indexes',
|
86
|
+
'truncating heap',
|
87
|
+
'performing final cleanup'].find_index(vacuum_phase)
|
88
|
+
end
|
89
|
+
|
90
|
+
def run
|
91
|
+
timestamp = Time.now.to_i
|
92
|
+
pgpass
|
93
|
+
con = PG.connect(host: config[:hostname],
|
94
|
+
dbname: config[:database],
|
95
|
+
user: config[:user],
|
96
|
+
password: config[:password],
|
97
|
+
port: config[:port],
|
98
|
+
connect_timeout: config[:timeout])
|
99
|
+
|
100
|
+
query = 'SELECT * FROM pg_stat_progress_vacuum'
|
101
|
+
params = []
|
102
|
+
unless config[:all_databases]
|
103
|
+
query += ' WHERE datname = $1'
|
104
|
+
params.push config[:database]
|
105
|
+
end
|
106
|
+
|
107
|
+
con.exec_params(query, params) do |result|
|
108
|
+
result.each do |row|
|
109
|
+
database = row['datname']
|
110
|
+
|
111
|
+
row.each do |key, value|
|
112
|
+
next if %w[datid datname].include?(key)
|
113
|
+
|
114
|
+
if key == 'phase'
|
115
|
+
output "#{config[:scheme]}.vacuum.#{database}.phase", phase_mapping(value).to_s, timestamp
|
116
|
+
else
|
117
|
+
output "#{config[:scheme]}.vacuum.#{database}.#{key}", value.to_s, timestamp
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
ok
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
#
|
5
|
+
# metrics-postgres-query
|
6
|
+
#
|
7
|
+
# DESCRIPTION:
|
8
|
+
# This plugin collects metrics from the results of a postgres query. Can optionally
|
9
|
+
# count the number of tuples (rows) returned by the query.
|
10
|
+
#
|
11
|
+
# OUTPUT:
|
12
|
+
# metric data
|
13
|
+
#
|
14
|
+
# PLATFORMS:
|
15
|
+
# Linux
|
16
|
+
#
|
17
|
+
# DEPENDENCIES:
|
18
|
+
# gem: pg
|
19
|
+
# gem: sensu-plugin
|
20
|
+
#
|
21
|
+
# USAGE:
|
22
|
+
# metrics-postgres-query.rb -u db_user -p db_pass -h db_server -d db -q 'select foo from bar'
|
23
|
+
#
|
24
|
+
# NOTES:
|
25
|
+
#
|
26
|
+
# LICENSE:
|
27
|
+
# Copyright 2015, Eric Heydrick <eheydrick@gmail.com>
|
28
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
29
|
+
# for details.
|
30
|
+
#
|
31
|
+
|
32
|
+
require 'sensu-plugins-postgres/pgpass'
|
33
|
+
require 'sensu-plugin/metric/cli'
|
34
|
+
require 'pg'
|
35
|
+
|
36
|
+
class MetricsPostgresQuery < Sensu::Plugin::Metric::CLI::Graphite
|
37
|
+
option :pgpass,
|
38
|
+
description: 'Pgpass file',
|
39
|
+
short: '-f FILE',
|
40
|
+
long: '--pgpass',
|
41
|
+
default: ENV['PGPASSFILE'] || "#{ENV['HOME']}/.pgpass"
|
42
|
+
|
43
|
+
option :user,
|
44
|
+
description: 'Postgres User',
|
45
|
+
short: '-u USER',
|
46
|
+
long: '--user USER'
|
47
|
+
|
48
|
+
option :password,
|
49
|
+
description: 'Postgres Password',
|
50
|
+
short: '-p PASS',
|
51
|
+
long: '--password PASS'
|
52
|
+
|
53
|
+
option :hostname,
|
54
|
+
description: 'Hostname to login to',
|
55
|
+
short: '-h HOST',
|
56
|
+
long: '--hostname HOST'
|
57
|
+
|
58
|
+
option :port,
|
59
|
+
description: 'Database port',
|
60
|
+
short: '-P PORT',
|
61
|
+
long: '--port PORT'
|
62
|
+
|
63
|
+
option :database,
|
64
|
+
description: 'Database name',
|
65
|
+
short: '-d DB',
|
66
|
+
long: '--db DB'
|
67
|
+
|
68
|
+
option :query,
|
69
|
+
description: 'Database query to execute',
|
70
|
+
short: '-q QUERY',
|
71
|
+
long: '--query QUERY',
|
72
|
+
required: true
|
73
|
+
|
74
|
+
option :count_tuples,
|
75
|
+
description: 'Count the number of tuples (rows) returned by the query',
|
76
|
+
short: '-t',
|
77
|
+
long: '--tuples',
|
78
|
+
boolean: true,
|
79
|
+
default: false
|
80
|
+
|
81
|
+
option :scheme,
|
82
|
+
description: 'Metric naming scheme, text to prepend to metric',
|
83
|
+
short: '-s SCHEME',
|
84
|
+
long: '--scheme SCHEME',
|
85
|
+
default: 'postgres'
|
86
|
+
|
87
|
+
option :multirow,
|
88
|
+
description: 'Determines if we return first row or all rows',
|
89
|
+
short: '-m',
|
90
|
+
long: '--multirow',
|
91
|
+
boolean: true,
|
92
|
+
default: false
|
93
|
+
|
94
|
+
option :timeout,
|
95
|
+
description: 'Connection timeout (seconds)',
|
96
|
+
short: '-T TIMEOUT',
|
97
|
+
long: '--timeout TIMEOUT',
|
98
|
+
default: 10,
|
99
|
+
proc: proc(&:to_i)
|
100
|
+
|
101
|
+
include Pgpass
|
102
|
+
|
103
|
+
def run
|
104
|
+
begin
|
105
|
+
pgpass
|
106
|
+
con = PG.connect(host: config[:hostname],
|
107
|
+
dbname: config[:database],
|
108
|
+
user: config[:user],
|
109
|
+
password: config[:password],
|
110
|
+
port: config[:port],
|
111
|
+
connect_timeout: config[:timeout])
|
112
|
+
res = con.exec(config[:query].to_s)
|
113
|
+
rescue PG::Error => e
|
114
|
+
unknown "Unable to query PostgreSQL: #{e.message}"
|
115
|
+
end
|
116
|
+
|
117
|
+
value = if config[:count_tuples]
|
118
|
+
res.ntuples
|
119
|
+
else
|
120
|
+
res.first&.values&.first
|
121
|
+
end
|
122
|
+
|
123
|
+
if config[:multirow] && !config[:count_tuples]
|
124
|
+
res.values.each do |row|
|
125
|
+
output "#{config[:scheme]}.#{row[0]}", row[1]
|
126
|
+
end
|
127
|
+
else
|
128
|
+
output config[:scheme], value
|
129
|
+
end
|
130
|
+
ok
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pgpass
|
4
|
+
def read_pgpass(pg_pass_file)
|
5
|
+
File.readlines(pg_pass_file).each do |line|
|
6
|
+
return line.strip.split(':') unless line.start_with?('#')
|
7
|
+
|
8
|
+
next
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def pgpass
|
13
|
+
if File.file?(config[:pgpass])
|
14
|
+
pgpass = Hash[%i[hostname port database user password].zip(read_pgpass(config[:pgpass]))]
|
15
|
+
pgpass[:database] = nil if pgpass[:database] == '*'
|
16
|
+
pgpass.each do |k, v|
|
17
|
+
config[k] ||= v
|
18
|
+
end
|
19
|
+
else
|
20
|
+
config[:hostname] ||= ENV['PGHOST'] || 'localhost'
|
21
|
+
config[:port] ||= ENV['PGPORT'] || 5432
|
22
|
+
config[:database] ||= ENV['PGDATABASE'] || 'postgres'
|
23
|
+
config[:user] ||= ENV['PGUSER'] || 'postgres'
|
24
|
+
config[:password] ||= ENV['PGPASSWORD']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgUtil
|
4
|
+
def check_vsn_newer_than_postgres9(conn)
|
5
|
+
pg_vsn = conn.exec("SELECT current_setting('server_version')").getvalue(0, 0)
|
6
|
+
pg_vsn = pg_vsn.split(' ')[0]
|
7
|
+
Gem::Version.new(pg_vsn) < Gem::Version.new('10.0') && Gem::Version.new(pg_vsn) >= Gem::Version.new('9.0')
|
8
|
+
end
|
9
|
+
|
10
|
+
def compute_lag(master, slave, m_segbytes)
|
11
|
+
m_segment, m_offset = master.split('/')
|
12
|
+
s_segment, s_offset = slave.split('/')
|
13
|
+
((m_segment.hex - s_segment.hex) * m_segbytes) + (m_offset.hex - s_offset.hex)
|
14
|
+
end
|
15
|
+
end
|