sensu-plugins-mysql 1.0.0 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 481c23c6d191fbb357eb02f3dbb577b59d662592
4
- data.tar.gz: 2f21d675e9dee317be43c6130204796625bf2552
3
+ metadata.gz: 3f33a1ae073b52dccd89fdf73543c66b45e48432
4
+ data.tar.gz: e5a88da4ae4bcf3d1d13238effdbbc38d3f50001
5
5
  SHA512:
6
- metadata.gz: c16f46e42b91517cb01c49420353f51f3dfa8036de139dfabe34e31c3afc77b2f03058142ed465a25d6f0af90aa737f367d88f5b2dce9ca84d1ec9c2fb7ee4c7
7
- data.tar.gz: f03353f1dd829e06b72f649c3da30d197bac17e14891e5c43cb7ad9966d537216da8bd004438ba12616def3c843c9d7da7ceb796c37ef2579944802504a3298a
6
+ metadata.gz: 0a1a0c0c2b9749c73bfd86b909f7d7d7738ec784185241a7612d9c0dccf5f87bbc29665208ad77cc113dd9e2ff4c441360ecf0cf78481cf38d6b3b57ddc81974
7
+ data.tar.gz: b012237ad2fd4945605821722a1a8944fb80b08ed5219e52995c7d2f0353f341b6b7e7d99ce828f4c1be10ef3b6f8b1b6ba4f8c6d0c76185fcbedd256e5729a6
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [1.1.0] - 2017-01-15
9
+ ### Added
10
+ - Added minimum thresholds to the check-mysql-threads.rb script
11
+ - Added metrics plugin with mysql gem requirement
12
+ - Added metrics plugin metrics-mysql-processes from `SHOW PROCESSLIST`
13
+ - Added fallback plugin check-mysql-status.rb with no mysql gem requirement - status and replication
14
+ - Added multi source replication parameter on check-mysql-replication-status.rb
15
+
16
+ ### Fixed
17
+ - metrics-mysql-graphite.rb: Properly close mysql connection
18
+
8
19
  ## [1.0.0] - 2016-08-15
9
20
  ### Added
10
21
  - added check-mysql-threads.rb script
@@ -40,7 +51,8 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
40
51
  ### Added
41
52
  - initial release
42
53
 
43
- [Unreleased]: https://github.com/sensu-plugins/sensu-plugins-mysql/compare/1.0.0...HEAD
54
+ [Unreleased]: https://github.com/sensu-plugins/sensu-plugins-mysql/compare/1.1.0...HEAD
55
+ [1.1.0]: https://github.com/sensu-plugins/sensu-plugins-mysql/compare/1.0.0...1.1.0
44
56
  [1.0.0]: https://github.com/sensu-plugins/sensu-plugins-mysql/compare/0.0.4...1.0.0
45
57
  [0.0.4]: https://github.com/sensu-plugins/sensu-plugins-mysql/compare/0.0.3...0.0.4
46
58
  [0.0.3]: https://github.com/sensu-plugins/sensu-plugins-mysql/compare/0.0.2...0.0.3
data/README.md CHANGED
@@ -11,11 +11,14 @@
11
11
  ## Files
12
12
  * bin/check-cloudwatch-mysql-sensu.rb
13
13
  * bin/check-mysql-alive.rb
14
+ * bin/check-mysql-status.rb
14
15
  * bin/check-mysql-connections.rb
15
16
  * bin/check-mysql-disk.rb
16
17
  * bin/check-mysql-innodb-lock.rb
17
18
  * bin/check-mysql-threads.rb
18
19
  * bin/metrics-mysql-graphite.rb
20
+ * bin/metrics-mysql-processes.rb
21
+ * bin/metrics-mysql-raw.rb
19
22
  * bin/metrics-mysql.rb
20
23
  * bin/mysql-metrics.sql
21
24
 
@@ -52,6 +52,19 @@ class CheckMysqlDisk < Sensu::Plugin::Check::CLI
52
52
  description: 'Critical threshold',
53
53
  default: '95'
54
54
 
55
+ option :port,
56
+ description: 'Port to connect to',
57
+ short: '-P PORT',
58
+ long: '--port PORT',
59
+ proc: proc(&:to_i),
60
+ default: '3306'
61
+
62
+ option :socket,
63
+ description: 'Socket to use',
64
+ short: '-s SOCKET',
65
+ long: '--socket SOCKET',
66
+ default: nil
67
+
55
68
  def run
56
69
  if config[:ini]
57
70
  ini = IniFile.load(config[:ini])
@@ -73,7 +86,7 @@ class CheckMysqlDisk < Sensu::Plugin::Check::CLI
73
86
 
74
87
  begin
75
88
  total_size = 0.0
76
- db = Mysql.new(db_host, db_user, db_pass)
89
+ db = Mysql.real_connect(config[:host], db_user, db_pass, nil, config[:port], config[:socket])
77
90
 
78
91
  results = db.query <<-EOSQL
79
92
  SELECT table_schema,
@@ -5,6 +5,7 @@
5
5
  #
