sensu-plugins-mysql-nagyt 2.6.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.
@@ -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,268 @@
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 run
94
+ # props to https://github.com/coredump/hoardd/blob/master/scripts-available/mysql.coffee
95
+
96
+ metrics = {
97
+ 'general' => {
98
+ 'Bytes_received' => 'rxBytes',
99
+ 'Bytes_sent' => 'txBytes',
100
+ 'Key_read_requests' => 'keyRead_requests',
101
+ 'Key_reads' => 'keyReads',
102
+ 'Key_write_requests' => 'keyWrite_requests',
103
+ 'Key_writes' => 'keyWrites',
104
+ 'Binlog_cache_use' => 'binlogCacheUse',
105
+ 'Binlog_cache_disk_use' => 'binlogCacheDiskUse',
106
+ 'Max_used_connections' => 'maxUsedConnections',
107
+ 'Aborted_clients' => 'abortedClients',
108
+ 'Aborted_connects' => 'abortedConnects',
109
+ 'Threads_connected' => 'threadsConnected',
110
+ 'Open_files' => 'openFiles',
111
+ 'Open_tables' => 'openTables',
112
+ 'Opened_tables' => 'openedTables',
113
+ 'Prepared_stmt_count' => 'preparedStmtCount',
114
+ 'Seconds_Behind_Master' => 'slaveLag',
115
+ 'Select_full_join' => 'fullJoins',
116
+ 'Select_full_range_join' => 'fullRangeJoins',
117
+ 'Select_range' => 'selectRange',
118
+ 'Select_range_check' => 'selectRange_check',
119
+ 'Select_scan' => 'selectScan',
120
+ 'Slow_queries' => 'slowQueries'
121
+ },
122
+ 'querycache' => {
123
+ 'Qcache_queries_in_cache' => 'queriesInCache',
124
+ 'Qcache_hits' => 'cacheHits',
125
+ 'Qcache_inserts' => 'inserts',
126
+ 'Qcache_not_cached' => 'notCached',
127
+ 'Qcache_lowmem_prunes' => 'lowMemPrunes'
128
+ },
129
+ 'commands' => {
130
+ 'Com_admin_commands' => 'admin_commands',
131
+ 'Com_begin' => 'begin',
132
+ 'Com_change_db' => 'change_db',
133
+ 'Com_commit' => 'commit',
134
+ 'Com_create_table' => 'create_table',
135
+ 'Com_drop_table' => 'drop_table',
136
+ 'Com_show_keys' => 'show_keys',
137
+ 'Com_delete' => 'delete',
138
+ 'Com_create_db' => 'create_db',
139
+ 'Com_grant' => 'grant',
140
+ 'Com_show_processlist' => 'show_processlist',
141
+ 'Com_flush' => 'flush',
142
+ 'Com_insert' => 'insert',
143
+ 'Com_purge' => 'purge',
144
+ 'Com_replace' => 'replace',
145
+ 'Com_rollback' => 'rollback',
146
+ 'Com_select' => 'select',
147
+ 'Com_set_option' => 'set_option',
148
+ 'Com_show_binlogs' => 'show_binlogs',
149
+ 'Com_show_databases' => 'show_databases',
150
+ 'Com_show_fields' => 'show_fields',
151
+ 'Com_show_status' => 'show_status',
152
+ 'Com_show_tables' => 'show_tables',
153
+ 'Com_show_variables' => 'show_variables',
154
+ 'Com_update' => 'update',
155
+ 'Com_drop_db' => 'drop_db',
156
+ 'Com_revoke' => 'revoke',
157
+ 'Com_drop_user' => 'drop_user',
158
+ 'Com_show_grants' => 'show_grants',
159
+ 'Com_lock_tables' => 'lock_tables',
160
+ 'Com_show_create_table' => 'show_create_table',
161
+ 'Com_unlock_tables' => 'unlock_tables',
162
+ 'Com_alter_table' => 'alter_table'
163
+ },
164
+ 'counters' => {
165
+ 'Handler_write' => 'handlerWrite',
166
+ 'Handler_update' => 'handlerUpdate',
167
+ 'Handler_delete' => 'handlerDelete',
168
+ 'Handler_read_first' => 'handlerRead_first',
169
+ 'Handler_read_key' => 'handlerRead_key',
170
+ 'Handler_read_next' => 'handlerRead_next',
171
+ 'Handler_read_prev' => 'handlerRead_prev',
172
+ 'Handler_read_rnd' => 'handlerRead_rnd',
173
+ 'Handler_read_rnd_next' => 'handlerRead_rnd_next',
174
+ 'Handler_commit' => 'handlerCommit',
175
+ 'Handler_rollback' => 'handlerRollback',
176
+ 'Handler_savepoint' => 'handlerSavepoint',
177
+ 'Handler_savepoint_rollback' => 'handlerSavepointRollback'
178
+ },
179
+ 'innodb' => {
180
+ 'Innodb_buffer_pool_pages_total' => 'bufferTotal_pages',
181
+ 'Innodb_buffer_pool_pages_free' => 'bufferFree_pages',
182
+ 'Innodb_buffer_pool_pages_dirty' => 'bufferDirty_pages',
183
+ 'Innodb_buffer_pool_pages_data' => 'bufferUsed_pages',
184
+ 'Innodb_page_size' => 'pageSize',
185
+ 'Innodb_pages_created' => 'pagesCreated',
186
+ 'Innodb_pages_read' => 'pagesRead',
187
+ 'Innodb_pages_written' => 'pagesWritten',
188
+ 'Innodb_row_lock_current_waits' => 'currentLockWaits',
189
+ 'Innodb_row_lock_waits' => 'lockWaitTimes',
190
+ 'Innodb_row_lock_time' => 'rowLockTime',
191
+ 'Innodb_data_reads' => 'fileReads',
192
+ 'Innodb_data_writes' => 'fileWrites',
193
+ 'Innodb_data_fsyncs' => 'fileFsyncs',
194
+ 'Innodb_log_writes' => 'logWrites',
195
+ 'Innodb_rows_updated' => 'rowsUpdated',
196
+ 'Innodb_rows_read' => 'rowsRead',
197
+ 'Innodb_rows_deleted' => 'rowsDeleted',
198
+ 'Innodb_rows_inserted' => 'rowsInserted'
199
+ },
200
+ 'configuration' => {
201
+ 'max_connections' => 'MaxConnections',
202
+ 'Max_prepared_stmt_count' => 'MaxPreparedStmtCount'
203
+ }
204
+ }
205
+
206
+ config[:host].split(' ').each do |mysql_host|
207
+ mysql_shorthostname = mysql_host.split('.')[0]
208
+ if config[:ini]
209
+ ini = IniFile.load(config[:ini])
210
+ section = ini[config[:ini_section]]
211
+ db_user = section['user']
212
+ db_pass = section['password']
213
+ else
214
+ db_user = config[:username]
215
+ db_pass = config[:password]
216
+ end
217
+ begin
218
+ mysql = Mysql.new(mysql_host, db_user, db_pass, nil, config[:port], config[:socket])
219
+
220
+ results = mysql.query('SHOW GLOBAL STATUS')
221
+ rescue => e
222
+ puts e.message
223
+ end
224
+
225
+ results.each_hash do |row|
226
+ metrics.each do |category, var_mapping|
227
+ if var_mapping.key?(row['Variable_name'])
228
+ output "#{config[:scheme]}.#{mysql_shorthostname}.#{category}.#{var_mapping[row['Variable_name']]}", row['Value']
229
+ end
230
+ end
231
+ end
232
+
233
+ begin
234
+ slave_results = mysql.query('SHOW SLAVE STATUS')
235
+ # should return a single element array containing one hash
236
+ # #YELLOW
237
+ slave_results.fetch_hash.each_pair do |key, value|
238
+ if metrics['general'].include?(key)
239
+ # Replication lag being null is bad, very bad, so negativate it here
240
+ value = -1 if key == 'Seconds_Behind_Master' && value.nil?
241
+ output "#{config[:scheme]}.#{mysql_shorthostname}.general.#{metrics['general'][key]}", value
242
+ end
243
+ end
244
+ rescue => e
245
+ puts "Error querying slave status: #{e}" if config[:verbose]
246
+ end
247
+
248
+ begin
249
+ variables_results = mysql.query('SHOW GLOBAL VARIABLES')
250
+
251
+ category = 'configuration'
252
+ variables_results.each_hash do |row|
253
+ metrics[category].each do |metric, desc|
254
+ if metric.casecmp(row['Variable_name']) == 0
255
+ output "#{config[:scheme]}.#{mysql_shorthostname}.#{category}.#{desc}", row['Value']
256
+ end
257
+ end
258
+ end
259
+ rescue => e
260
+ puts e.message
261
+ end
262
+
263
+ mysql.close if mysql
264
+ end
265
+
266
+ ok
267
+ end
268
+ end
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # MySQL Select Count Metric
4
+ #
5
+ # Creates a graphite-formatted metric for the first value of a result set from a MySQL query.
6
+ #
7
+ # Copyright 2017 Andrew Thal <athal7@me.com>
8
+ # Copyright 2018 Tibor Nagy <nagyt@hu.inter.net>
9
+ #
10
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
11
+ # for details.
12
+
13
+ require 'sensu-plugin/metric/cli'
14
+ require 'mysql'
15
+ require 'inifile'
16
+ require 'json'
17
+
18
+ class MysqlQueryCountMetric < Sensu::Plugin::Metric::CLI::Graphite
19
+ option :host,
20
+ short: '-h HOST',
21
+ long: '--host HOST',
22
+ description: 'MySQL Host to connect to',
23
+ required: true
24
+
25
+ option :port,
26
+ short: '-P PORT',
27
+ long: '--port PORT',
28
+ description: 'MySQL Port to connect to',
29
+ proc: proc(&:to_i),
30
+ default: 3306
31
+
32
+ option :username,
33
+ short: '-u USERNAME',
34
+ long: '--user USERNAME',
35
+ description: 'MySQL Username'
36
+
37
+ option :password,
38
+ short: '-p PASSWORD',
39
+ long: '--pass PASSWORD',
40
+ description: 'MySQL password'
41
+
42
+ option :database,
43
+ short: '-d DATABASE',
44
+ long: '--database DATABASE',
45
+ description: 'MySQL database',
46
+ default: ''
47
+
48
+ option :ini,
49
+ short: '-i',
50
+ long: '--ini VALUE',
51
+ description: 'My.cnf ini file'
52
+
53
+ option :ini_section,
54
+ description: 'Section in my.cnf ini file',
55
+ long: '--ini-section VALUE',
56
+ default: 'client'
57
+
58
+ option :socket,
59
+ short: '-S SOCKET',
60
+ long: '--socket SOCKET',
61
+ description: 'MySQL Unix socket to connect to'
62
+
63
+ option :name,
64
+ short: '-n NAME',
65
+ long: '--name NAME',
66
+ description: 'Metric name for a configured handler',
67
+ default: 'mysql.query_count'
68
+
69
+ option :query,
70
+ short: '-q SELECT_COUNT_QUERY',
71
+ long: '--query SELECT_COUNT_QUERY',
72
+ description: 'Queries to execute in JSON',
73
+ required: true
74
+
75
+ def run
76
+ if config[:ini]
77
+ ini = IniFile.load(config[:ini])
78
+ section = ini[config[:ini_section]]
79
+ db_user = section['user']
80
+ db_pass = section['password']
81
+ else
82
+ db_user = config[:username]
83
+ db_pass = config[:password]
84
+ end
85
+
86
+ begin
87
+ query_hash = ::JSON.parse config[:query]
88
+ rescue ::JSON::ParserError => e
89
+ critical "JSON.parse error: #{e}"
90
+ end
91
+
92
+ # traverse all SQL
93
+ query_hash.each do |key, sql|
94
+ raise "invalid query : #{sql}" unless sql =~ /^select\s+count\(\s*\*\s*\)/i
95
+
96
+ db = Mysql.real_connect(config[:host], db_user, db_pass, config[:database], config[:port], config[:socket])
97
+ count = db.query(sql).fetch_row[0].to_i
98
+
99
+ output "#{config[:name]}.#{key}", count
100
+ end
101
+
102
+ ok
103
+
104
+ rescue Mysql::Error => e
105
+ errstr = "Error code: #{e.errno} Error message: #{e.error}"
106
+ critical "#{errstr} SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
107
+
108
+ rescue StandardError => e
109
+ critical "unhandled exception: #{e}"
110
+
111
+ end
112
+ end