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,142 @@
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
+ # mysql-alive.rb -h db01 --ini '/etc/sensu/my.cnf' --ini-section customsection
29
+ #
30
+ # MY.CNF INI FORMAT
31
+ # [client]
32
+ # user=sensu
33
+ # password="abcd1234"
34
+ #
35
+ # [customsection]
36
+ # user=user
37
+ # password="password"
38
+ #
39
+ # NOTES:
40
+ #
41
+ # LICENSE:
42
+ # Jonathan Ballet <jballet@edgelab.ch>
43
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
44
+ # for details.
45
+
46
+ require 'sensu-plugin/metric/cli'
47
+ require 'mysql'
48
+ require 'socket'
49
+ require 'inifile'
50
+
51
+ class MetricsMySQLProcesses < Sensu::Plugin::Metric::CLI::Graphite
52
+ option :host,
53
+ short: '-h HOST',
54
+ long: '--host HOST',
55
+ description: 'MySQL Host to connect to',
56
+ required: true
57
+
58
+ option :port,
59
+ short: '-P PORT',
60
+ long: '--port PORT',
61
+ description: 'MySQL Port to connect to',
62
+ proc: proc(&:to_i),
63
+ default: 3306
64
+
65
+ option :username,
66
+ short: '-u USERNAME',
67
+ long: '--user USERNAME',
68
+ description: 'MySQL Username'
69
+
70
+ option :password,
71
+ short: '-p PASSWORD',
72
+ long: '--pass PASSWORD',
73
+ description: 'MySQL password',
74
+ default: ''
75
+
76
+ option :ini,
77
+ short: '-i',
78
+ long: '--ini VALUE',
79
+ description: 'My.cnf ini file'
80
+
81
+ option :ini_section,
82
+ description: 'Section in my.cnf ini file',
83
+ long: '--ini-section VALUE',
84
+ default: 'client'
85
+
86
+ option :scheme,
87
+ description: 'Metric naming scheme, text to prepend to metric',
88
+ short: '-s SCHEME',
89
+ long: '--scheme SCHEME',
90
+ default: "#{Socket.gethostname}.mysql"
91
+
92
+ option :socket,
93
+ short: '-S SOCKET',
94
+ long: '--socket SOCKET',
95
+ description: 'MySQL Unix socket to connect to'
96
+
97
+ def run
98
+ config[:host].split(' ').each do |mysql_host|
99
+ mysql_shorthostname = mysql_host.split('.')[0]
100
+ if config[:ini]
101
+ ini = IniFile.load(config[:ini])
102
+ section = ini[config[:ini_section]]
103
+ db_user = section['user']
104
+ db_pass = section['password']
105
+ else
106
+ db_user = config[:username]
107
+ db_pass = config[:password]
108
+ end
109
+ begin
110
+ mysql = Mysql.new(mysql_host, db_user, db_pass, nil, config[:port], config[:socket])
111
+
112
+ results = mysql.query('SHOW PROCESSLIST')
113
+ rescue => e
114
+ unknown "Unable to query MySQL: #{e.message}"
115
+ end
116
+
117
+ metrics = {
118
+ 'user' => {},
119
+ 'database' => {},
120
+ 'command' => {}
121
+ }
122
+
123
+ metrics.each_value { |value| value.default = 0 }
124
+
125
+ results.each_hash do |row|
126
+ metrics['user'][row['User']] += 1
127
+ if row['db'] # If no database has been selected by the process, it is set to nil.
128
+ metrics['database'][row['db']] += 1
129
+ end
130
+ metrics['command'][row['Command']] += 1
131
+ end
132
+
133
+ metrics.each do |key, value|
134
+ value.each do |instance, count|
135
+ output "#{config[:scheme]}.#{mysql_shorthostname}.#{key}.#{instance}", count
136
+ end
137
+ end
138
+ end
139
+
140
+ ok
141
+ end
142
+ end
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # MySQL Query Result Count Metric
4
+ #
5
+ # Creates a graphite-formatted metric for the length of a result set from a MySQL query.
6
+ #
7
+ # Copyright 2017 Andrew Thal <athal7@me.com>
8
+ #
9
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
10
+ # for details.
11
+
12
+ require 'sensu-plugin/metric/cli'
13
+ require 'mysql'
14
+ require 'inifile'
15
+
16
+ class MysqlQueryCountMetric < Sensu::Plugin::Metric::CLI::Graphite
17
+ option :host,
18
+ short: '-h HOST',
19
+ long: '--host HOST',
20
+ description: 'MySQL Host to connect to',
21
+ required: true
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
+ default: ''
40
+
41
+ option :database,
42
+ short: '-d DATABASE',
43
+ long: '--database DATABASE',
44
+ description: 'MySQL database',
45
+ default: ''
46
+
47
+ option :ini,
48
+ short: '-i',
49
+ long: '--ini VALUE',
50
+ description: 'My.cnf ini file'
51
+
52
+ option :ini_section,
53
+ description: 'Section in my.cnf ini file',
54
+ long: '--ini-section VALUE',
55
+ default: 'client'
56
+
57
+ option :socket,
58
+ short: '-S SOCKET',
59
+ long: '--socket SOCKET',
60
+ description: 'MySQL Unix socket to connect to'
61
+
62
+ option :name,
63
+ short: '-n NAME',
64
+ long: '--name NAME',
65
+ description: 'Metric name for a configured handler',
66
+ default: 'mysql.query_count'
67
+
68
+ option :query,
69
+ short: '-q QUERY',
70
+ long: '--query QUERY',
71
+ description: 'Query to execute',
72
+ required: true
73
+
74
+ def run
75
+ if config[:ini]
76
+ ini = IniFile.load(config[:ini])
77
+ section = ini[config[:ini_section]]
78
+ db_user = section['user']
79
+ db_pass = section['password']
80
+ else
81
+ db_user = config[:username]
82
+ db_pass = config[:password]
83
+ end
84
+ db = Mysql.real_connect(config[:host], db_user, db_pass, config[:database], config[:port].to_i, config[:socket])
85
+ length = db.query(config[:query]).count
86
+
87
+ output config[:name], length
88
+ ok
89
+
90
+ rescue Mysql::Error => e
91
+ errstr = "Error code: #{e.errno} Error message: #{e.error}"
92
+ critical "#{errstr} SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
93
+
94
+ rescue => e
95
+ critical e
96
+
97
+ ensure
98
+ db.close if db
99
+ end
100
+ end
@@ -0,0 +1,396 @@
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
+ # metrics-mysql-raw.rb -h localhost --ini '/etc/sensu/my.cnf' --ini-section customsection
20
+ #
21
+ # MY.CNF INI FORMAT
22
+ # [client]
23
+ # user=sensu
24
+ # password="abcd1234"
25
+ # socket="/var/lib/mysql/mysql.sock"
26
+ #
27
+ # [customsection]
28
+ # user=user
29
+ # password="password"
30
+ #
31
+ # LICENSE:
32
+ # Copyright 2012 Pete Shima <me@peteshima.com>
33
+ # Additional hacks by Joe Miller - https://github.com/joemiller
34
+ # Updated by Oluwaseun Obajobi 2014 to accept ini argument
35
+ # Forked by Magic Online 11.2016 to not depend on mysql gem
36
+ # - www.magic.fr <hanynowsky@gmail.com>
37
+ # MIT - Same as Sensu License
38
+ #
39
+
40
+ require 'sensu-plugin/metric/cli'
41
+ require 'open3'
42
+ require 'socket'
43
+ require 'inifile'
44
+ require 'timeout'
45
+
46
+ #
47
+ # Metrics Mysql Raw
48
+ #
49
+ class MetricsMySQLRaw < Sensu::Plugin::Metric::CLI::Graphite
50
+ option(
51
+ :user,
52
+ description: 'MySQL User',
53
+ short: '-u USER',
54
+ long: '--user USER',
55
+ default: 'mosim'
56
+ )
57
+
58
+ option(
59
+ :password,
60
+ description: 'MySQL Password',
61
+ short: '-p PASS',
62
+ long: '--password PASS',
63
+ default: 'mysqlPassWord'
64
+ )
65
+
66
+ option(
67
+ :ini,
68
+ description: 'My.cnf ini file',
69
+ short: '-i',
70
+ long: '--ini VALUE'
71
+ )
72
+
73
+ option(
74
+ :ini_section,
75
+ description: 'Section in my.cnf ini file',
76
+ long: '--ini-section VALUE',
77
+ default: 'client'
78
+ )
79
+
80
+ option(
81
+ :hostname,
82
+ description: 'Hostname to login to',
83
+ short: '-h HOST',
84
+ long: '--hostname HOST',
85
+ default: 'localhost'
86
+ )
87
+
88
+ option(
89
+ :database,
90
+ description: 'Database schema to connect to. NOT YET IMPlemented',
91
+ short: '-d DATABASE',
92
+ long: '--database DATABASE',
93
+ default: 'test'
94
+ )
95
+
96
+ option(
97
+ :timeout,
98
+ description: 'Timeout',
99
+ short: '-T TIMEOUT',
100
+ long: '--timeout TIMEOUT',
101
+ default: 10
102
+ )
103
+
104
+ option(
105
+ :port,
106
+ description: 'Port to connect to',
107
+ short: '-P PORT',
108
+ long: '--port PORT',
109
+ default: '3306'
110
+ )
111
+
112
+ option(
113
+ :socket,
114
+ description: 'Socket to use',
115
+ short: '-s SOCKET',
116
+ long: '--socket SOCKET',
117
+ default: '/var/run/mysqld/mysqld.sock'
118
+ )
119
+
120
+ option(
121
+ :binary,
122
+ description: 'Absolute path to mysql binary',
123
+ short: '-b BINARY',
124
+ long: '--binary BINARY',
125
+ default: 'mysql'
126
+ )
127
+
128
+ option(
129
+ :check,
130
+ description: 'type of check: metric',
131
+ short: '-c CHECK',
132
+ long: '--check CHECK',
133
+ default: 'metric'
134
+ )
135
+
136
+ option(
137
+ :scheme,
138
+ description: 'Metric naming scheme, text to prepend to metric',
139
+ short: '-s SCHEME',
140
+ long: '--scheme SCHEME',
141
+ default: "#{Socket.gethostname}.mysql"
142
+ )
143
+
144
+ option(
145
+ :verbose,
146
+ short: '-v',
147
+ long: '--verbose',
148
+ boolean: true
149
+ )
150
+
151
+ option(
152
+ :off,
153
+ description: 'Turn Metrics OFF',
154
+ long: '--off',
155
+ boolean: true,
156
+ default: false
157
+ )
158
+
159
+ # Metrics hash
160
+ def metrics_hash
161
+ metrics = {
162
+ 'general' => {
163
+ 'Bytes_received' => 'rxBytes',
164
+ 'Bytes_sent' => 'txBytes',
165
+ 'Key_read_requests' => 'keyRead_requests',
166
+ 'Key_reads' => 'keyReads',
167
+ 'Key_write_requests' => 'keyWrite_requests',
168
+ 'Key_writes' => 'keyWrites',
169
+ 'Binlog_cache_use' => 'binlogCacheUse',
170
+ 'Binlog_cache_disk_use' => 'binlogCacheDiskUse',
171
+ 'Max_used_connections' => 'maxUsedConnections',
172
+ 'Aborted_clients' => 'abortedClients',
173
+ 'Aborted_connects' => 'abortedConnects',
174
+ 'Threads_connected' => 'threadsConnected',
175
+ 'Open_files' => 'openFiles',
176
+ 'Open_tables' => 'openTables',
177
+ 'Opened_tables' => 'openedTables',
178
+ 'Prepared_stmt_count' => 'preparedStmtCount',
179
+ 'Seconds_Behind_Master' => 'slaveLag',
180
+ 'Select_full_join' => 'fullJoins',
181
+ 'Select_full_range_join' => 'fullRangeJoins',
182
+ 'Select_range' => 'selectRange',
183
+ 'Select_range_check' => 'selectRange_check',
184
+ 'Select_scan' => 'selectScan',
185
+ 'Slow_queries' => 'slowQueries'
186
+ },
187
+ 'querycache' => {
188
+ 'Qcache_queries_in_cache' => 'queriesInCache',
189
+ 'Qcache_hits' => 'cacheHits',
190
+ 'Qcache_inserts' => 'inserts',
191
+ 'Qcache_not_cached' => 'notCached',
192
+ 'Qcache_lowmem_prunes' => 'lowMemPrunes',
193
+ 'Qcache_free_memory' => 'freeMemory'
194
+ },
195
+ 'commands' => {
196
+ 'Com_admin_commands' => 'admin_commands',
197
+ 'Com_begin' => 'begin',
198
+ 'Com_change_db' => 'change_db',
199
+ 'Com_commit' => 'commit',
200
+ 'Com_create_table' => 'create_table',
201
+ 'Com_drop_table' => 'drop_table',
202
+ 'Com_show_keys' => 'show_keys',
203
+ 'Com_delete' => 'delete',
204
+ 'Com_create_db' => 'create_db',
205
+ 'Com_grant' => 'grant',
206
+ 'Com_show_processlist' => 'show_processlist',
207
+ 'Com_flush' => 'flush',
208
+ 'Com_insert' => 'insert',
209
+ 'Com_purge' => 'purge',
210
+ 'Com_replace' => 'replace',
211
+ 'Com_rollback' => 'rollback',
212
+ 'Com_select' => 'select',
213
+ 'Com_set_option' => 'set_option',
214
+ 'Com_show_binlogs' => 'show_binlogs',
215
+ 'Com_show_databases' => 'show_databases',
216
+ 'Com_show_fields' => 'show_fields',
217
+ 'Com_show_status' => 'show_status',
218
+ 'Com_show_tables' => 'show_tables',
219
+ 'Com_show_variables' => 'show_variables',
220
+ 'Com_update' => 'update',
221
+ 'Com_drop_db' => 'drop_db',
222
+ 'Com_revoke' => 'revoke',
223
+ 'Com_drop_user' => 'drop_user',
224
+ 'Com_show_grants' => 'show_grants',
225
+ 'Com_lock_tables' => 'lock_tables',
226
+ 'Com_show_create_table' => 'show_create_table',
227
+ 'Com_unlock_tables' => 'unlock_tables',
228
+ 'Com_alter_table' => 'alter_table'
229
+ },
230
+ 'counters' => {
231
+ 'Handler_write' => 'handlerWrite',
232
+ 'Handler_update' => 'handlerUpdate',
233
+ 'Handler_delete' => 'handlerDelete',
234
+ 'Handler_read_first' => 'handlerRead_first',
235
+ 'Handler_read_key' => 'handlerRead_key',
236
+ 'Handler_read_next' => 'handlerRead_next',
237
+ 'Handler_read_prev' => 'handlerRead_prev',
238
+ 'Handler_read_rnd' => 'handlerRead_rnd',
239
+ 'Handler_read_rnd_next' => 'handlerRead_rnd_next',
240
+ 'Handler_commit' => 'handlerCommit',
241
+ 'Handler_rollback' => 'handlerRollback',
242
+ 'Handler_savepoint' => 'handlerSavepoint',
243
+ 'Handler_savepoint_rollback' => 'handlerSavepointRollback'
244
+ },
245
+ 'innodb' => {
246
+ 'Innodb_buffer_pool_pages_total' => 'bufferTotal_pages',
247
+ 'Innodb_buffer_pool_pages_free' => 'bufferFree_pages',
248
+ 'Innodb_buffer_pool_pages_dirty' => 'bufferDirty_pages',
249
+ 'Innodb_buffer_pool_pages_data' => 'bufferUsed_pages',
250
+ 'Innodb_page_size' => 'pageSize',
251
+ 'Innodb_pages_created' => 'pagesCreated',
252
+ 'Innodb_pages_read' => 'pagesRead',
253
+ 'Innodb_pages_written' => 'pagesWritten',
254
+ 'Innodb_row_lock_current_waits' => 'currentLockWaits',
255
+ 'Innodb_row_lock_waits' => 'lockWaitTimes',
256
+ 'Innodb_row_lock_time' => 'rowLockTime',
257
+ 'Innodb_data_reads' => 'fileReads',
258
+ 'Innodb_data_writes' => 'fileWrites',
259
+ 'Innodb_data_fsyncs' => 'fileFsyncs',
260
+ 'Innodb_log_writes' => 'logWrites',
261
+ 'Innodb_rows_updated' => 'rowsUpdated',
262
+ 'Innodb_rows_read' => 'rowsRead',
263
+ 'Innodb_rows_deleted' => 'rowsDeleted',
264
+ 'Innodb_rows_inserted' => 'rowsInserted'
265
+ },
266
+ 'configuration' => {
267
+ 'Max_prepared_stmt_count' => 'MaxPreparedStmtCount'
268
+ }
269
+ }
270
+ metrics
271
+ end
272
+
273
+ # Credentials
274
+ def credentials
275
+ if config[:ini]
276
+ ini = IniFile.load(config[:ini])
277
+ section = ini[config[:ini_section]]
278
+ db_user = section['user']
279
+ db_pass = section['password']
280
+ db_socket = section['socket']
281
+ else
282
+ db_user = config[:user]
283
+ db_pass = config[:password]
284
+ db_socket = config[:socket]
285
+ end
286
+ [db_user, db_pass, db_socket]
287
+ end
288
+
289
+ # Slave metrics
290
+ def slave_metrics(metrics)
291
+ # should return a single element array containing one hash
292
+ # #YELLOW
293
+ mysql_shorthostname = config[:hostname].tr('.', '_')
294
+ slave_results = Hash['a' => 100, 'b' => 200]
295
+ slave_results.first.each do |key, value|
296
+ if metrics['general'].include?(key)
297
+ # Replication lag being null is bad, very bad, so negativate it here
298
+ value = -1 if key == 'Seconds_Behind_Master' && value.nil?
299
+ output "#{config[:scheme]}.#{mysql_shorthostname}.general.#{metrics['general'][key]}", value
300
+ end
301
+ end
302
+ rescue => e
303
+ puts "Error querying slave status: #{e}" if config[:verbose]
304
+ end
305
+
306
+ # Configuration metrics
307
+ def configuration_metrics(metrics, db_user, db_pass, db_socket)
308
+ mysql_shorthostname = config[:hostname].tr('.', '_')
309
+ table = []
310
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} \
311
+ --port #{config[:port]} --socket #{db_socket} -p\"#{db_pass.chomp}\" --batch \
312
+ --disable-column-names -e 'SHOW GLOBAL VARIABLES;'"
313
+ stdout, _stderr, status = Open3.capture3(cmd)
314
+ puts status.to_s.split(' ')[3] if config[:verbose]
315
+ if status == 0
316
+ puts status.to_s if config[:verbose]
317
+ stdout.split("\n").each do |row|
318
+ line = row.tr("\t", ':')
319
+ key = line.split(':')[0]
320
+ value = line.split(':')[1]
321
+ table.push('Variable_name' => key, 'Value' => value)
322
+ end
323
+ else
324
+ critical "Error message: Global variables - status: #{status}"
325
+ end
326
+ variables_results = table
327
+ category = 'configuration'
328
+ variables_results.each do |row|
329
+ metrics[category].each do |metric, desc|
330
+ if metric.casecmp(row['Variable_name']) == 0
331
+ output "#{config[:scheme]}.#{mysql_shorthostname}.#{category}.#{desc}", row['Value']
332
+ end
333
+ end
334
+ end
335
+ rescue => e
336
+ puts e.message
337
+ end
338
+
339
+ # Fetch MySQL metrics
340
+ def fetcher(db_user, db_pass, db_socket)
341
+ metrics = metrics_hash
342
+ if config[:check] == 'metric'
343
+ mysql_shorthostname = config[:hostname].tr('.', '_')
344
+ begin
345
+ table = []
346
+ cmd = "#{config[:binary]} -u #{db_user} -h #{config[:hostname]} \
347
+ --port #{config[:port]} --socket #{db_socket} -p\"#{db_pass.chomp}\" --batch \
348
+ --disable-column-names -e 'SHOW GLOBAL STATUS;'"
349
+ stdout, _stderr, status = Open3.capture3(cmd)
350
+ puts status.to_s.split(' ')[3] if config[:verbose]
351
+ if status == 0
352
+ puts status.to_s if config[:verbose]
353
+ stdout.split("\n").each do |row|
354
+ line = row.tr("\t", ':')
355
+ key = line.split(':')[0]
356
+ value = line.split(':')[1]
357
+ table.push('Variable_name' => key, 'Value' => value)
358
+ end
359
+ else
360
+ critical "Error message: status: #{status}"
361
+ end
362
+ table.each do |row|
363
+ metrics.each do |category, var_mapping|
364
+ row_var_name = row['Variable_name'].to_s
365
+ var_mapping.keys.each do |vmkey|
366
+ if row_var_name.to_s == vmkey.to_s
367
+ prefix = "#{config[:scheme]}.#{mysql_shorthostname}.#{category}.#{vmkey[row_var_name]}"
368
+ output prefix, row['Value'] unless mysql_shorthostname.to_s.chomp.empty?
369
+ end
370
+ end
371
+ end
372
+ end
373
+ # Slave and configuration metrics here
374
+ slave_metrics(metrics)
375
+ configuration_metrics(metrics, db_user, db_pass, db_socket)
376
+ rescue => e
377
+ critical "Error message: status: #{status} | Exception: #{e.backtrace}"
378
+ ensure
379
+ ok ''
380
+ end
381
+ end
382
+ end
383
+
384
+ # Main Function
385
+ def run
386
+ ok 'Metrics deactivated by user using option --off' if config[:off] == true
387
+ begin
388
+ Timeout.timeout(config[:timeout]) do
389
+ fetcher(credentials[0], credentials[1], credentials[2])
390
+ end
391
+ rescue Timeout::Error => e
392
+ unknown "Timed out #{e.message}"
393
+ end
394
+ unknown 'Did not succeed to retrieve MySQL metrics. Check your options'
395
+ end
396
+ end