sensu-plugins-mysql 1.0.0 → 1.1.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: 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