6
6
  # Copyright 2011 Sonian, Inc <chefs@sonian.net>
7
7
  # Updated by Oluwaseun Obajobi 2014 to accept ini argument
8
+ # Updated by Nicola Strappazzon 2016 to implement Multi Source Replication
8
9
  #
9
10
  # Released under the same terms as Sensu (the MIT license); see LICENSE
10
11
  # for details.
@@ -56,6 +57,11 @@ class CheckMysqlReplicationStatus < Sensu::Plugin::Check::CLI
56
57
  long: '--password=VALUE',
57
58
  description: 'Database password'
58
59
 
60
+ option :master_connection,
61
+ short: '-m',
62
+ long: '--master-connection=VALUE',
63
+ description: 'Replication master connection name'
64
+
59
65
  option :ini,
60
66
  short: '-i',
61
67
  long: '--ini VALUE',
@@ -88,6 +94,7 @@ class CheckMysqlReplicationStatus < Sensu::Plugin::Check::CLI
88
94
  db_pass = config[:pass]
89
95
  end
90
96
  db_host = config[:host]
97
+ db_conn = config[:master_connection]
91
98
 
92
99
  if [db_host, db_user, db_pass].any?(&:nil?)
93
100
  unknown 'Must specify host, user, password'
@@ -95,7 +102,12 @@ class CheckMysqlReplicationStatus < Sensu::Plugin::Check::CLI
95
102
 
96
103
  begin
97
104
  db = Mysql.new(db_host, db_user, db_pass, nil, config[:port], config[:socket])
98
- results = db.query 'show slave status'
105
+
106
+ results = if db_conn.nil?
107
+ db.query 'SHOW SLAVE STATUS'
108
+ else
109
+ db.query "SHOW SLAVE '#{db_conn}' STATUS"
110
+ end
99
111
 
100
112
  unless results.nil?
101
113
  results.each_hash do |row|
@@ -108,7 +120,12 @@ class CheckMysqlReplicationStatus < Sensu::Plugin::Check::CLI
108
120
  row[key] =~ /Yes/
109
121
  end
110
122
 
111
- output = 'Slave not running!'
123
+ output = if db_conn.nil?
124
+ 'Slave not running!'
125
+ else
126
+ "Slave on master connection #{db_conn} not running!"
127
+ end
128
+
112
129
  output += ' STATES:'
113
130
  output += " Slave_IO_Running=#{row['Slave_IO_Running']}"
114
131
  output += ", Slave_SQL_Running=#{row['Slave_SQL_Running']}"
@@ -125,8 +142,10 @@ class CheckMysqlReplicationStatus < Sensu::Plugin::Check::CLI
125
142
  warning message
126
143
  elsif replication_delay >= config[:crit]
127
144
  critical message
128
- else
145
+ elsif db_conn.nil?
129
146
  ok "slave running: #{slave_running}, #{message}"
147
+ else
148
+ ok "master connection: #{db_conn}, slave running: #{slave_running}, #{message}"
130
149
  end
131
150
  end
