sensu-plugins-mysql-boutetnico 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # MySQL Select Count Check
4
+ #
5
+ # Checks the length of a result set from a MySQL query.
6
+ #
7
+ # Copyright 2017 Andrew Thal <athal7@me.com> to check-mysql-query-result-count.rb
8
+ # Modified by Mutsutoshi Yoshimoto <negachov@gmail.com> 2018 to select count(*) version
9
+ #
10
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
11
+ # for details.
12
+
13
+ require 'sensu-plugin/check/cli'
14
+ require 'mysql'
15
+ require 'inifile'
16
+
17
+ class MysqlSelectCountCheck < Sensu::Plugin::Check::CLI
18
+ option :host,
19
+ short: '-h HOST',
20
+ long: '--host HOST',
21
+ description: 'MySQL Host to connect to'
22
+
23
+ option :port,
24
+ short: '-P PORT',
25
+ long: '--port PORT',
26
+ description: 'MySQL Port to connect to',
27
+ proc: proc(&:to_i),
28
+ default: 3306
29
+
30
+ option :username,
31
+ short: '-u USERNAME',
32
+ long: '--user USERNAME',
33
+ description: 'MySQL Username'
34
+
35
+ option :password,
36
+ short: '-p PASSWORD',
37
+ long: '--pass PASSWORD',
38
+ description: 'MySQL password'
39
+
40
+ option :database,
41
+ short: '-d DATABASE',
42
+ long: '--database DATABASE',
43
+ description: 'MySQL database',
44
+ required: true
45
+
46
+ option :ini,
47
+ short: '-i',
48
+ long: '--ini VALUE',
49
+ description: 'My.cnf ini file'
50
+
51
+ option :ini_section,
52
+ description: 'Section in my.cnf ini file',
53
+ long: '--ini-section VALUE',
54
+ default: 'client'
55
+
56
+ option :socket,
57
+ short: '-S SOCKET',
58
+ long: '--socket SOCKET',
59
+ description: 'MySQL Unix socket to connect to'
60
+
61
+ option :warn,
62
+ short: '-w COUNT',
63
+ long: '--warning COUNT',
64
+ description: 'Warning when query value exceeds threshold',
65
+ proc: proc(&:to_i),
66
+ required: true
67
+
68
+ option :crit,
69
+ short: '-c COUNT',
70
+ long: '--critical COUNT',
71
+ description: 'Critical when query value exceeds threshold',
72
+ proc: proc(&:to_i),
73
+ required: true
74
+
75
+ option :query,
76
+ short: '-q SELECT_COUNT_QUERY',
77
+ long: '--query SELECT_COUNT_QUERY',
78
+ description: 'Query to execute',
79
+ required: true
80
+
81
+ def run
82
+ if config[:ini]
83
+ ini = IniFile.load(config[:ini])
84
+ section = ini[config[:ini_section]]
85
+ db_user = section['user']
86
+ db_pass = section['password']
87
+ config[:host] = section['host']
88
+ config[:socket] = section['socket']
89
+ else
90
+ db_user = config[:username]
91
+ db_pass = config[:password]
92
+ end
93
+ raise 'Please specify hostname using -h or in mysql.cnf file' unless config[:host]
94
+
95
+ db = Mysql.real_connect(config[:host], db_user, db_pass, config[:database], config[:port], config[:socket])
96
+
97
+ count = db.query(config[:query]).fetch_row[0].to_i
98
+ if count >= config[:crit]
99
+ critical "Count is above the CRITICAL limit: #{count} count / #{config[:crit]} limit"
100
+ elsif count >= config[:warn]
101
+ warning "Count is above the WARNING limit: #{count} count / #{config[:warn]} limit"
102
+ else
103
+ ok "Count is below thresholds : #{count} count"
104
+ end
105
+ rescue Mysql::Error => e
106
+ errstr = "Error code: #{e.errno} Error message: #{e.error}"
107
+ critical "#{errstr} SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
108
+ rescue StandardError => e
109
+ critical "unhandled exception: #{e}"
110
+ ensure
111
+ db.close if db
112
+ end
113
+ end
@@ -0,0 +1,209 @@
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,
38
+ description: 'MySQL User, you really should use ini to hide credentials instead of using me',
39
+ short: '-u USER',
40
+ long: '--user USER',
41
+ default: 'mosim'
42
+
43
+ option :password,
44
+ description: 'MySQL Password, you really should use ini to hide credentials instead of using me',
45
+ short: '-p PASS',
46
+ long: '--password PASS',
47
+ default: 'mysqlPassWord'
48
+
49
+ option :ini,
50
+ description: 'My.cnf ini file',
51
+ short: '-i',
52
+ long: '--ini VALUE'
53
+
54
+ option :ini_section,
55
+ description: 'Section in my.cnf ini file',
56
+ long: '--ini-section VALUE',
57
+ default: 'client'
58
+
59
+ option :hostname,
60
+ description: 'Hostname to login to',
61
+ short: '-h HOST',
62
+ long: '--hostname HOST',
63
+ default: 'localhost'
64
+
65
+ option :database,
66
+ description: 'Database schema to connect to',
67
+ short: '-d DATABASE',
68
+ long: '--database DATABASE',
69
+ default: 'test'
70
+
71
+ option :port,
72
+ description: 'Port to connect to',
73
+ short: '-P PORT',
74
+ long: '--port PORT',
75
+ default: '3306'
76
+
77
+ option :socket,
78
+ description: 'Socket to use',
79
+ short: '-s SOCKET',
80
+ long: '--socket SOCKET',
81
+ default: '/var/run/mysqld/mysqld.sock'
82
+
83
+ option :binary,
84
+ description: 'Absolute path to mysql binary',
85
+ short: '-b BINARY',
86
+ long: '--binary BINARY',
87
+ default: 'mysql'
88
+
89
+ option :check,
90
+ description: 'type of check: (status|replication)',
91
+ short: '-C CHECK',
92
+ long: '--check CHECK',
93
+ default: 'status'
94
+
95
+ option :warn,
96
+ description: 'Warning threshold for replication lag',
97
+ short: '-w',
98
+ long: '--warning=VALUE',
99
+ default: 900
100
+
101
+ option :crit,
102
+ description: 'Critical threshold for replication lag',
103
+ short: '-c',
104
+ long: '--critical=VALUE',
105
+ default: 1800
106
+
107
+ option :debug,
108
+ description: 'Print debug info',
109
+ long: '--debug',
110
+ default: false
111
+
112
+ def credentials
113
+ if config[:ini]
114
+ ini = IniFile.load(config[:ini])
115
+ section = ini[config[:ini_section]]
116
+ db_user = section['user']
117
+ db_pass = section['password']
118
+ db_socket = if config[:socket]
119
+ config[:socket]
120
+ else
121
+ section['socket']
122
+ end
123
+ else
124
+ db_user = config[:user]
125
+ db_pass = config[:password]
126
+ db_socket = config[:socket]
127
+ end
128
+ [db_user, db_pass, db_socket]
129
+ end
130
+
131
+ # Status check
132
+ def status_check(db_user, db_pass, db_socket)
133
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} --port #{config[:port]} \
134
+ --socket #{db_socket} -p\"#{db_pass.strip}\" --batch --disable-column-names -e 'show schemas;'"
135
+ begin
136
+ stdout, _stderr, status = Open3.capture3(cmd)
137
+ if status.to_i == 0
138
+ ok "#{status} | #{stdout.split("\n")}"
139
+ else
140
+ critical "Error message: status: #{status}"
141
+ end
142
+ rescue StandardError => e
143
+ critical "Error message: status: #{status} | Exception: #{e}"
144
+ ensure
145
+ puts ''
146
+ end
147
+ end
148
+
149
+ def replication_check(db_user, db_pass, db_socket)
150
+ table = {}
151
+ begin
152
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} --port #{config[:port]} \
153
+ --socket #{db_socket} -p\"#{db_pass.strip}\" -e 'SHOW SLAVE STATUS\\G'"
154
+ stdout, _stderr, status = Open3.capture3(cmd)
155
+ if status.to_i != 0
156
+ critical "Error message: status: #{status}"
157
+ end
158
+ stdout.split("\n").each do |line|
159
+ key = line.split(':')[0]
160
+ value = line.split(':')[1]
161
+ table[key.strip.to_s] = value.to_s unless key.include? '***'
162
+ end
163
+ dict = []
164
+ table.keys.to_a.each do |k|
165
+ %w[Slave_IO_State Slave_IO_Running Slave_SQL_Running Last_IO_Error Last_SQL_Error Seconds_Behind_Master].each do |key|
166
+ dict.push(k.strip.to_s) if key.strip == k.strip
167
+ end
168
+ end
169
+ table.each do |attribute, value|
170
+ puts "#{attribute} : #{value}" if config[:debug]
171
+ warn "couldn't detect replication status :#{dict.size}" unless dict.size == 6
172
+ slave_running = %w[Slave_IO_Running Slave_SQL_Running].all? do |key|
173
+ table[key].to_s =~ /Yes/
174
+ end
175
+ output = 'Slave not running!'
176
+ output += ' STATES:'
177
+ output += " Slave_IO_Running=#{table['Slave_IO_Running']}"
178
+ output += ", Slave_SQL_Running=#{table['Slave_SQL_Running']}"
179
+ output += ", LAST ERROR: #{table['Last_SQL_Error']}"
180
+ critical output unless slave_running
181
+ replication_delay = table['Seconds_Behind_Master'].to_i
182
+ message = "replication delayed by #{replication_delay}"
183
+ if replication_delay > config[:warn].to_i && replication_delay <= config[:crit].to_i
184
+ warning message
185
+ elsif replication_delay >= config[:crit].to_i
186
+ critical message
187
+ else
188
+ ok "slave running: #{slave_running}, #{message}"
189
+ end
190
+ end
191
+ ok 'show slave status was nil. This server is not a slave.'
192
+ rescue StandardError => e
193
+ critical "Error message: status: #{status} | Exception: #{e}"
194
+ end
195
+ end
196
+
197
+ def run
198
+ db_user = credentials[0]
199
+ db_pass = credentials[1]
200
+ db_socket = credentials[2]
201
+ if config[:check] == 'status'
202
+ status_check(db_user, db_pass, db_socket)
203
+ end
204
+ if config[:check] == 'replication'
205
+ replication_check(db_user, db_pass, db_socket)
206
+ end
207
+ unknown 'No check type succeeded. Check your options'
208
+ end
209
+ end
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # check-mysql-threads.rb
4
+ #
5
+ # DESCRIPTION:
6
+ # MySQL Threads Health plugin
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
12
+ #
13
+ # OUTPUT:
14
+ # plain text
15
+ #
16
+ # PLATFORMS:
17
+ # All
18
+ #
19
+ # DEPENDENCIES:
20
+ # gem: sensu-plugin
21
+ #
22
+ # USAGE:
23
+ # check-mysql-threads.rb -w [threshold] -c [threshold] -m [threshold] -l [threshold]
24
+ #
25
+ # NOTES:
26
+ #
27
+ # LICENSE:
28
+ # Author: Guillaume Lefranc <guillaume@mariadb.com>
29
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
30
+ # for details.
31
+ #
32
+
33
+ require 'sensu-plugin/check/cli'
34
+ require 'mysql'
35
+ require 'inifile'
36
+
37
+ class CheckMySQLHealth < Sensu::Plugin::Check::CLI
38
+ option :user,
39
+ description: 'MySQL User',
40
+ short: '-u USER',
41
+ long: '--user USER',
42
+ default: 'root'
43
+
44
+ option :password,
45
+ description: 'MySQL Password',
46
+ short: '-p PASS',
47
+ long: '--password PASS'
48
+
49
+ option :ini,
50
+ description: 'My.cnf ini file',
51
+ short: '-i',
52
+ long: '--ini VALUE'
53
+
54
+ option :ini_section,
55
+ description: 'Section in my.cnf ini file',
56
+ long: '--ini-section VALUE',
57
+ default: 'client'
58
+
59
+ option :hostname,
60
+ description: 'Hostname to login to',
61
+ short: '-h HOST',
62
+ long: '--hostname HOST',
63
+ default: 'localhost'
64
+
65
+ option :port,
66
+ description: 'Port to connect to',
67
+ short: '-P PORT',
68
+ long: '--port PORT',
69
+ default: '3306'
70
+
71
+ option :socket,
72
+ description: 'Socket to use',
73
+ short: '-s SOCKET',
74
+ long: '--socket SOCKET'
75
+
76
+ option :maxwarn,
77
+ description: "Number of running threads upon which we'll issue a warning",
78
+ short: '-w NUMBER',
79
+ long: '--warnnum NUMBER',
80
+ default: 20
81
+
82
+ option :maxcrit,
83
+ description: "Number of running threads upon which we'll issue an alert",
84
+ short: '-c NUMBER',
85
+ long: '--critnum NUMBER',
86
+ default: 25
87
+
88
+ option :minwarn,
89
+ description: "Number of running threads under which we'll issue a warning",
90
+ short: '-m NUMBER',
91
+ long: '--warnlow NUMBER',
92
+ default: 1
93
+
94
+ option :mincrit,
95
+ description: "Number of running threads under which we'll issue an alert",
96
+ short: '-l NUMBER',
97
+ long: '--critlow NUMBER',
98
+ default: 0
99
+
100
+ def run
101
+ if config[:ini]
102
+ ini = IniFile.load(config[:ini])
103
+ section = ini[config[:ini_section]]
104
+ db_user = section['user']
105
+ db_pass = section['password']
106
+ else
107
+ db_user = config[:user]
108
+ db_pass = config[:password]
109
+ end
110
+ db = Mysql.real_connect(config[:hostname], db_user, db_pass, config[:database], config[:port].to_i, config[:socket])
111
+ run_thr = db.query("SHOW GLOBAL STATUS LIKE 'Threads_running'").fetch_hash.fetch('Value').to_i
112
+ critical "MySQL currently running threads: #{run_thr}" if run_thr >= config[:maxcrit].to_i
113
+ warning "MySQL currently running threads: #{run_thr}" if run_thr >= config[:maxwarn].to_i
114
+ critical "MySQL currently running threads: #{run_thr}" if run_thr <= config[:mincrit].to_i
115
+ warning "MySQL currently running threads: #{run_thr}" if run_thr <= config[:minwarn].to_i
116
+ ok "Currently running threads are under limit in MySQL: #{run_thr}"
117
+ rescue Mysql::Error => e
118
+ critical "MySQL check failed: #{e.error}"
119
+ ensure
120
+ db.close if db
121
+ end
122
+ end
@@ -0,0 +1,273 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Push mysql stats into graphite
4
+ # ===
5
+ #
6
+ # NOTE: This plugin will attempt to get replication stats but the user
7
+ # must have SUPER or REPLICATION CLIENT privileges to run 'SHOW SLAVE
8
+ # STATUS'. It will silently ignore and continue if 'SHOW SLAVE STATUS'
9
+ # fails for any reason. The key 'slaveLag' will not be present in the
10
+ # output.
11
+ #
12
+ # Copyright 2012 Pete Shima <me@peteshima.com>
13
+ # Additional hacks by Joe Miller - https://github.com/joemiller
14
+ # Updated by Oluwaseun Obajobi 2014 to accept ini argument
15
+ #
16
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
17
+ # for details.
18
+ #
19
+ # USING INI ARGUMENT
20
+ # This was implemented to load mysql credentials without parsing the username/password.
21
+ # The ini file should be readable by the sensu user/group.
22
+ # Ref: http://eric.lubow.org/2009/ruby/parsing-ini-files-with-ruby/
23
+ #
24
+ # EXAMPLE
25
+ # mysql-alive.rb -h db01 --ini '/etc/sensu/my.cnf'
26
+ # mysql-alive.rb -h db01 --ini '/etc/sensu/my.cnf' --ini-section customsection
27
+ #
28
+ # MY.CNF INI FORMAT
29
+ # [client]
30
+ # user=sensu
31
+ # password="abcd1234"
32
+ #
33
+ # [customsection]
34
+ # user=user
35
+ # password="password"
36
+ #
37
+
38
+ require 'sensu-plugin/metric/cli'
39
+ require 'mysql'
40
+ require 'socket'
41
+ require 'inifile'
42
+
43
+ class MysqlGraphite < Sensu::Plugin::Metric::CLI::Graphite
44
+ option :host,
45
+ short: '-h HOST',
46
+ long: '--host HOST',
47
+ description: 'Mysql Host to connect to',
48
+ required: true
49
+
50
+ option :port,
51
+ short: '-P PORT',
52
+ long: '--port PORT',
53
+ description: 'Mysql Port to connect to',
54
+ proc: proc(&:to_i),
55
+ default: 3306
56
+
57
+ option :username,
58
+ short: '-u USERNAME',
59
+ long: '--user USERNAME',
60
+ description: 'Mysql Username'
61
+
62
+ option :password,
63
+ short: '-p PASSWORD',
64
+ long: '--pass PASSWORD',
65
+ description: 'Mysql password',
66
+ default: ''
67
+
68
+ option :ini,
69
+ short: '-i',
70
+ long: '--ini VALUE',
71
+ description: 'My.cnf ini file'
72
+
73
+ option :ini_section,
74
+ description: 'Section in my.cnf ini file',
75
+ long: '--ini-section VALUE',
76
+ default: 'client'
77
+
78
+ option :scheme,
79
+ description: 'Metric naming scheme, text to prepend to metric',
80
+ short: '-s SCHEME',
81
+ long: '--scheme SCHEME',
82
+ default: "#{Socket.gethostname}.mysql"
83
+
84
+ option :socket,
85
+ short: '-S SOCKET',
86
+ long: '--socket SOCKET'
87
+
88
+ option :verbose,
89
+ short: '-v',
90
+ long: '--verbose',
91
+ boolean: true
92
+
93
+ def metrics_hash
94
+ {
95
+ 'general' => {
96
+ 'Bytes_received' => 'rxBytes',
97
+ 'Bytes_sent' => 'txBytes',
98
+ 'Key_read_requests' => 'keyRead_requests',
99
+ 'Key_reads' => 'keyReads',
100
+ 'Key_write_requests' => 'keyWrite_requests',
101
+ 'Key_writes' => 'keyWrites',
102
+ 'Binlog_cache_use' => 'binlogCacheUse',
103
+ 'Binlog_cache_disk_use' => 'binlogCacheDiskUse',
104
+ 'Max_used_connections' => 'maxUsedConnections',
105
+ 'Aborted_clients' => 'abortedClients',
106
+ 'Aborted_connects' => 'abortedConnects',
107
+ 'Threads_connected' => 'threadsConnected',
108
+ 'Open_files' => 'openFiles',
109
+ 'Open_tables' => 'openTables',
110
+ 'Opened_tables' => 'openedTables',
111
+ 'Prepared_stmt_count' => 'preparedStmtCount',
112
+ 'Seconds_Behind_Master' => 'slaveLag',
113
+ 'Select_full_join' => 'fullJoins',
114
+ 'Select_full_range_join' => 'fullRangeJoins',
115
+ 'Select_range' => 'selectRange',
116
+ 'Select_range_check' => 'selectRange_check',
117
+ 'Select_scan' => 'selectScan',
118
+ 'Slow_queries' => 'slowQueries',
119
+ },
120
+ 'querycache' => {
121
+ 'Qcache_queries_in_cache' => 'queriesInCache',
122
+ 'Qcache_hits' => 'cacheHits',
123
+ 'Qcache_inserts' => 'inserts',
124
+ 'Qcache_not_cached' => 'notCached',
125
+ 'Qcache_lowmem_prunes' => 'lowMemPrunes',
126
+ },
127
+ 'commands' => {
128
+ 'Com_admin_commands' => 'admin_commands',
129
+ 'Com_begin' => 'begin',
130
+ 'Com_change_db' => 'change_db',
131
+ 'Com_commit' => 'commit',
132
+ 'Com_create_table' => 'create_table',
133
+ 'Com_drop_table' => 'drop_table',
134
+ 'Com_show_keys' => 'show_keys',
135
+ 'Com_delete' => 'delete',
136
+ 'Com_create_db' => 'create_db',
137
+ 'Com_grant' => 'grant',
138
+ 'Com_show_processlist' => 'show_processlist',
139
+ 'Com_flush' => 'flush',
140
+ 'Com_insert' => 'insert',
141
+ 'Com_purge' => 'purge',
142
+ 'Com_replace' => 'replace',
143
+ 'Com_rollback' => 'rollback',
144
+ 'Com_select' => 'select',
145
+ 'Com_set_option' => 'set_option',
146
+ 'Com_show_binlogs' => 'show_binlogs',
147
+ 'Com_show_databases' => 'show_databases',
148
+ 'Com_show_fields' => 'show_fields',
149
+ 'Com_show_status' => 'show_status',
150
+ 'Com_show_tables' => 'show_tables',
151
+ 'Com_show_variables' => 'show_variables',
152
+ 'Com_update' => 'update',
153
+ 'Com_drop_db' => 'drop_db',
154
+ 'Com_revoke' => 'revoke',
155
+ 'Com_drop_user' => 'drop_user',
156
+ 'Com_show_grants' => 'show_grants',
157
+ 'Com_lock_tables' => 'lock_tables',
158
+ 'Com_show_create_table' => 'show_create_table',
159
+ 'Com_unlock_tables' => 'unlock_tables',
160
+ 'Com_alter_table' => 'alter_table',
161
+ },
162
+ 'counters' => {
163
+ 'Handler_write' => 'handlerWrite',
164
+ 'Handler_update' => 'handlerUpdate',
165
+ 'Handler_delete' => 'handlerDelete',
166
+ 'Handler_read_first' => 'handlerRead_first',
167
+ 'Handler_read_key' => 'handlerRead_key',
168
+ 'Handler_read_next' => 'handlerRead_next',
169
+ 'Handler_read_prev' => 'handlerRead_prev',
170
+ 'Handler_read_rnd' => 'handlerRead_rnd',
171
+ 'Handler_read_rnd_next' => 'handlerRead_rnd_next',
172
+ 'Handler_commit' => 'handlerCommit',
173
+ 'Handler_rollback' => 'handlerRollback',
174
+ 'Handler_savepoint' => 'handlerSavepoint',
175
+ 'Handler_savepoint_rollback' => 'handlerSavepointRollback',
176
+ },
177
+ 'innodb' => {
178
+ 'Innodb_buffer_pool_pages_total' => 'bufferTotal_pages',
179
+ 'Innodb_buffer_pool_pages_free' => 'bufferFree_pages',
180
+ 'Innodb_buffer_pool_pages_dirty' => 'bufferDirty_pages',
181
+ 'Innodb_buffer_pool_pages_data' => 'bufferUsed_pages',
182
+ 'Innodb_page_size' => 'pageSize',
183
+ 'Innodb_pages_created' => 'pagesCreated',
184
+ 'Innodb_pages_read' => 'pagesRead',
185
+ 'Innodb_pages_written' => 'pagesWritten',
186
+ 'Innodb_row_lock_current_waits' => 'currentLockWaits',
187
+ 'Innodb_row_lock_waits' => 'lockWaitTimes',
188
+ 'Innodb_row_lock_time' => 'rowLockTime',
189
+ 'Innodb_data_reads' => 'fileReads',
190
+ 'Innodb_data_writes' => 'fileWrites',
191
+ 'Innodb_data_fsyncs' => 'fileFsyncs',
192
+ 'Innodb_log_writes' => 'logWrites',
193
+ 'Innodb_rows_updated' => 'rowsUpdated',
194
+ 'Innodb_rows_read' => 'rowsRead',
195
+ 'Innodb_rows_deleted' => 'rowsDeleted',
196
+ 'Innodb_rows_inserted' => 'rowsInserted',
197
+ },
198
+ 'configuration' => {
199
+ 'max_connections' => 'MaxConnections',
200
+ 'Max_prepared_stmt_count' => 'MaxPreparedStmtCount',
201
+ },
202
+ }
203
+ end
204
+
205
+ def run
206
+ # props to https://github.com/coredump/hoardd/blob/master/scripts-available/mysql.coffee
207
+
208
+ metrics = metrics_hash
209
+
210
+ # FIXME: break this up
211
+ config[:host].split(' ').each do |mysql_host| # rubocop:disable Metrics/BlockLength
212
+ mysql_shorthostname = mysql_host.split('.')[0]
213
+ if config[:ini]
214
+ ini = IniFile.load(config[:ini])
215
+ section = ini[config[:ini_section]]
216
+ db_user = section['user']
217
+ db_pass = section['password']
218
+ else
219
+ db_user = config[:username]
220
+ db_pass = config[:password]
221
+ end
222
+ begin
223
+ mysql = Mysql.new(mysql_host, db_user, db_pass, nil, config[:port], config[:socket])
224
+
225
+ results = mysql.query('SHOW GLOBAL STATUS')
226
+ rescue StandardError => e
227
+ puts e.message
228
+ end
229
+
230
+ results.each_hash do |row|
231
+ metrics.each do |category, var_mapping|
232
+ if var_mapping.key?(row['Variable_name'])
233
+ output "#{config[:scheme]}.#{mysql_shorthostname}.#{category}.#{var_mapping[row['Variable_name']]}", row['Value']
234
+ end
235
+ end
236
+ end
237
+
238
+ begin
239
+ slave_results = mysql.query('SHOW SLAVE STATUS')
240
+ # should return a single element array containing one hash
241
+ # #YELLOW
242
+ slave_results.fetch_hash.each_pair do |key, value|
243
+ if metrics['general'].include?(key)
244
+ # Replication lag being null is bad, very bad, so negativate it here
245
+ value = -1 if key == 'Seconds_Behind_Master' && value.nil?
246
+ output "#{config[:scheme]}.#{mysql_shorthostname}.general.#{metrics['general'][key]}", value
247
+ end
248
+ end
249
+ rescue StandardError => e
250
+ puts "Error querying slave status: #{e}" if config[:verbose]
251
+ end
252
+
253
+ begin
254
+ variables_results = mysql.query('SHOW GLOBAL VARIABLES')
255
+
256
+ category = 'configuration'
257
+ variables_results.each_hash do |row|
258
+ metrics[category].each do |metric, desc|
259
+ if metric.casecmp(row['Variable_name']).zero?
260
+ output "#{config[:scheme]}.#{mysql_shorthostname}.#{category}.#{desc}", row['Value']
261
+ end
262
+ end
263
+ end
264
+ rescue StandardError => e
265
+ puts e.message
266
+ end
267
+
268
+ mysql.close if mysql
269
+ end
270
+
271
+ ok
272
+ end
273
+ end