sensu-plugins-mysql-boutetnico 1.0.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 +7 -0
- data/CHANGELOG.md +1 -0
- data/LICENSE +22 -0
- data/README.md +161 -0
- data/bin/check-mysql-alive.rb +102 -0
- data/bin/check-mysql-connections.rb +110 -0
- data/bin/check-mysql-disk.rb +137 -0
- data/bin/check-mysql-innodb-lock.rb +148 -0
- data/bin/check-mysql-msr-replication-status.rb +157 -0
- data/bin/check-mysql-query-result-count.rb +110 -0
- data/bin/check-mysql-replication-status.rb +185 -0
- data/bin/check-mysql-select-count.rb +113 -0
- data/bin/check-mysql-status.rb +209 -0
- data/bin/check-mysql-threads.rb +122 -0
- data/bin/metrics-mysql-graphite.rb +273 -0
- data/bin/metrics-mysql-multiple-select-count.rb +110 -0
- data/bin/metrics-mysql-processes.rb +149 -0
- data/bin/metrics-mysql-query-result-count.rb +97 -0
- data/bin/metrics-mysql-raw.rb +397 -0
- data/bin/metrics-mysql-select-count.rb +99 -0
- data/bin/metrics-mysql.rb +58 -0
- data/bin/mysql-metrics.sql +15 -0
- data/lib/sensu-plugins-mysql.rb +1 -0
- data/lib/sensu-plugins-mysql/version.rb +9 -0
- metadata +262 -0
@@ -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
|