132
151
  ok 'show slave status was nil. This server is not a slave.'
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # MySQL Status Plugin
4
+ # ===
5
+ #
6
+ # This plugin attempts to login to mysql with provided credentials.
7
+ # NO DEPENDENCIES (no mysql-devel and thus no implicit mysql-server restart)
8
+ # It checks whether MySQL is UP --check status
9
+ # It checks replication delay --check replication
10
+ # Author: Magic Online - www.magic.fr
11
+ # Date: September 2016
12
+ #
13
+ # Author: Magic Online - www.magic.fr - September 2016
14
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
15
+ # for details.
16
+ #
17
+ # USING INI ARGUMENT
18
+ # The ini file should be readable by the sensu user/group.
19
+ #
20
+ # EXAMPLE
21
+ # check-mysql-status.rb -h localhost --ini '/etc/sensu/my.cnf' --check status
22
+ # check-mysql-status.rb -h localhost --ini '/etc/sensu/my.cnf' --check replication
23
+ #
24
+ # MY.CNF INI FORMAT
25
+ # [client]
26
+ # user=sensu
27
+ # password="abcd1234"
28
+ # socket="/var/lib/mysql/mysql.sock"
29
+ #
30
+
31
+ require 'sensu-plugin/check/cli'
32
+ require 'inifile'
33
+ require 'open3'
34
+
35
+ # Check MySQL Status
36
+ class CheckMySQLStatus < Sensu::Plugin::Check::CLI
37
+ option :user, description: 'MySQL User', short: '-u USER', long: '--user USER', default: 'mosim'
38
+ option :password, description: 'MySQL Password', short: '-p PASS', long: '--password PASS', default: 'mysqlPassWord'
39
+ option :ini, description: 'My.cnf ini file', short: '-i', long: '--ini VALUE'
40
+ option :hostname, description: 'Hostname to login to', short: '-h HOST', long: '--hostname HOST', default: 'localhost'
41
+ option :database, description: 'Database schema to connect to', short: '-d DATABASE', long: '--database DATABASE', default: 'test'
42
+ option :port, description: 'Port to connect to', short: '-P PORT', long: '--port PORT', default: '3306'
43
+ option :socket, description: 'Socket to use', short: '-s SOCKET', long: '--socket SOCKET', default: '/var/run/mysqld/mysqld.sock'
44
+ option :binary, description: 'Absolute path to mysql binary', short: '-b BINARY', long: '--binary BINARY', default: 'mysql'
45
+ option :check, description: 'type of check: status | replication', short: '-c CHECK', long: '--check CHECK', default: 'status'
46
+ option :warn, short: '-w', long: '--warning=VALUE', description: 'Warning threshold for replication lag', default: 900
47
+ option :crit, short: '-c', long: '--critical=VALUE', description: 'Critical threshold for replication lag', default: 1800
48
+ option :debug, description: 'Print debug info', long: '--debug', default: false
49
+
50
+ def credentials
51
+ if config[:ini]
52
+ ini = IniFile.load(config[:ini])
53
+ section = ini['client']
54
+ db_user = section['user']
55
+ db_pass = section['password']
56
+ db_socket = section['socket']
57
+ else
58
+ db_user = config[:user]
59
+ db_pass = config[:password]
60
+ db_socket = config[:socket]
61
+ end
62
+ [db_user, db_pass, db_socket]
63
+ end
64
+
65
+ # Status check
66
+ def status_check(db_user, db_pass, db_socket)
67
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} --port #{config[:port]} \
68
+ --socket #{db_socket} -p\"#{db_pass.strip}\" --batch --disable-column-names -e 'show schemas;'"
69
+ begin
70
+ stdout, _stderr, status = Open3.capture3(cmd)
71
+ if status.to_i == 0
72
+ ok "#{status} | #{stdout.split("\n")}"
73
+ else
74
+ critical "Error message: status: #{status}"
75
+ end
76
+ rescue => e
77
+ critical "Error message: status: #{status} | Exception: #{e}"
78
+ ensure
79
+ puts ''
80
+ end
81
+ end
82
+
83
+ def replication_check(db_user, db_pass, db_socket)
84
+ table = {}
85
+ begin
86
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} --port #{config[:port]} \
87
+ --socket #{db_socket} -p\"#{db_pass.strip}\" -e 'SHOW SLAVE STATUS\\G'"
88
+ stdout, _stderr, status = Open3.capture3(cmd)
89
+ if status.to_i != 0
90
+ critical "Error message: status: #{status}"
91
+ end
92
+ stdout.split("\n").each do |line|
93
+ key = line.split(':')[0]
94
+ value = line.split(':')[1]
95
+ table[key.strip.to_s] = value.to_s unless key.include? '***'
96
+ end
97
+ dict = []
98
+ table.keys.to_a.each do |k|
99
+ %w(Slave_IO_State Slave_IO_Running Slave_SQL_Running Last_IO_Error Last_SQL_Error Seconds_Behind_Master).each do |key|
100
+ dict.push(k.strip.to_s) if key.strip == k.strip
101
+ end
102
+ end
103
+ table.each do |attribute, value|
104
+ puts "#{attribute} : #{value}" if config[:debug]
105
+ warn "couldn't detect replication status :#{dict.size}" unless dict.size == 6
106
+ slave_running = %w(Slave_IO_Running Slave_SQL_Running).all? do |key|
107
+ table[key].to_s =~ /Yes/
108
+ end
109
+ output = 'Slave not running!'
110
+ output += ' STATES:'
111
+ output += " Slave_IO_Running=#{table['Slave_IO_Running']}"
112
+ output += ", Slave_SQL_Running=#{table['Slave_SQL_Running']}"
113
+ output += ", LAST ERROR: #{table['Last_SQL_Error']}"
114
+ critical output unless slave_running
115
+ replication_delay = table['Seconds_Behind_Master'].to_i
116
+ message = "replication delayed by #{replication_delay}"
117
+ if replication_delay > config[:warn].to_i && replication_delay <= config[:crit].to_i
118
+ warning message
119
+ elsif replication_delay >= config[:crit].to_i
120
+ critical message
121
+ else
122
+ ok "slave running: #{slave_running}, #{message}"
123
+ end
124
+ end
125
+ ok 'show slave status was nil. This server is not a slave.'
126
+ rescue => e
127
+ critical "Error message: status: #{status} | Exception: #{e}"
128
+ end
129
+ end
130
+
131
+ def run
132
+ db_user = credentials[0]
133
+ db_pass = credentials[1]
134
+ db_socket = credentials[2]
135
+ if config[:check] == 'status'
136
+ status_check(db_user, db_pass, db_socket)
137
+ end
138
+ if config[:check] == 'replication'
139
+ replication_check(db_user, db_pass, db_socket)
140
+ end
141
+ unknown 'No check type succeeded. Check your options'
142
+ end
143
+ end
@@ -5,6 +5,10 @@
5
5
  # DESCRIPTION:
6
6
  # MySQL Threads Health plugin
