diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d8db19..7e722ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). This CHANGELOG follows the format listed [here](https://github.com/sensu-plugins/community/blob/master/HOW_WE_CHANGELOG.md). ## [Unreleased] +### Changed +- On `bin/metric-*`: option `database (-d, --db)` now supports semicolon separated list of databases to fetch metrics of multiple databases at once. +### Breaking Changes +- On `bin/metric-*`: if no `database (-d, --db)` argument is supplied through the command line now metrics for all databases are returned. ## [4.0.0] - 2020-01-09 diff --git a/bin/metric-postgres-connections.rb b/bin/metric-postgres-connections.rb index 8a86976..fd33742 100755 --- a/bin/metric-postgres-connections.rb +++ b/bin/metric-postgres-connections.rb @@ -20,6 +20,7 @@ # # USAGE: # ./metric-postgres-connections.rb -u db_user -p db_pass -h db_host -d db +# ./metric-postgres-connections.rb -u db_user -p db_pass -h db_host -d 'db1,db2' # # NOTES: # @@ -31,6 +32,7 @@ # require 'sensu-plugins-postgres/pgpass' +require 'sensu-plugins-postgres/pgdatabases' require 'sensu-plugin/metric/cli' require 'pg' require 'socket' @@ -62,10 +64,11 @@ class PostgresStatsDBMetrics < Sensu::Plugin::Metric::CLI::Graphite short: '-P PORT', long: '--port PORT' - option :database, - description: 'Database name', + option :databases, + description: 'Database names, separated by ","', short: '-d DB', - long: '--db DB' + long: '--db DB', + default: nil option :scheme, description: 'Metric naming scheme, text to prepend to $queue_name.$metric', @@ -79,12 +82,14 @@ class PostgresStatsDBMetrics < Sensu::Plugin::Metric::CLI::Graphite default: nil include Pgpass + include Pgdatabases def run timestamp = Time.now.to_i pgpass + databases = pgdatabases con = PG.connect(host: config[:hostname], - dbname: config[:database], + dbname: databases.first, user: config[:user], password: config[:password], port: config[:port], @@ -98,30 +103,32 @@ def run ] wait_col = con.exec(request.join(' ')).first['wait_col'] - request = [ - "select count(*), #{wait_col} as waiting from pg_stat_activity", - "where datname = '#{config[:database]}' group by #{wait_col}" - ] - - metrics = { - active: 0, - waiting: 0, - total: 0 - } - con.exec(request.join(' ')) do |result| - result.each do |row| - if row['waiting'] == 't' - metrics[:waiting] = row['count'] - elsif row['waiting'] == 'f' - metrics[:active] = row['count'] + databases.each do |database| + request = [ + "select count(*), #{wait_col} as waiting from pg_stat_activity", + "where datname = '#{con.escape_string(database)}' group by #{wait_col}" + ] + + metrics = { + active: 0, + waiting: 0, + total: 0 + } + con.exec(request.join(' ')) do |result| + result.each do |row| + if row['waiting'] == 't' + metrics[:waiting] = row['count'] + elsif row['waiting'] == 'f' + metrics[:active] = row['count'] + end end end - end - metrics[:total] = (metrics[:waiting].to_i + metrics[:active].to_i) + metrics[:total] = (metrics[:waiting].to_i + metrics[:active].to_i) - metrics.each do |metric, value| - output "#{config[:scheme]}.connections.#{config[:database]}.#{metric}", value, timestamp + metrics.each do |metric, value| + output "#{config[:scheme]}.connections.#{database}.#{metric}", value, timestamp + end end ok diff --git a/bin/metric-postgres-dbsize.rb b/bin/metric-postgres-dbsize.rb index 18f38e8..db324b3 100755 --- a/bin/metric-postgres-dbsize.rb +++ b/bin/metric-postgres-dbsize.rb @@ -20,6 +20,7 @@ # # USAGE: # ./metric-postgres-dbsize.rb -u db_user -p db_pass -h db_host -d db +# ./metric-postgres-dbsize.rb -u db_user -p db_pass -h db_host -d 'db1,db2' # # NOTES: # @@ -31,6 +32,7 @@ # require 'sensu-plugins-postgres/pgpass' +require 'sensu-plugins-postgres/pgdatabases' require 'sensu-plugin/metric/cli' require 'pg' require 'socket' @@ -62,10 +64,11 @@ class PostgresStatsDBMetrics < Sensu::Plugin::Metric::CLI::Graphite short: '-P PORT', long: '--port PORT' - option :database, - description: 'Database name', + option :databases, + description: 'Database names, separated by ","', short: '-d DB', - long: '--db DB' + long: '--db DB', + default: nil option :scheme, description: 'Metric naming scheme, text to prepend to $queue_name.$metric', @@ -79,23 +82,24 @@ class PostgresStatsDBMetrics < Sensu::Plugin::Metric::CLI::Graphite default: nil include Pgpass + include Pgdatabases def run timestamp = Time.now.to_i pgpass + databases = pgdatabases con = PG.connect(host: config[:hostname], - dbname: config[:database], + dbname: databases.first, user: config[:user], password: config[:password], port: config[:port], connect_timeout: config[:timeout]) - request = [ - "select pg_database_size('#{config[:database]}')" - ] - con.exec(request.join(' ')) do |result| - result.each do |row| - output "#{config[:scheme]}.size.#{config[:database]}", row['pg_database_size'], timestamp + databases.each do |database| + con.exec_params('select pg_database_size($1)', [database]) do |result| + result.each do |row| + output "#{config[:scheme]}.size.#{database}", row['pg_database_size'], timestamp + end end end diff --git a/bin/metric-postgres-locks.rb b/bin/metric-postgres-locks.rb index 474ca53..dc1dd6d 100755 --- a/bin/metric-postgres-locks.rb +++ b/bin/metric-postgres-locks.rb @@ -20,6 +20,7 @@ # # USAGE: # ./metric-postgres-locks.rb -u db_user -p db_pass -h db_host -d db +# ./metric-postgres-locks.rb -u db_user -p db_pass -h db_host -d 'db1,db2' # # NOTES: # @@ -31,6 +32,7 @@ # require 'sensu-plugins-postgres/pgpass' +require 'sensu-plugins-postgres/pgdatabases' require 'sensu-plugin/metric/cli' require 'pg' require 'socket' @@ -62,10 +64,11 @@ class PostgresStatsDBMetrics < Sensu::Plugin::Metric::CLI::Graphite short: '-P PORT', long: '--port PORT' - option :database, - description: 'Database name', + option :databases, + description: 'Database names, separated by ","', short: '-d DB', - long: '--db DB' + long: '--db DB', + default: nil option :scheme, description: 'Metric naming scheme, text to prepend to $queue_name.$metric', @@ -79,33 +82,39 @@ class PostgresStatsDBMetrics < Sensu::Plugin::Metric::CLI::Graphite default: nil include Pgpass + include Pgdatabases def run timestamp = Time.now.to_i locks_per_type = Hash.new(0) pgpass + databases = pgdatabases + # connect only to first database and get information for all databases through SQL queries con = PG.connect(host: config[:hostname], - dbname: config[:database], + dbname: databases.first, user: config[:user], password: config[:password], port: config[:port], connect_timeout: config[:timeout]) - request = [ - 'SELECT mode, count(mode) AS count FROM pg_locks', - "WHERE database = (SELECT oid FROM pg_database WHERE datname = '#{config[:database]}')", - 'GROUP BY mode' - ] - - con.exec(request.join(' ')) do |result| - result.each do |row| - lock_name = row['mode'].downcase.to_sym - locks_per_type[lock_name] = row['count'] + + databases.each do |database| + request = [ + 'SELECT mode, count(mode) AS count FROM pg_locks', + 'WHERE database = (SELECT oid FROM pg_database WHERE datname = $1)', + 'GROUP BY mode' + ] + + con.exec_params(request.join(' '), [database]) do |result| + result.each do |row| + lock_name = row['mode'].downcase.to_sym + locks_per_type[lock_name] = row['count'] + end end - end - locks_per_type.each do |lock_type, count| - output "#{config[:scheme]}.locks.#{config[:database]}.#{lock_type}", count, timestamp + locks_per_type.each do |lock_type, count| + output "#{config[:scheme]}.locks.#{database}.#{lock_type}", count, timestamp + end end ok diff --git a/bin/metric-postgres-statsdb.rb b/bin/metric-postgres-statsdb.rb index 761a567..61d7ac2 100755 --- a/bin/metric-postgres-statsdb.rb +++ b/bin/metric-postgres-statsdb.rb @@ -20,6 +20,7 @@ # # USAGE: # ./metric-postgres-statsdb.rb -u db_user -p db_pass -h db_host -d db +# ./metric-postgres-statsdb.rb -u db_user -p db_pass -h db_host -d 'db1;db2;db3' # # NOTES: # Requires PSQL `track_counts` `track_io_timing` for some metrics enabled diff --git a/bin/metric-postgres-statsio.rb b/bin/metric-postgres-statsio.rb index 21ef815..b097d38 100755 --- a/bin/metric-postgres-statsio.rb +++ b/bin/metric-postgres-statsio.rb @@ -20,6 +20,7 @@ # # USAGE: # ./metric-postgres-statsio.rb -u db_user -p db_pass -h db_host -d db -s scope +# ./metric-postgres-statsio.rb -u db_user -p db_pass -h db_host -d 'db1,db2' -s scope # # NOTES: # Requires PSQL `track_io_timing` enabled @@ -32,6 +33,7 @@ # require 'sensu-plugins-postgres/pgpass' +require 'sensu-plugins-postgres/pgdatabases' require 'sensu-plugin/metric/cli' require 'pg' require 'socket' @@ -63,10 +65,11 @@ class PostgresStatsIOMetrics < Sensu::Plugin::Metric::CLI::Graphite short: '-P PORT', long: '--port PORT' - option :database, - description: 'Database name', + option :databases, + description: 'Database names, separated by ","', short: '-d DB', - long: '--db DB' + long: '--db DB', + default: nil option :scope, description: 'Scope, see http://www.postgresql.org/docs/9.2/static/monitoring-stats.html', @@ -86,12 +89,24 @@ class PostgresStatsIOMetrics < Sensu::Plugin::Metric::CLI::Graphite default: nil include Pgpass + include Pgdatabases def run - timestamp = Time.now.to_i pgpass + + pgdatabases.each do |database| + output_database(database) + end + + ok + end + + private + + def output_database(database) + timestamp = Time.now.to_i con = PG.connect(host: config[:hostname], - dbname: config[:database], + dbname: database, user: config[:user], password: config[:password], port: config[:port], @@ -105,17 +120,17 @@ def run ] con.exec(request.join(' ')) do |result| result.each do |row| - output "#{config[:scheme]}.statsio.#{config[:database]}.heap_blks_read", row['heap_blks_read'], timestamp - output "#{config[:scheme]}.statsio.#{config[:database]}.heap_blks_hit", row['heap_blks_hit'], timestamp - output "#{config[:scheme]}.statsio.#{config[:database]}.idx_blks_read", row['idx_blks_read'], timestamp - output "#{config[:scheme]}.statsio.#{config[:database]}.idx_blks_hit", row['idx_blks_hit'], timestamp - output "#{config[:scheme]}.statsio.#{config[:database]}.toast_blks_read", row['toast_blks_read'], timestamp - output "#{config[:scheme]}.statsio.#{config[:database]}.toast_blks_hit", row['toast_blks_hit'], timestamp - output "#{config[:scheme]}.statsio.#{config[:database]}.tidx_blks_read", row['tidx_blks_read'], timestamp - output "#{config[:scheme]}.statsio.#{config[:database]}.tidx_blks_hit", row['tidx_blks_hit'], timestamp + output "#{config[:scheme]}.statsio.#{database}.heap_blks_read", row['heap_blks_read'], timestamp + output "#{config[:scheme]}.statsio.#{database}.heap_blks_hit", row['heap_blks_hit'], timestamp + output "#{config[:scheme]}.statsio.#{database}.idx_blks_read", row['idx_blks_read'], timestamp + output "#{config[:scheme]}.statsio.#{database}.idx_blks_hit", row['idx_blks_hit'], timestamp + output "#{config[:scheme]}.statsio.#{database}.toast_blks_read", row['toast_blks_read'], timestamp + output "#{config[:scheme]}.statsio.#{database}.toast_blks_hit", row['toast_blks_hit'], timestamp + output "#{config[:scheme]}.statsio.#{database}.tidx_blks_read", row['tidx_blks_read'], timestamp + output "#{config[:scheme]}.statsio.#{database}.tidx_blks_hit", row['tidx_blks_hit'], timestamp end end - ok + con.close end end diff --git a/bin/metric-postgres-statstable.rb b/bin/metric-postgres-statstable.rb index a839d69..101810d 100755 --- a/bin/metric-postgres-statstable.rb +++ b/bin/metric-postgres-statstable.rb @@ -20,6 +20,7 @@ # # USAGE: # ./metric-postgres-statstable.rb -u db_user -p db_pass -h db_host -d db -s scope +# ./metric-postgres-statstable.rb -u db_user -p db_pass -h db_host -d 'db1,db2' -s scope # # NOTES: # Requires PSQL `track_counts` enabled @@ -32,6 +33,7 @@ # require 'sensu-plugins-postgres/pgpass' +require 'sensu-plugins-postgres/pgdatabases' require 'sensu-plugin/metric/cli' require 'pg' require 'socket' @@ -63,10 +65,11 @@ class PostgresStatsTableMetrics < Sensu::Plugin::Metric::CLI::Graphite short: '-P PORT', long: '--port PORT' - option :database, - description: 'Database name', + option :databases, + description: 'Database names, separated by ","', short: '-d DB', - long: '--db DB' + long: '--db DB', + default: nil option :scope, description: 'Scope, see http://www.postgresql.org/docs/9.2/static/monitoring-stats.html', @@ -86,12 +89,24 @@ class PostgresStatsTableMetrics < Sensu::Plugin::Metric::CLI::Graphite default: nil include Pgpass + include Pgdatabases def run - timestamp = Time.now.to_i pgpass + + pgdatabases.each do |database| + output_database(database) + end + + ok + end + + private + + def output_database(database) + timestamp = Time.now.to_i con = PG.connect(host: config[:hostname], - dbname: config[:database], + dbname: database, user: config[:user], password: config[:password], port: config[:port], @@ -105,19 +120,17 @@ def run ] con.exec(request.join(' ')) do |result| result.each do |row| - output "#{config[:scheme]}.statstable.#{config[:database]}.seq_scan", row['seq_scan'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.seq_tup_read", row['seq_tup_read'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.idx_scan", row['idx_scan'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.idx_tup_fetch", row['idx_tup_fetch'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.n_tup_ins", row['n_tup_ins'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.n_tup_upd", row['n_tup_upd'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.n_tup_del", row['n_tup_del'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.n_tup_hot_upd", row['n_tup_hot_upd'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.n_live_tup", row['n_live_tup'], timestamp - output "#{config[:scheme]}.statstable.#{config[:database]}.n_dead_tup", row['n_dead_tup'], timestamp + output "#{config[:scheme]}.statstable.#{database}.seq_scan", row['seq_scan'], timestamp + output "#{config[:scheme]}.statstable.#{database}.seq_tup_read", row['seq_tup_read'], timestamp + output "#{config[:scheme]}.statstable.#{database}.idx_scan", row['idx_scan'], timestamp + output "#{config[:scheme]}.statstable.#{database}.idx_tup_fetch", row['idx_tup_fetch'], timestamp + output "#{config[:scheme]}.statstable.#{database}.n_tup_ins", row['n_tup_ins'], timestamp + output "#{config[:scheme]}.statstable.#{database}.n_tup_upd", row['n_tup_upd'], timestamp + output "#{config[:scheme]}.statstable.#{database}.n_tup_del", row['n_tup_del'], timestamp + output "#{config[:scheme]}.statstable.#{database}.n_tup_hot_upd", row['n_tup_hot_upd'], timestamp + output "#{config[:scheme]}.statstable.#{database}.n_live_tup", row['n_live_tup'], timestamp + output "#{config[:scheme]}.statstable.#{database}.n_dead_tup", row['n_dead_tup'], timestamp end end - - ok end end diff --git a/lib/sensu-plugins-postgres/pgdatabases.rb b/lib/sensu-plugins-postgres/pgdatabases.rb new file mode 100644 index 0000000..34ebc16 --- /dev/null +++ b/lib/sensu-plugins-postgres/pgdatabases.rb @@ -0,0 +1,20 @@ +module Pgdatabases + def pgdatabases + if config[:databases].nil? + con = PG.connect(host: config[:hostname], + dbname: config[:database], + user: config[:user], + password: config[:password], + port: config[:port], + connect_timeout: config[:timeout]) + + dbs = con.exec('SELECT datname FROM pg_database').map { |r| r['datname'] } - %w[template0] + + con.close + + dbs + else + config[:databases].split(',').map(&:strip) + end + end +end