summaryrefslogtreecommitdiffstats
path: root/plugins/check_mysql.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_mysql.c')
-rw-r--r--plugins/check_mysql.c377
1 files changed, 243 insertions, 134 deletions
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c
index ca3422b5..9d8094c0 100644
--- a/plugins/check_mysql.c
+++ b/plugins/check_mysql.c
@@ -30,13 +30,11 @@
30 * 30 *
31 *****************************************************************************/ 31 *****************************************************************************/
32 32
33const char *progname = "check_mysql";
34const char *copyright = "1999-2024";
35const char *email = "devel@monitoring-plugins.org";
36
37#define REPLICA_RESULTSIZE 96
38
39#include "common.h" 33#include "common.h"
34#include "output.h"
35#include "perfdata.h"
36#include "states.h"
37#include "thresholds.h"
40#include "utils.h" 38#include "utils.h"
41#include "utils_base.h" 39#include "utils_base.h"
42#include "netutils.h" 40#include "netutils.h"
@@ -46,19 +44,33 @@ const char *email = "devel@monitoring-plugins.org";
46#include <mysqld_error.h> 44#include <mysqld_error.h>
47#include <errmsg.h> 45#include <errmsg.h>
48 46
47const char *progname = "check_mysql";
48const char *copyright = "1999-2024";
49const char *email = "devel@monitoring-plugins.org";
50
49static int verbose = 0; 51static int verbose = 0;
50 52
53#define REPLICA_RESULTSIZE 96
54
51#define LENGTH_METRIC_UNIT 6 55#define LENGTH_METRIC_UNIT 6
52static const char *metric_unit[LENGTH_METRIC_UNIT] = { 56static const char *metric_unit[LENGTH_METRIC_UNIT] = {
53 "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", "Threads_connected", "Threads_running"}; 57 "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache",
58 "Threads_connected", "Threads_running"};
54 59
55#define LENGTH_METRIC_COUNTER 9 60#define LENGTH_METRIC_COUNTER 9
56static const char *metric_counter[LENGTH_METRIC_COUNTER] = { 61static const char *metric_counter[LENGTH_METRIC_COUNTER] = {"Connections",
57 "Connections", "Qcache_hits", "Qcache_inserts", "Qcache_lowmem_prunes", "Qcache_not_cached", "Queries", 62 "Qcache_hits",
58 "Questions", "Table_locks_waited", "Uptime"}; 63 "Qcache_inserts",
59 64 "Qcache_lowmem_prunes",
60#define MYSQLDUMP_THREADS_QUERY \ 65 "Qcache_not_cached",
61 "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'" 66 "Queries",
67 "Questions",
68 "Table_locks_waited",
69 "Uptime"};
70
71#define MYSQLDUMP_THREADS_QUERY \
72 "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE " \
73 "'SELECT /*!40001 SQL_NO_CACHE */%'"
62 74
63typedef struct { 75typedef struct {
64 int errorcode; 76 int errorcode;
@@ -99,82 +111,130 @@ int main(int argc, char **argv) {
99 } 111 }
100 112
101 if (config.ssl) { 113 if (config.ssl) {
102 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, config.ciphers); 114 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir,
115 config.ciphers);
103 } 116 }
104 /* establish a connection to the server and error checking */ 117
105 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) { 118 mp_check overall = mp_check_init();
119
120 mp_subcheck sc_connection = mp_subcheck_init();
121 /* establish a connection to the server and check for errors */
122 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db,
123 config.db_port, config.db_socket, 0)) {
106 /* Depending on internally-selected auth plugin MySQL might return */ 124 /* Depending on internally-selected auth plugin MySQL might return */
107 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */ 125 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
108 /* Semantically these errors are the same. */ 126 /* Semantically these errors are the same. */
109 if (config.ignore_auth && 127 if (config.ignore_auth && (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR ||
110 (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) { 128 mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
111 printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql)); 129 xasprintf(&sc_connection.output, "Version: %s (protocol %d)",
112 mysql_close(&mysql); 130 mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql));
113 return STATE_OK; 131 sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK);
114 }
115 132
116 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { 133 mysql_close(&mysql);
117 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
118 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
119 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
120 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
121 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
122 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
123 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
124 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
125 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
126 } else { 134 } else {
127 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 135 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
136 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
137 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
138 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
139 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
140 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
141 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
142 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
143 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
144 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
145 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
146 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
147 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
148 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
149 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
150 } else {
151 sc_connection = mp_set_subcheck_state(sc_connection, STATE_CRITICAL);
152 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
153 }
128 } 154 }
155
156 mp_add_subcheck_to_check(&overall, sc_connection);
157 mp_exit(overall);
158 } else {
159 // successful connection
160 sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK);
161 xasprintf(&sc_connection.output, "Version: %s (protocol %d)", mysql_get_server_info(&mysql),
162 mysql_get_proto_info(&mysql));
163 mp_add_subcheck_to_check(&overall, sc_connection);
129 } 164 }
130 165
131 /* get the server stats */ 166 /* get the server stats */
132 char *result = strdup(mysql_stat(&mysql)); 167 char *mysql_stats = strdup(mysql_stat(&mysql));
168
169 mp_subcheck sc_stats = mp_subcheck_init();
170 sc_stats = mp_set_subcheck_default_state(sc_stats, STATE_OK);
133 171
134 /* error checking once more */ 172 /* error checking once more */
135 if (mysql_error(&mysql)) { 173 if (mysql_errno(&mysql) != 0) {
136 if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) { 174 if ((mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) ||
137 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 175 (mysql_errno(&mysql) == CR_SERVER_LOST) || (mysql_errno(&mysql) == CR_UNKNOWN_ERROR)) {
138 } else if (mysql_errno(&mysql) == CR_SERVER_LOST) { 176 sc_stats = mp_set_subcheck_state(sc_stats, STATE_CRITICAL);
139 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 177 xasprintf(&sc_stats.output, "Retrieving stats failed: %s", mysql_error(&mysql));
140 } else if (mysql_errno(&mysql) == CR_UNKNOWN_ERROR) { 178 } else {
141 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 179 // not sure which error modes occur here, but mysql_error indicates an error
180 sc_stats = mp_set_subcheck_state(sc_stats, STATE_WARNING);
181 xasprintf(&sc_stats.output, "retrieving stats caused an error: %s",
182 mysql_error(&mysql));
142 } 183 }
184
185 mp_add_subcheck_to_check(&overall, sc_stats);
186 mp_exit(overall);
187 } else {
188 xasprintf(&sc_stats.output, "retrieved stats: %s", mysql_stats);
189 sc_stats = mp_set_subcheck_state(sc_stats, STATE_OK);
190 mp_add_subcheck_to_check(&overall, sc_stats);
143 } 191 }
144 192
145 char *perf = strdup("");
146 char *error = NULL;
147 MYSQL_RES *res; 193 MYSQL_RES *res;
148 MYSQL_ROW row; 194 MYSQL_ROW row;
195 mp_subcheck sc_query = mp_subcheck_init();
149 /* try to fetch some perf data */ 196 /* try to fetch some perf data */
150 if (mysql_query(&mysql, "show global status") == 0) { 197 if (mysql_query(&mysql, "show global status") == 0) {
151 if ((res = mysql_store_result(&mysql)) == NULL) { 198 if ((res = mysql_store_result(&mysql)) == NULL) {
152 error = strdup(mysql_error(&mysql)); 199 xasprintf(&sc_connection.output, "query failed - status store_result error: %s",
200 mysql_error(&mysql));
153 mysql_close(&mysql); 201 mysql_close(&mysql);
154 die(STATE_CRITICAL, _("status store_result error: %s\n"), error); 202
203 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
204 mp_add_subcheck_to_check(&overall, sc_query);
205 mp_exit(overall);
155 } 206 }
156 207
157 while ((row = mysql_fetch_row(res)) != NULL) { 208 while ((row = mysql_fetch_row(res)) != NULL) {
158 for (int i = 0; i < LENGTH_METRIC_UNIT; i++) { 209 for (int i = 0; i < LENGTH_METRIC_UNIT; i++) {
159 if (strcmp(row[0], metric_unit[i]) == 0) { 210 if (strcmp(row[0], metric_unit[i]) == 0) {
160 xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false, 0, false, 0)); 211 mp_perfdata pd_mysql_stat = perfdata_init();
212 pd_mysql_stat.label = (char *)metric_unit[i];
213 pd_mysql_stat.value = mp_create_pd_value(atol(row[1]));
214 mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat);
161 continue; 215 continue;
162 } 216 }
163 } 217 }
218
164 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) { 219 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) {
165 if (strcmp(row[0], metric_counter[i]) == 0) { 220 if (strcmp(row[0], metric_counter[i]) == 0) {
166 xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0)); 221 mp_perfdata pd_mysql_stat = perfdata_init();
222 pd_mysql_stat.label = (char *)metric_counter[i];
223 pd_mysql_stat.value = mp_create_pd_value(atol(row[1]));
224 pd_mysql_stat.uom = "c";
225 mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat);
167 continue; 226 continue;
168 } 227 }
169 } 228 }
170 } 229 }
171 /* remove trailing space */ 230 } else {
172 if (strlen(perf) > 0) { 231 // Query failed!
173 perf[strlen(perf) - 1] = '\0'; 232 xasprintf(&sc_connection.output, "query failed");
174 } 233 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
234 mp_add_subcheck_to_check(&overall, sc_query);
235 mp_exit(overall);
175 } 236 }
176 237
177 char replica_result[REPLICA_RESULTSIZE] = {0};
178 if (config.check_replica) { 238 if (config.check_replica) {
179 // Detect which version we are, on older version 239 // Detect which version we are, on older version
180 // "show slave status" should work, on newer ones 240 // "show slave status" should work, on newer ones
@@ -188,9 +248,11 @@ int main(int argc, char **argv) {
188 unsigned long major_version = server_verion_int / 10000; 248 unsigned long major_version = server_verion_int / 10000;
189 unsigned long minor_version = (server_verion_int % 10000) / 100; 249 unsigned long minor_version = (server_verion_int % 10000) / 100;
190 unsigned long patch_version = (server_verion_int % 100); 250 unsigned long patch_version = (server_verion_int % 100);
251
191 if (verbose) { 252 if (verbose) {
192 printf("Found MariaDB: %s, main version: %lu, minor version: %lu, patch version: %lu\n", server_version, major_version, 253 printf("Found MariaDB/MySQL: %s, main version: %lu, minor version: %lu, patch version: "
193 minor_version, patch_version); 254 "%lu\n",
255 server_version, major_version, minor_version, patch_version);
194 } 256 }
195 257
196 if (strstr(server_version, "MariaDB") != NULL) { 258 if (strstr(server_version, "MariaDB") != NULL) {
@@ -204,16 +266,13 @@ int main(int argc, char **argv) {
204 use_deprecated_slave_status = true; 266 use_deprecated_slave_status = true;
205 } 267 }
206 } 268 }
207 } else if (strstr(server_version, "MySQL") != NULL) { 269 } else {
208 // Looks like MySQL 270 // Looks like MySQL or at least not like MariaDB
209 if (major_version < 8) { 271 if (major_version < 8) {
210 use_deprecated_slave_status = true; 272 use_deprecated_slave_status = true;
211 } else if (major_version == 10 && minor_version < 4) { 273 } else if (major_version == 10 && minor_version < 4) {
212 use_deprecated_slave_status = true; 274 use_deprecated_slave_status = true;
213 } 275 }
214 } else {
215 printf("Not a known sever implementation: %s\n", server_version);
216 exit(STATE_UNKNOWN);
217 } 276 }
218 277
219 char *replica_query = NULL; 278 char *replica_query = NULL;
@@ -223,43 +282,60 @@ int main(int argc, char **argv) {
223 replica_query = "show replica status"; 282 replica_query = "show replica status";
224 } 283 }
225 284
285 mp_subcheck sc_replica = mp_subcheck_init();
286
226 /* check the replica status */ 287 /* check the replica status */
227 if (mysql_query(&mysql, replica_query) != 0) { 288 if (mysql_query(&mysql, replica_query) != 0) {
228 error = strdup(mysql_error(&mysql)); 289 xasprintf(&sc_replica.output, "replica query error: %s", mysql_error(&mysql));
229 mysql_close(&mysql); 290 mysql_close(&mysql);
230 die(STATE_CRITICAL, _("replica query error: %s\n"), error); 291
292 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
293 mp_add_subcheck_to_check(&overall, sc_replica);
294 mp_exit(overall);
231 } 295 }
232 296
233 /* store the result */ 297 /* store the result */
234 if ((res = mysql_store_result(&mysql)) == NULL) { 298 if ((res = mysql_store_result(&mysql)) == NULL) {
235 error = strdup(mysql_error(&mysql)); 299 xasprintf(&sc_replica.output, "replica store_result error: %s", mysql_error(&mysql));
236 mysql_close(&mysql); 300 mysql_close(&mysql);
237 die(STATE_CRITICAL, _("replica store_result error: %s\n"), error); 301
302 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
303 mp_add_subcheck_to_check(&overall, sc_replica);
304 mp_exit(overall);
238 } 305 }
239 306
240 /* Check there is some data */ 307 /* Check there is some data */
241 if (mysql_num_rows(res) == 0) { 308 if (mysql_num_rows(res) == 0) {
242 mysql_close(&mysql); 309 mysql_close(&mysql);
243 die(STATE_WARNING, "%s\n", _("No replicas defined")); 310
311 xasprintf(&sc_replica.output, "no replicas defined");
312 sc_replica = mp_set_subcheck_state(sc_replica, STATE_WARNING);
313 mp_add_subcheck_to_check(&overall, sc_replica);
314 mp_exit(overall);
244 } 315 }
245 316
246 /* fetch the first row */ 317 /* fetch the first row */
247 if ((row = mysql_fetch_row(res)) == NULL) { 318 if ((row = mysql_fetch_row(res)) == NULL) {
248 error = strdup(mysql_error(&mysql)); 319 xasprintf(&sc_replica.output, "replica fetch row error: %s", mysql_error(&mysql));
249 mysql_free_result(res); 320 mysql_free_result(res);
250 mysql_close(&mysql); 321 mysql_close(&mysql);
251 die(STATE_CRITICAL, _("replica fetch row error: %s\n"), error); 322
323 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
324 mp_add_subcheck_to_check(&overall, sc_replica);
325 mp_exit(overall);
252 } 326 }
253 327
254 if (mysql_field_count(&mysql) == 12) { 328 if (mysql_field_count(&mysql) == 12) {
255 /* mysql 3.23.x */ 329 /* mysql 3.23.x */
256 snprintf(replica_result, REPLICA_RESULTSIZE, _("Replica running: %s"), row[6]); 330 xasprintf(&sc_replica.output, "Replica running: %s", row[6]);
257 if (strcmp(row[6], "Yes") != 0) { 331 if (strcmp(row[6], "Yes") != 0) {
258 mysql_free_result(res); 332 mysql_free_result(res);
259 mysql_close(&mysql); 333 mysql_close(&mysql);
260 die(STATE_CRITICAL, "%s\n", replica_result);
261 }
262 334
335 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
336 mp_add_subcheck_to_check(&overall, sc_replica);
337 mp_exit(overall);
338 }
263 } else { 339 } else {
264 /* mysql 4.x.x and mysql 5.x.x */ 340 /* mysql 4.x.x and mysql 5.x.x */
265 int replica_io_field = -1; 341 int replica_io_field = -1;
@@ -270,17 +346,32 @@ int main(int argc, char **argv) {
270 num_fields = mysql_num_fields(res); 346 num_fields = mysql_num_fields(res);
271 fields = mysql_fetch_fields(res); 347 fields = mysql_fetch_fields(res);
272 for (int i = 0; i < num_fields; i++) { 348 for (int i = 0; i < num_fields; i++) {
273 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) { 349 if (use_deprecated_slave_status) {
274 replica_io_field = i; 350 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
275 continue; 351 replica_io_field = i;
276 } 352 continue;
277 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) { 353 }
278 replica_sql_field = i; 354 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) {
279 continue; 355 replica_sql_field = i;
280 } 356 continue;
281 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) { 357 }
282 seconds_behind_field = i; 358 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) {
283 continue; 359 seconds_behind_field = i;
360 continue;
361 }
362 } else {
363 if (strcmp(fields[i].name, "Replica_IO_Running") == 0) {
364 replica_io_field = i;
365 continue;
366 }
367 if (strcmp(fields[i].name, "Replica_SQL_Running") == 0) {
368 replica_sql_field = i;
369 continue;
370 }
371 if (strcmp(fields[i].name, "Seconds_Behind_Source") == 0) {
372 seconds_behind_field = i;
373 continue;
374 }
284 } 375 }
285 } 376 }
286 377
@@ -288,15 +379,23 @@ int main(int argc, char **argv) {
288 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) { 379 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) {
289 mysql_free_result(res); 380 mysql_free_result(res);
290 mysql_close(&mysql); 381 mysql_close(&mysql);
291 die(STATE_CRITICAL, "Replica status unavailable\n"); 382
383 xasprintf(&sc_replica.output, "Replica status unavailable");
384 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
385 mp_add_subcheck_to_check(&overall, sc_replica);
386 mp_exit(overall);
292 } 387 }
293 388
294 /* Save replica status in replica_result */ 389 /* Save replica status in replica_result */
295 snprintf(replica_result, REPLICA_RESULTSIZE, "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s", row[replica_io_field], 390 xasprintf(&sc_replica.output,
296 row[replica_sql_field], seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown"); 391 "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s",
297 392 row[replica_io_field], row[replica_sql_field],
298 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */ 393 seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown");
299 if (strcmp(row[replica_io_field], "Yes") != 0 || strcmp(row[replica_sql_field], "Yes") != 0) { 394
395 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no
396 * mysqldump threads running */
397 if (strcmp(row[replica_io_field], "Yes") != 0 ||
398 strcmp(row[replica_sql_field], "Yes") != 0) {
300 MYSQL_RES *res_mysqldump; 399 MYSQL_RES *res_mysqldump;
301 MYSQL_ROW row_mysqldump; 400 MYSQL_ROW row_mysqldump;
302 unsigned int mysqldump_threads = 0; 401 unsigned int mysqldump_threads = 0;
@@ -314,10 +413,14 @@ int main(int argc, char **argv) {
314 } 413 }
315 mysql_close(&mysql); 414 mysql_close(&mysql);
316 } 415 }
416
317 if (mysqldump_threads == 0) { 417 if (mysqldump_threads == 0) {
318 die(STATE_CRITICAL, "%s\n", replica_result); 418 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
419 mp_add_subcheck_to_check(&overall, sc_replica);
420 mp_exit(overall);
319 } else { 421 } else {
320 strncat(replica_result, " Mysqldump: in progress", REPLICA_RESULTSIZE - 1); 422 xasprintf(&sc_replica.output, "%s %s", sc_replica.output,
423 " Mysqldump: in progress");
321 } 424 }
322 } 425 }
323 426
@@ -325,27 +428,30 @@ int main(int argc, char **argv) {
325 if (seconds_behind_field == -1) { 428 if (seconds_behind_field == -1) {
326 printf("seconds_behind_field not found\n"); 429 printf("seconds_behind_field not found\n");
327 } else { 430 } else {
328 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]); 431 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field,
432 row[seconds_behind_field]);
329 } 433 }
330 } 434 }
331 435
332 /* Check Seconds Behind against threshold */ 436 /* Check Seconds Behind against threshold */
333 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp(row[seconds_behind_field], "NULL") != 0)) { 437 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL &&
334 double value = atof(row[seconds_behind_field]); 438 strcmp(row[seconds_behind_field], "NULL") != 0)) {
335 int status; 439 mp_perfdata pd_seconds_behind = perfdata_init();
336 440 pd_seconds_behind.label = "seconds behind master";
337 status = get_status(value, config.my_threshold); 441 pd_seconds_behind.value = mp_create_pd_value(atof(row[seconds_behind_field]));
338 442 pd_seconds_behind =
339 xasprintf(&perf, "%s %s", perf, 443 mp_pd_set_thresholds(pd_seconds_behind, config.replica_thresholds);
340 fperfdata("seconds behind master", value, "s", true, (double)config.warning_time, true, 444 pd_seconds_behind.uom = "s";
341 (double)config.critical_time, false, 0, false, 0)); 445 mp_add_perfdata_to_subcheck(&sc_replica, pd_seconds_behind);
342 446
343 if (status == STATE_WARNING) { 447 mp_state_enum status = mp_get_pd_status(pd_seconds_behind);
344 printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf); 448
345 exit(STATE_WARNING); 449 sc_replica = mp_set_subcheck_state(sc_replica, status);
346 } else if (status == STATE_CRITICAL) { 450
347 printf("SLOW_REPLICA %s: %s|%s\n", _("CRITICAL"), replica_result, perf); 451 if (status != STATE_OK) {
348 exit(STATE_CRITICAL); 452 xasprintf(&sc_replica.output, "slow replica - %s", sc_replica.output);
453 mp_add_subcheck_to_check(&overall, sc_replica);
454 mp_exit(overall);
349 } 455 }
350 } 456 }
351 } 457 }
@@ -357,20 +463,16 @@ int main(int argc, char **argv) {
357 /* close the connection */ 463 /* close the connection */
358 mysql_close(&mysql); 464 mysql_close(&mysql);
359 465
360 /* print out the result of stats */ 466 mp_exit(overall);
361 if (config.check_replica) {
362 printf("%s %s|%s\n", result, replica_result, perf);
363 } else {
364 printf("%s|%s\n", result, perf);
365 }
366
367 return STATE_OK;
368} 467}
369 468
370#define CHECK_REPLICA_OPT CHAR_MAX + 1
371
372/* process command-line arguments */ 469/* process command-line arguments */
373check_mysql_config_wrapper process_arguments(int argc, char **argv) { 470check_mysql_config_wrapper process_arguments(int argc, char **argv) {
471
472 enum {
473 CHECK_REPLICA_OPT = CHAR_MAX + 1,
474 };
475
374 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 476 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
375 {"socket", required_argument, 0, 's'}, 477 {"socket", required_argument, 0, 's'},
376 {"database", required_argument, 0, 'd'}, 478 {"database", required_argument, 0, 'd'},
@@ -405,12 +507,10 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
405 return result; 507 return result;
406 } 508 }
407 509
408 char *warning = NULL;
409 char *critical = NULL;
410
411 int option = 0; 510 int option = 0;
412 while (true) { 511 while (true) {
413 int option_index = getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option); 512 int option_index =
513 getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
414 514
415 if (option_index == -1 || option_index == EOF) { 515 if (option_index == -1 || option_index == EOF) {
416 break; 516 break;
@@ -478,14 +578,22 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
478 case 'n': 578 case 'n':
479 result.config.ignore_auth = true; /* ignore-auth */ 579 result.config.ignore_auth = true; /* ignore-auth */
480 break; 580 break;
481 case 'w': 581 case 'w': {
482 warning = optarg; 582 mp_range_parsed tmp = mp_parse_range_string(optarg);
483 result.config.warning_time = strtod(warning, NULL); 583 if (tmp.error != MP_PARSING_SUCCES) {
484 break; 584 die(STATE_UNKNOWN, "failed to parse warning time threshold");
485 case 'c': 585 }
486 critical = optarg; 586 result.config.replica_thresholds =
487 result.config.critical_time = strtod(critical, NULL); 587 mp_thresholds_set_warn(result.config.replica_thresholds, tmp.range);
488 break; 588 } break;
589 case 'c': {
590 mp_range_parsed tmp = mp_parse_range_string(optarg);
591 if (tmp.error != MP_PARSING_SUCCES) {
592 die(STATE_UNKNOWN, "failed to parse critical time threshold");
593 }
594 result.config.replica_thresholds =
595 mp_thresholds_set_crit(result.config.replica_thresholds, tmp.range);
596 } break;
489 case 'V': /* version */ 597 case 'V': /* version */
490 print_revision(progname, NP_VERSION); 598 print_revision(progname, NP_VERSION);
491 exit(STATE_UNKNOWN); 599 exit(STATE_UNKNOWN);
@@ -502,8 +610,6 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
502 610
503 int index = optind; 611 int index = optind;
504 612
505 set_thresholds(&result.config.my_threshold, warning, critical);
506
507 while (argc > index) { 613 while (argc > index) {
508 if (result.config.db_host == NULL) { 614 if (result.config.db_host == NULL) {
509 if (is_host(argv[index])) { 615 if (is_host(argv[index])) {
@@ -580,15 +686,17 @@ void print_help(void) {
580 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 686 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
581 printf(" %s\n", _("Your clear-text password could be visible as a process table entry")); 687 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
582 printf(" %s\n", "-S, --check-slave"); 688 printf(" %s\n", "-S, --check-slave");
583 printf(" %s\n", 689 printf(" %s\n", _("Check if the slave thread is running properly. This option is deprecated "
584 _("Check if the slave thread is running properly. This option is deprecated in favour of check-replica, which does the same")); 690 "in favour of check-replica, which does the same"));
585 printf(" %s\n", "--check-replica"); 691 printf(" %s\n", "--check-replica");
586 printf(" %s\n", _("Check if the replica thread is running properly.")); 692 printf(" %s\n", _("Check if the replica thread is running properly."));
587 printf(" %s\n", "-w, --warning"); 693 printf(" %s\n", "-w, --warning");
588 printf(" %s\n", _("Exit with WARNING status if replica server is more than INTEGER seconds")); 694 printf(" %s\n",
695 _("Exit with WARNING status if replica server is more than INTEGER seconds"));
589 printf(" %s\n", _("behind master")); 696 printf(" %s\n", _("behind master"));
590 printf(" %s\n", "-c, --critical"); 697 printf(" %s\n", "-c, --critical");
591 printf(" %s\n", _("Exit with CRITICAL status if replica server is more then INTEGER seconds")); 698 printf(" %s\n",
699 _("Exit with CRITICAL status if replica server is more then INTEGER seconds"));
592 printf(" %s\n", _("behind master")); 700 printf(" %s\n", _("behind master"));
593 printf(" %s\n", "-l, --ssl"); 701 printf(" %s\n", "-l, --ssl");
594 printf(" %s\n", _("Use ssl encryption")); 702 printf(" %s\n", _("Use ssl encryption"));
@@ -604,7 +712,8 @@ void print_help(void) {
604 printf(" %s\n", _("List of valid SSL ciphers")); 712 printf(" %s\n", _("List of valid SSL ciphers"));
605 713
606 printf("\n"); 714 printf("\n");
607 printf(" %s\n", _("There are no required arguments. By default, the local database is checked")); 715 printf(" %s\n",
716 _("There are no required arguments. By default, the local database is checked"));
608 printf(" %s\n", _("using the default unix socket. You can force TCP on localhost by using an")); 717 printf(" %s\n", _("using the default unix socket. You can force TCP on localhost by using an"));
609 printf(" %s\n", _("IP address or FQDN ('localhost' will use the socket as well).")); 718 printf(" %s\n", _("IP address or FQDN ('localhost' will use the socket as well)."));
610 719