7
7
  # This plugin evaluates the number of MySQL running threads and warns you according to specified limits
8
+ # -w for high threshold warning
9
+ # -c for high threshold critical
10
+ # -m for low threshold warning
11
+ # -l for low threshold critical
8
12
  #
9
13
  # OUTPUT:
10
14
  # plain text
@@ -16,7 +20,7 @@
16
20
  # gem: sensu-plugin
17
21
  #
18
22
  # USAGE:
19
- # check-mysql-threads.rb -w [threshold] -c [threshold]
23
+ # check-mysql-threads.rb -w [threshold] -c [threshold] -m [threshold] -l [threshold]
20
24
  #
21
25
  # NOTES:
22
26
  #
@@ -76,6 +80,18 @@ class CheckMySQLHealth < Sensu::Plugin::Check::CLI
76
80
  long: '--critnum NUMBER',
77
81
  default: 25
78
82
 
83
+ option :minwarn,
84
+ description: "Number of running threads under which we'll issue a warning",
85
+ short: '-m NUMBER',
86
+ long: '--warnlow NUMBER',
87
+ default: 1
88
+
89
+ option :mincrit,
90
+ description: "Number of running threads under which we'll issue an alert",
91
+ short: '-l NUMBER',
92
+ long: '--critlow NUMBER',
93
+ default: 0
94
+
79
95
  def run
80
96
  if config[:ini]
81
97
  ini = IniFile.load(config[:ini])
@@ -90,6 +106,8 @@ class CheckMySQLHealth < Sensu::Plugin::Check::CLI
90
106
  run_thr = db.query("SHOW GLOBAL STATUS LIKE 'Threads_running'").fetch_hash.fetch('Value').to_i
91
107
  critical "MySQL currently running threads: #{run_thr}" if run_thr >= config[:maxcrit].to_i
92
108
  warning "MySQL currently running threads: #{run_thr}" if run_thr >= config[:maxwarn].to_i
109
+ critical "MySQL currently running threads: #{run_thr}" if run_thr <= config[:mincrit].to_i
110
+ warning "MySQL currently running threads: #{run_thr}" if run_thr <= config[:minwarn].to_i
93
111
  ok "Currently running threads are under limit in MySQL: #{run_thr}"
94
112
  rescue Mysql::Error => e
95
113
  critical "MySQL check failed: #{e.error}"
@@ -249,6 +249,8 @@ class MysqlGraphite < Sensu::Plugin::Metric::CLI::Graphite
249
249
  rescue => e
250
250
  puts e.message
251
251
  end
252
+
253
+ mysql.close if mysql
252
254
  end
253
255
 
254
256
  ok
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # metrics-mysql-processes
4
+ #
5
+ # DESCRIPTION:
6
+ # Gets metrics out of of MySQL's "SHOW PROCESSLIST" query.
7
+ #
8
+ # Output number of connections per-users, number of connections
9
+ # per-databases, number of the different commands running.
10
+ #
11
+ # OUTPUT:
12
+ # metric-data
13
+ #
14
+ # PLATFORMS:
15
+ # Linux, Windows, BSD, Solaris, etc
16
+ #
17
+ # DEPENDENCIES:
18
+ # gem: sensu-plugin
19
+ # gem: mysql
20
+ #
21
+ # USAGE:
22
+ # This was implemented to load mysql credentials without parsing the username/password.
23
+ # The ini file should be readable by the sensu user/group.
24
+ # Ref: http://eric.lubow.org/2009/ruby/parsing-ini-files-with-ruby/
25
+ #
26
+ # EXAMPLE
27
+ # mysql-alive.rb -h db01 --ini '/etc/sensu/my.cnf'
28
+ #
29
+ # MY.CNF INI FORMAT
30
+ # [client]
31
+ # user=sensu
32
+ # password="abcd1234"
33
+ #
34
+ # NOTES:
35
+ #
36
+ # LICENSE:
37
+ # Jonathan Ballet <jballet@edgelab.ch>
38
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
39
+ # for details.
40
+
41
+ require 'sensu-plugin/metric/cli'
42
+ require 'mysql'
43
+ require 'socket'
44
+ require 'inifile'
45
+
46
+ class MetricsMySQLProcesses < Sensu::Plugin::Metric::CLI::Graphite
47
+ option :host,
48
+ short: '-h HOST',
49
+ long: '--host HOST',
50
+ description: 'MySQL Host to connect to',
51
+ required: true
52
+
53
+ option :port,
54
+ short: '-P PORT',
55
+ long: '--port PORT',
56
+ description: 'MySQL Port to connect to',
57
+ proc: proc(&:to_i),
58
+ default: 3306
59
+
60
+ option :username,
61
+ short: '-u USERNAME',
62
+ long: '--user USERNAME',
63
+ description: 'MySQL Username'
64
+
65
+ option :password,
66
+ short: '-p PASSWORD',
67
+ long: '--pass PASSWORD',
68
+ description: 'MySQL password',
69
+ default: ''
70
+
71
+ option :ini,
72
+ short: '-i',
73
+ long: '--ini VALUE',
74
+ description: 'My.cnf ini file'
75
+
76
+ option :scheme,
77
+ description: 'Metric naming scheme, text to prepend to metric',
78
+ short: '-s SCHEME',
79
+ long: '--scheme SCHEME',
80
+ default: "#{Socket.gethostname}.mysql"
81
+
82
+ option :socket,
83
+ short: '-S SOCKET',
84
+ long: '--socket SOCKET',
85
+ description: 'MySQL Unix socket to connect to'
86
+
87
+ def run
88
+ config[:host].split(' ').each do |mysql_host|
89
+ mysql_shorthostname = mysql_host.split('.')[0]
90
+ if config[:ini]
91
+ ini = IniFile.load(config[:ini])
92
+ section = ini['client']
93
+ db_user = section['user']
94
+ db_pass = section['password']
95
+ else
96
+ db_user = config[:username]
97
+ db_pass = config[:password]
98
+ end
99
+ begin
100
+ mysql = Mysql.new(mysql_host, db_user, db_pass, nil, config[:port], config[:socket])
101
+
102
+ results = mysql.query('SHOW PROCESSLIST')
103
+ rescue => e
104
+ unknown "Unable to query MySQL: #{e.message}"
105
+ end
106
+
107
+ metrics = {
108
+ 'user' => {},
109
+ 'database' => {},
110
+ 'command' => {}
111
+ }
112
+
113
+ metrics.each_value { |value| value.default = 0 }
114
+
115
+ results.each_hash do |row|
116
+ metrics['user'][row['User']] += 1
117
+ if row['db'] # If no database has been selected by the process, it is set to nil.
118
+ metrics['database'][row['db']] += 1
119
+ end
120
+ metrics['command'][row['Command']] += 1
121
+ end
122
+
123
+ metrics.each do |key, value|
124
+ value.each do |instance, count|
125
+ output "#{config[:scheme]}.#{mysql_shorthostname}.#{key}.#{instance}", count
126
+ end
127
+ end
128
+ end
129
+
130
+ ok
131
+ end
132
+ end
@@ -0,0 +1,382 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # MySQL metrics Plugin without mysql gem requirement
4
+ # ===
5
+ #
6
+ # This plugin attempts to login to mysql with provided credentials.
7
+ # and outputs metrics in graphite format
8
+ #
9
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
10
+ # for details.
11
+ #
12
+ # USING INI ARGUMENT
13
+ # This was implemented to load mysql credentials without parsing
14
+ # the username/password.
15
+ # The ini file should be readable by the sensu user/group.
16
+ #
17
+ # EXAMPLE
18
+ # metrics-mysql-raw.rb -h localhost --ini '/etc/sensu/my.cnf'
19
+ #
20
+ # MY.CNF INI FORMAT
21
+ # [client]
22
+ # user=sensu
23
+ # password="abcd1234"
24
+ # socket="/var/lib/mysql/mysql.sock"
25
+ #
26
+ # LICENSE:
27
+ # Copyright 2012 Pete Shima <me@peteshima.com>
28
+ # Additional hacks by Joe Miller - https://github.com/joemiller
29
+ # Updated by Oluwaseun Obajobi 2014 to accept ini argument
30
+ # Forked by Magic Online 11.2016 to not depend on mysql gem
31
+ # - www.magic.fr <hanynowsky@gmail.com>
32
+ # MIT - Same as Sensu License
33
+ #
34
+
35
+ require 'sensu-plugin/metric/cli'
36
+ require 'open3'
37
+ require 'socket'
38
+ require 'inifile'
39
+ require 'timeout'
40
+
41
+ #
42
+ # Metrics Mysql Raw
43
+ #
44
+ class MetricsMySQLRaw < Sensu::Plugin::Metric::CLI::Graphite
45
+ option(
46
+ :user,
47
+ description: 'MySQL User',
48
+ short: '-u USER',
49
+ long: '--user USER',
50
+ default: 'mosim'
51
+ )
52
+
53
+ option(
54
+ :password,
55
+ description: 'MySQL Password',
56
+ short: '-p PASS',
57
+ long: '--password PASS',
58
+ default: 'mysqlPassWord'
59
+ )
60
+ option(
61
+ :ini,
62
+ description: 'My.cnf ini file',
63
+ short: '-i',
64
+ long: '--ini VALUE'
65
+ )
66
+
67
+ option(
68
+ :hostname,
69
+ description: 'Hostname to login to',
70
+ short: '-h HOST',
71
+ long: '--hostname HOST',
72
+ default: 'localhost'
73
+ )
74
+
75
+ option(
76
+ :database,
77
+ description: 'Database schema to connect to. NOT YET IMPlemented',
78
+ short: '-d DATABASE',
79
+ long: '--database DATABASE',
80
+ default: 'test'
81
+ )
82
+
83
+ option(
84
+ :timeout,
85
+ description: 'Timeout',
86
+ short: '-T TIMEOUT',
87
+ long: '--timeout TIMEOUT',
88
+ default: 10
89
+ )
90
+
91
+ option(
92
+ :port,
93
+ description: 'Port to connect to',
94
+ short: '-P PORT',
95
+ long: '--port PORT',
96
+ default: '3306'
97
+ )
98
+
99
+ option(
100
+ :socket,
101
+ description: 'Socket to use',
102
+ short: '-s SOCKET',
103
+ long: '--socket SOCKET',
104
+ default: '/var/run/mysqld/mysqld.sock'
105
+ )
106
+
107
+ option(
108
+ :binary,
109
+ description: 'Absolute path to mysql binary',
110
+ short: '-b BINARY',
111
+ long: '--binary BINARY',
112
+ default: 'mysql'
113
+ )
114
+
115
+ option(
116
+ :check,
117
+ description: 'type of check: metric',
118
+ short: '-c CHECK',
119
+ long: '--check CHECK',
120
+ default: 'metric'
121
+ )
122
+
123
+ option(
124
+ :scheme,
125
+ description: 'Metric naming scheme, text to prepend to metric',
126
+ short: '-s SCHEME',
127
+ long: '--scheme SCHEME',
128
+ default: "#{Socket.gethostname}.mysql"
129
+ )
130
+
131
+ option(
132
+ :verbose,
133
+ short: '-v',
134
+ long: '--verbose',
135
+ boolean: true
136
+ )
137
+
138
+ option(
139
+ :off,
140
+ description: 'Turn Metrics OFF',
141
+ long: '--off',
142
+ boolean: true,
143
+ default: false
144
+ )
145
+
146
+ # Metrics hash
147
+ def metrics_hash
148
+ metrics = {
149
+ 'general' => {
150
+ 'Bytes_received' => 'rxBytes',
151
+ 'Bytes_sent' => 'txBytes',
152
+ 'Key_read_requests' => 'keyRead_requests',
153
+ 'Key_reads' => 'keyReads',
154
+ 'Key_write_requests' => 'keyWrite_requests',
155
+ 'Key_writes' => 'keyWrites',
156
+ 'Binlog_cache_use' => 'binlogCacheUse',
157
+ 'Binlog_cache_disk_use' => 'binlogCacheDiskUse',
158
+ 'Max_used_connections' => 'maxUsedConnections',
159
+ 'Aborted_clients' => 'abortedClients',
160
+ 'Aborted_connects' => 'abortedConnects',
161
+ 'Threads_connected' => 'threadsConnected',
162
+ 'Open_files' => 'openFiles',
163
+ 'Open_tables' => 'openTables',
164
+ 'Opened_tables' => 'openedTables',
165
+ 'Prepared_stmt_count' => 'preparedStmtCount',
166
+ 'Seconds_Behind_Master' => 'slaveLag',
167
+ 'Select_full_join' => 'fullJoins',
168
+ 'Select_full_range_join' => 'fullRangeJoins',
169
+ 'Select_range' => 'selectRange',
170
+ 'Select_range_check' => 'selectRange_check',
171
+ 'Select_scan' => 'selectScan',
172
+ 'Slow_queries' => 'slowQueries'
173
+ },
174
+ 'querycache' => {
175
+ 'Qcache_queries_in_cache' => 'queriesInCache',
176
+ 'Qcache_hits' => 'cacheHits',
177
+ 'Qcache_inserts' => 'inserts',
178
+ 'Qcache_not_cached' => 'notCached',
179
+ 'Qcache_lowmem_prunes' => 'lowMemPrunes'
180
+ },
181
+ 'commands' => {
182
+ 'Com_admin_commands' => 'admin_commands',
183
+ 'Com_begin' => 'begin',
184
+ 'Com_change_db' => 'change_db',
185
+ 'Com_commit' => 'commit',
186
+ 'Com_create_table' => 'create_table',
187
+ 'Com_drop_table' => 'drop_table',
188
+ 'Com_show_keys' => 'show_keys',
189
+ 'Com_delete' => 'delete',
190
+ 'Com_create_db' => 'create_db',
191
+ 'Com_grant' => 'grant',
192
+ 'Com_show_processlist' => 'show_processlist',
193
+ 'Com_flush' => 'flush',
194
+ 'Com_insert' => 'insert',
195
+ 'Com_purge' => 'purge',
196
+ 'Com_replace' => 'replace',
197
+ 'Com_rollback' => 'rollback',
198
+ 'Com_select' => 'select',
199
+ 'Com_set_option' => 'set_option',
200
+ 'Com_show_binlogs' => 'show_binlogs',
201
+ 'Com_show_databases' => 'show_databases',
202
+ 'Com_show_fields' => 'show_fields',
203
+ 'Com_show_status' => 'show_status',
204
+ 'Com_show_tables' => 'show_tables',
205
+ 'Com_show_variables' => 'show_variables',
206
+ 'Com_update' => 'update',
207
+ 'Com_drop_db' => 'drop_db',
208
+ 'Com_revoke' => 'revoke',
209
+ 'Com_drop_user' => 'drop_user',
210
+ 'Com_show_grants' => 'show_grants',
211
+ 'Com_lock_tables' => 'lock_tables',
212
+ 'Com_show_create_table' => 'show_create_table',
213
+ 'Com_unlock_tables' => 'unlock_tables',
214
+ 'Com_alter_table' => 'alter_table'
215
+ },
216
+ 'counters' => {
217
+ 'Handler_write' => 'handlerWrite',
218
+ 'Handler_update' => 'handlerUpdate',
219
+ 'Handler_delete' => 'handlerDelete',
220
+ 'Handler_read_first' => 'handlerRead_first',
221
+ 'Handler_read_key' => 'handlerRead_key',
222
+ 'Handler_read_next' => 'handlerRead_next',
223
+ 'Handler_read_prev' => 'handlerRead_prev',
224
+ 'Handler_read_rnd' => 'handlerRead_rnd',
225
+ 'Handler_read_rnd_next' => 'handlerRead_rnd_next',
226
+ 'Handler_commit' => 'handlerCommit',
227
+ 'Handler_rollback' => 'handlerRollback',
228
+ 'Handler_savepoint' => 'handlerSavepoint',
229
+ 'Handler_savepoint_rollback' => 'handlerSavepointRollback'
230
+ },
231
+ 'innodb' => {
232
+ 'Innodb_buffer_pool_pages_total' => 'bufferTotal_pages',
233
+ 'Innodb_buffer_pool_pages_free' => 'bufferFree_pages',
234
+ 'Innodb_buffer_pool_pages_dirty' => 'bufferDirty_pages',
235
+ 'Innodb_buffer_pool_pages_data' => 'bufferUsed_pages',
236
+ 'Innodb_page_size' => 'pageSize',
237
+ 'Innodb_pages_created' => 'pagesCreated',
238
+ 'Innodb_pages_read' => 'pagesRead',
239
+ 'Innodb_pages_written' => 'pagesWritten',
240
+ 'Innodb_row_lock_current_waits' => 'currentLockWaits',
241
+ 'Innodb_row_lock_waits' => 'lockWaitTimes',
242
+ 'Innodb_row_lock_time' => 'rowLockTime',
243
+ 'Innodb_data_reads' => 'fileReads',
244
+ 'Innodb_data_writes' => 'fileWrites',
245
+ 'Innodb_data_fsyncs' => 'fileFsyncs',
246
+ 'Innodb_log_writes' => 'logWrites',
247
+ 'Innodb_rows_updated' => 'rowsUpdated',
248
+ 'Innodb_rows_read' => 'rowsRead',
249
+ 'Innodb_rows_deleted' => 'rowsDeleted',
250
+ 'Innodb_rows_inserted' => 'rowsInserted'
251
+ },
252
+ 'configuration' => {
253
+ 'Max_prepared_stmt_count' => 'MaxPreparedStmtCount'
254
+ }
255
+ }
256
+ metrics
257
+ end
258
+
259
+ # Credentials
260
+ def credentials
261
+ if config[:ini]
262
+ ini = IniFile.load(config[:ini])
263
+ section = ini['client']
264
+ db_user = section['user']
265
+ db_pass = section['password']
266
+ db_socket = section['socket']
267
+ else
268
+ db_user = config[:user]
269
+ db_pass = config[:password]
270
+ db_socket = config[:socket]
271
+ end
272
+ [db_user, db_pass, db_socket]
273
+ end
274
+
275
+ # Slave metrics
276
+ def slave_metrics(metrics)
277
+ # should return a single element array containing one hash
278
+ # #YELLOW
279
+ mysql_shorthostname = config[:hostname].tr('.', '_')
280
+ slave_results = Hash['a' => 100, 'b' => 200]
281
+ slave_results.first.each do |key, value|
282
+ if metrics['general'].include?(key)
283
+ # Replication lag being null is bad, very bad, so negativate it here
284
+ value = -1 if key == 'Seconds_Behind_Master' && value.nil?
285
+ output "#{config[:scheme]}.#{mysql_shorthostname}.general.#{metrics['general'][key]}", value
286
+ end
287
+ end
288
+ rescue => e
289
+ puts "Error querying slave status: #{e}" if config[:verbose]
290
+ end
291
+
292
+ # Configuration metrics
293
+ def configuration_metrics(metrics, db_user, db_pass, db_socket)
294
+ mysql_shorthostname = config[:hostname].tr('.', '_')
295
+ table = []
296
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} \
297
+ --port #{config[:port]} --socket #{db_socket} -p\"#{db_pass.chomp}\" --batch \
298
+ --disable-column-names -e 'SHOW GLOBAL VARIABLES;'"
299
+ stdout, _stderr, status = Open3.capture3(cmd)
300
+ puts status.to_s.split(' ')[3] if config[:verbose]
301
+ if status == 0
302
+ puts status.to_s if config[:verbose]
303
+ stdout.split("\n").each do |row|
304
+ line = row.tr("\t", ':')
305
+ key = line.split(':')[0]
306
+ value = line.split(':')[1]
307
+ table.push('Variable_name' => key, 'Value' => value)
308
+ end
309
+ else
310
+ critical "Error message: Global variables - status: #{status}"
311
+ end
312
+ variables_results = table
313
+ category = 'configuration'
314
+ variables_results.each do |row|
315
+ metrics[category].each do |metric, desc|
316
+ if metric.casecmp(row['Variable_name']) == 0
317
+ output "#{config[:scheme]}.#{mysql_shorthostname}.#{category}.#{desc}", row['Value']
318
+ end
319
+ end
320
+ end
321
+ rescue => e
322
+ puts e.message
323
+ end
324
+
325
+ # Fetch MySQL metrics
326
+ def fetcher(db_user, db_pass, db_socket)
327
+ metrics = metrics_hash
328
+ if config[:check] == 'metric'
329
+ mysql_shorthostname = config[:hostname].tr('.', '_')
330
+ begin
331
+ table = []
332
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} \
333
+ --port #{config[:port]} --socket #{db_socket} -p\"#{db_pass.chomp}\" --batch \
334
+ --disable-column-names -e 'SHOW GLOBAL STATUS;'"
335
+ stdout, _stderr, status = Open3.capture3(cmd)
336
+ puts status.to_s.split(' ')[3] if config[:verbose]
337
+ if status == 0
338
+ puts status.to_s if config[:verbose]
339
+ stdout.split("\n").each do |row|
340
+ line = row.tr("\t", ':')
341
+ key = line.split(':')[0]
342
+ value = line.split(':')[1]
343
+ table.push('Variable_name' => key, 'Value' => value)
344
+ end
345
+ else
346
+ critical "Error message: status: #{status}"
347
+ end
348
+ table.each do |row|
349
+ metrics.each do |category, var_mapping|
350
+ row_var_name = row['Variable_name'].to_s
351
+ var_mapping.keys.each do |vmkey|
352
+ if row_var_name.to_s == vmkey.to_s
353
+ prefix = "#{config[:scheme]}.#{mysql_shorthostname}.#{category}.#{vmkey[row_var_name]}"
354
+ output prefix, row['Value'] unless mysql_shorthostname.to_s.chomp.empty?
355
+ end
356
+ end
357
+ end
358
+ end
359
+ # Slave and configuration metrics here
360
+ slave_metrics(metrics)
361
+ configuration_metrics(metrics, db_user, db_pass, db_socket)
362
+ rescue => e
363
+ critical "Error message: status: #{status} | Exception: #{e.backtrace}"
364
+ ensure
365
+ ok ''
366
+ end
367
+ end
368
+ end
369
+
370
+ # Main Function
371
+ def run
372
+ ok 'Metrics deactivated by user using option --off' if config[:off] == true
373
+ begin
374
+ Timeout.timeout(config[:timeout]) do
375
+ fetcher(credentials[0], credentials[1], credentials[2])
376
+ end
377
+ rescue Timeout::Error => e
378
+ unknown "Timed out #{e.message}"
379
+ end
380
+ unknown 'Did not succeed to retrieve MySQL metrics. Check your options'
381
+ end
382
+ end
@@ -1,7 +1,7 @@
1
1
  module SensuPluginsMySql
2
2
  module Version
3
3
  MAJOR = 1
4
- MINOR = 0
4
+ MINOR = 1
5
5
  PATCH = 0
6
6
 
7
7
  VER_STRING = [MAJOR, MINOR, PATCH].compact.join('.')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sensu-plugins-mysql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sensu-Plugins and contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-16 00:00:00.000000000 Z
11
+ date: 2017-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inifile
@@ -191,8 +191,11 @@ executables:
191
191
  - check-mysql-disk.rb
192
192
  - check-mysql-innodb-lock.rb
193
193
  - check-mysql-replication-status.rb
194
+ - check-mysql-status.rb
194
195
  - check-mysql-threads.rb
195
196
  - metrics-mysql-graphite.rb
197
+ - metrics-mysql-processes.rb
198
+ - metrics-mysql-raw.rb
196
199
  - metrics-mysql.rb
197
200
  extensions: []
198
201
  extra_rdoc_files: []
@@ -205,8 +208,11 @@ files:
205
208
  - bin/check-mysql-disk.rb
206
209
  - bin/check-mysql-innodb-lock.rb
207
210
  - bin/check-mysql-replication-status.rb
211
+ - bin/check-mysql-status.rb
208
212
  - bin/check-mysql-threads.rb
209
213
  - bin/metrics-mysql-graphite.rb
214
+ - bin/metrics-mysql-processes.rb
215
+ - bin/metrics-mysql-raw.rb
210
216
  - bin/metrics-mysql.rb
211
217
  - bin/mysql-metrics.sql
212
218
  - lib/sensu-plugins-mysql.rb
@@ -237,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
237
243
  version: '0'
238
244
  requirements: []
239
245
  rubyforge_project:
240
- rubygems_version: 2.5.1
246
+ rubygems_version: 2.4.5
241
247
  signing_key:
242
248
  specification_version: 4
243
249
  summary: Sensu plugins for MySql