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.c376
1 files changed, 245 insertions, 131 deletions
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c
index ca3422b5..26730d4c 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;
@@ -84,6 +96,10 @@ int main(int argc, char **argv) {
84 96
85 const check_mysql_config config = tmp_config.config; 97 const check_mysql_config config = tmp_config.config;
86 98
99 if (config.output_format_is_set) {
100 mp_set_format(config.output_format);
101 }
102
87 MYSQL mysql; 103 MYSQL mysql;
88 /* initialize mysql */ 104 /* initialize mysql */
89 mysql_init(&mysql); 105 mysql_init(&mysql);
@@ -99,82 +115,130 @@ int main(int argc, char **argv) {
99 } 115 }
100 116
101 if (config.ssl) { 117 if (config.ssl) {
102 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, config.ciphers); 118 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir,
119 config.ciphers);
103 } 120 }
104 /* establish a connection to the server and error checking */ 121
105 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) { 122 mp_check overall = mp_check_init();
123
124 mp_subcheck sc_connection = mp_subcheck_init();
125 /* establish a connection to the server and check for errors */
126 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db,
127 config.db_port, config.db_socket, 0)) {
106 /* Depending on internally-selected auth plugin MySQL might return */ 128 /* Depending on internally-selected auth plugin MySQL might return */
107 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */ 129 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
108 /* Semantically these errors are the same. */ 130 /* Semantically these errors are the same. */
109 if (config.ignore_auth && 131 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)) { 132 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)); 133 xasprintf(&sc_connection.output, "Version: %s (protocol %d)",
112 mysql_close(&mysql); 134 mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql));
113 return STATE_OK; 135 sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK);
114 }
115 136
116 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { 137 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 { 138 } else {
127 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 139 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
140 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
141 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
142 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
143 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
144 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
145 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
146 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
147 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
148 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
149 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
150 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
151 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
152 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
153 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
154 } else {
155 sc_connection = mp_set_subcheck_state(sc_connection, STATE_CRITICAL);
156 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
157 }
128 } 158 }
159
160 mp_add_subcheck_to_check(&overall, sc_connection);
161 mp_exit(overall);
162 } else {
163 // successful connection
164 sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK);
165 xasprintf(&sc_connection.output, "Version: %s (protocol %d)", mysql_get_server_info(&mysql),
166 mysql_get_proto_info(&mysql));
167 mp_add_subcheck_to_check(&overall, sc_connection);
129 } 168 }
130 169
131 /* get the server stats */ 170 /* get the server stats */
132 char *result = strdup(mysql_stat(&mysql)); 171 char *mysql_stats = strdup(mysql_stat(&mysql));
172
173 mp_subcheck sc_stats = mp_subcheck_init();
174 sc_stats = mp_set_subcheck_default_state(sc_stats, STATE_OK);
133 175
134 /* error checking once more */ 176 /* error checking once more */
135 if (mysql_error(&mysql)) { 177 if (mysql_errno(&mysql) != 0) {
136 if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) { 178 if ((mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) ||
137 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 179 (mysql_errno(&mysql) == CR_SERVER_LOST) || (mysql_errno(&mysql) == CR_UNKNOWN_ERROR)) {
138 } else if (mysql_errno(&mysql) == CR_SERVER_LOST) { 180 sc_stats = mp_set_subcheck_state(sc_stats, STATE_CRITICAL);
139 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 181 xasprintf(&sc_stats.output, "Retrieving stats failed: %s", mysql_error(&mysql));
140 } else if (mysql_errno(&mysql) == CR_UNKNOWN_ERROR) { 182 } else {
141 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 183 // not sure which error modes occur here, but mysql_error indicates an error
184 sc_stats = mp_set_subcheck_state(sc_stats, STATE_WARNING);
185 xasprintf(&sc_stats.output, "retrieving stats caused an error: %s",
186 mysql_error(&mysql));
142 } 187 }
188
189 mp_add_subcheck_to_check(&overall, sc_stats);
190 mp_exit(overall);
191 } else {
192 xasprintf(&sc_stats.output, "retrieved stats: %s", mysql_stats);
193 sc_stats = mp_set_subcheck_state(sc_stats, STATE_OK);
194 mp_add_subcheck_to_check(&overall, sc_stats);
143 } 195 }
144 196
145 char *perf = strdup("");
146 char *error = NULL;
147 MYSQL_RES *res; 197 MYSQL_RES *res;
148 MYSQL_ROW row; 198 MYSQL_ROW row;
199 mp_subcheck sc_query = mp_subcheck_init();
149 /* try to fetch some perf data */ 200 /* try to fetch some perf data */
150 if (mysql_query(&mysql, "show global status") == 0) { 201 if (mysql_query(&mysql, "show global status") == 0) {
151 if ((res = mysql_store_result(&mysql)) == NULL) { 202 if ((res = mysql_store_result(&mysql)) == NULL) {
152 error = strdup(mysql_error(&mysql)); 203 xasprintf(&sc_connection.output, "query failed - status store_result error: %s",
204 mysql_error(&mysql));
153 mysql_close(&mysql); 205 mysql_close(&mysql);
154 die(STATE_CRITICAL, _("status store_result error: %s\n"), error); 206
207 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
208 mp_add_subcheck_to_check(&overall, sc_query);
209 mp_exit(overall);
155 } 210 }
156 211
157 while ((row = mysql_fetch_row(res)) != NULL) { 212 while ((row = mysql_fetch_row(res)) != NULL) {
158 for (int i = 0; i < LENGTH_METRIC_UNIT; i++) { 213 for (int i = 0; i < LENGTH_METRIC_UNIT; i++) {
159 if (strcmp(row[0], metric_unit[i]) == 0) { 214 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)); 215 mp_perfdata pd_mysql_stat = perfdata_init();
216 pd_mysql_stat.label = (char *)metric_unit[i];
217 pd_mysql_stat.value = mp_create_pd_value(atol(row[1]));
218 mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat);
161 continue; 219 continue;
162 } 220 }
163 } 221 }
222
164 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) { 223 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) {
165 if (strcmp(row[0], metric_counter[i]) == 0) { 224 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)); 225 mp_perfdata pd_mysql_stat = perfdata_init();
226 pd_mysql_stat.label = (char *)metric_counter[i];
227 pd_mysql_stat.value = mp_create_pd_value(atol(row[1]));
228 pd_mysql_stat.uom = "c";
229 mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat);
167 continue; 230 continue;
168 } 231 }
169 } 232 }
170 } 233 }
171 /* remove trailing space */ 234 } else {
172 if (strlen(perf) > 0) { 235 // Query failed!
173 perf[strlen(perf) - 1] = '\0'; 236 xasprintf(&sc_connection.output, "query failed");
174 } 237 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
238 mp_add_subcheck_to_check(&overall, sc_query);
239 mp_exit(overall);
175 } 240 }
176 241
177 char replica_result[REPLICA_RESULTSIZE] = {0};
178 if (config.check_replica) { 242 if (config.check_replica) {
179 // Detect which version we are, on older version 243 // Detect which version we are, on older version
180 // "show slave status" should work, on newer ones 244 // "show slave status" should work, on newer ones
@@ -188,9 +252,11 @@ int main(int argc, char **argv) {
188 unsigned long major_version = server_verion_int / 10000; 252 unsigned long major_version = server_verion_int / 10000;
189 unsigned long minor_version = (server_verion_int % 10000) / 100; 253 unsigned long minor_version = (server_verion_int % 10000) / 100;
190 unsigned long patch_version = (server_verion_int % 100); 254 unsigned long patch_version = (server_verion_int % 100);
255
191 if (verbose) { 256 if (verbose) {
192 printf("Found MariaDB: %s, main version: %lu, minor version: %lu, patch version: %lu\n", server_version, major_version, 257 printf("Found MariaDB/MySQL: %s, main version: %lu, minor version: %lu, patch version: "
193 minor_version, patch_version); 258 "%lu\n",
259 server_version, major_version, minor_version, patch_version);
194 } 260 }
195 261
196 if (strstr(server_version, "MariaDB") != NULL) { 262 if (strstr(server_version, "MariaDB") != NULL) {
@@ -204,16 +270,13 @@ int main(int argc, char **argv) {
204 use_deprecated_slave_status = true; 270 use_deprecated_slave_status = true;
205 } 271 }
206 } 272 }
207 } else if (strstr(server_version, "MySQL") != NULL) { 273 } else {
208 // Looks like MySQL 274 // Looks like MySQL or at least not like MariaDB
209 if (major_version < 8) { 275 if (major_version < 8) {
210 use_deprecated_slave_status = true; 276 use_deprecated_slave_status = true;
211 } else if (major_version == 10 && minor_version < 4) { 277 } else if (major_version == 10 && minor_version < 4) {
212 use_deprecated_slave_status = true; 278 use_deprecated_slave_status = true;
213 } 279 }
214 } else {
215 printf("Not a known sever implementation: %s\n", server_version);
216 exit(STATE_UNKNOWN);
217 } 280 }
218 281
219 char *replica_query = NULL; 282 char *replica_query = NULL;
@@ -223,62 +286,80 @@ int main(int argc, char **argv) {
223 replica_query = "show replica status"; 286 replica_query = "show replica status";
224 } 287 }
225 288
289 mp_subcheck sc_replica = mp_subcheck_init();
290
226 /* check the replica status */ 291 /* check the replica status */
227 if (mysql_query(&mysql, replica_query) != 0) { 292 if (mysql_query(&mysql, replica_query) != 0) {
228 error = strdup(mysql_error(&mysql)); 293 xasprintf(&sc_replica.output, "replica query error: %s", mysql_error(&mysql));
229 mysql_close(&mysql); 294 mysql_close(&mysql);
230 die(STATE_CRITICAL, _("replica query error: %s\n"), error); 295
296 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
297 mp_add_subcheck_to_check(&overall, sc_replica);
298 mp_exit(overall);
231 } 299 }
232 300
233 /* store the result */ 301 /* store the result */
234 if ((res = mysql_store_result(&mysql)) == NULL) { 302 if ((res = mysql_store_result(&mysql)) == NULL) {
235 error = strdup(mysql_error(&mysql)); 303 xasprintf(&sc_replica.output, "replica store_result error: %s", mysql_error(&mysql));
236 mysql_close(&mysql); 304 mysql_close(&mysql);
237 die(STATE_CRITICAL, _("replica store_result error: %s\n"), error); 305
306 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
307 mp_add_subcheck_to_check(&overall, sc_replica);
308 mp_exit(overall);
238 } 309 }
239 310
240 /* Check there is some data */ 311 /* Check there is some data */
241 if (mysql_num_rows(res) == 0) { 312 if (mysql_num_rows(res) == 0) {
242 mysql_close(&mysql); 313 mysql_close(&mysql);
243 die(STATE_WARNING, "%s\n", _("No replicas defined")); 314
315 xasprintf(&sc_replica.output, "no replicas defined");
316 sc_replica = mp_set_subcheck_state(sc_replica, STATE_WARNING);
317 mp_add_subcheck_to_check(&overall, sc_replica);
318 mp_exit(overall);
244 } 319 }
245 320
246 /* fetch the first row */ 321 /* fetch the first row */
247 if ((row = mysql_fetch_row(res)) == NULL) { 322 if ((row = mysql_fetch_row(res)) == NULL) {
248 error = strdup(mysql_error(&mysql)); 323 xasprintf(&sc_replica.output, "replica fetch row error: %s", mysql_error(&mysql));
249 mysql_free_result(res); 324 mysql_free_result(res);
250 mysql_close(&mysql); 325 mysql_close(&mysql);
251 die(STATE_CRITICAL, _("replica fetch row error: %s\n"), error); 326
327 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
328 mp_add_subcheck_to_check(&overall, sc_replica);
329 mp_exit(overall);
252 } 330 }
253 331
254 if (mysql_field_count(&mysql) == 12) { 332 if (mysql_field_count(&mysql) == 12) {
255 /* mysql 3.23.x */ 333 /* mysql 3.23.x */
256 snprintf(replica_result, REPLICA_RESULTSIZE, _("Replica running: %s"), row[6]); 334 xasprintf(&sc_replica.output, "Replica running: %s", row[6]);
257 if (strcmp(row[6], "Yes") != 0) { 335 if (strcmp(row[6], "Yes") != 0) {
258 mysql_free_result(res); 336 mysql_free_result(res);
259 mysql_close(&mysql); 337 mysql_close(&mysql);
260 die(STATE_CRITICAL, "%s\n", replica_result);
261 }
262 338
339 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
340 mp_add_subcheck_to_check(&overall, sc_replica);
341 mp_exit(overall);
342 }
263 } else { 343 } else {
264 /* mysql 4.x.x and mysql 5.x.x */ 344 /* mysql 4.x.x and mysql 5.x.x */
265 int replica_io_field = -1; 345 int replica_io_field = -1;
266 int replica_sql_field = -1; 346 int replica_sql_field = -1;
267 int seconds_behind_field = -1; 347 int seconds_behind_field = -1;
268 int num_fields; 348 unsigned int num_fields = mysql_num_fields(res);
269 MYSQL_FIELD *fields; 349 MYSQL_FIELD *fields = mysql_fetch_fields(res);
270 num_fields = mysql_num_fields(res); 350 for (int i = 0; i < (int)num_fields; i++) {
271 fields = mysql_fetch_fields(res); 351 if ((strcasecmp(fields[i].name, "Slave_IO_Running") == 0) ||
272 for (int i = 0; i < num_fields; i++) { 352 (strcasecmp(fields[i].name, "Replica_IO_Running") == 0)) {
273 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
274 replica_io_field = i; 353 replica_io_field = i;
275 continue; 354 continue;
276 } 355 }
277 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) { 356 if ((strcasecmp(fields[i].name, "Slave_SQL_Running") == 0) ||
357 (strcasecmp(fields[i].name, "Replica_SQL_Running") == 0)) {
278 replica_sql_field = i; 358 replica_sql_field = i;
279 continue; 359 continue;
280 } 360 }
281 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) { 361 if ((strcasecmp(fields[i].name, "Seconds_Behind_Master") == 0) ||
362 (strcasecmp(fields[i].name, "Seconds_Behind_Source") == 0)) {
282 seconds_behind_field = i; 363 seconds_behind_field = i;
283 continue; 364 continue;
284 } 365 }
@@ -288,15 +369,23 @@ int main(int argc, char **argv) {
288 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) { 369 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) {
289 mysql_free_result(res); 370 mysql_free_result(res);
290 mysql_close(&mysql); 371 mysql_close(&mysql);
291 die(STATE_CRITICAL, "Replica status unavailable\n"); 372
373 xasprintf(&sc_replica.output, "Replica status unavailable");
374 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
375 mp_add_subcheck_to_check(&overall, sc_replica);
376 mp_exit(overall);
292 } 377 }
293 378
294 /* Save replica status in replica_result */ 379 /* 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], 380 xasprintf(&sc_replica.output,
296 row[replica_sql_field], seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown"); 381 "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s",
297 382 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 */ 383 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) { 384
385 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no
386 * mysqldump threads running */
387 if (strcmp(row[replica_io_field], "Yes") != 0 ||
388 strcmp(row[replica_sql_field], "Yes") != 0) {
300 MYSQL_RES *res_mysqldump; 389 MYSQL_RES *res_mysqldump;
301 MYSQL_ROW row_mysqldump; 390 MYSQL_ROW row_mysqldump;
302 unsigned int mysqldump_threads = 0; 391 unsigned int mysqldump_threads = 0;
@@ -314,10 +403,14 @@ int main(int argc, char **argv) {
314 } 403 }
315 mysql_close(&mysql); 404 mysql_close(&mysql);
316 } 405 }
406
317 if (mysqldump_threads == 0) { 407 if (mysqldump_threads == 0) {
318 die(STATE_CRITICAL, "%s\n", replica_result); 408 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
409 mp_add_subcheck_to_check(&overall, sc_replica);
410 mp_exit(overall);
319 } else { 411 } else {
320 strncat(replica_result, " Mysqldump: in progress", REPLICA_RESULTSIZE - 1); 412 xasprintf(&sc_replica.output, "%s %s", sc_replica.output,
413 " Mysqldump: in progress");
321 } 414 }
322 } 415 }
323 416
@@ -325,27 +418,30 @@ int main(int argc, char **argv) {
325 if (seconds_behind_field == -1) { 418 if (seconds_behind_field == -1) {
326 printf("seconds_behind_field not found\n"); 419 printf("seconds_behind_field not found\n");
327 } else { 420 } else {
328 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]); 421 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field,
422 row[seconds_behind_field]);
329 } 423 }
330 } 424 }
331 425
332 /* Check Seconds Behind against threshold */ 426 /* Check Seconds Behind against threshold */
333 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp(row[seconds_behind_field], "NULL") != 0)) { 427 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL &&
334 double value = atof(row[seconds_behind_field]); 428 strcmp(row[seconds_behind_field], "NULL") != 0)) {
335 int status; 429 mp_perfdata pd_seconds_behind = perfdata_init();
336 430 pd_seconds_behind.label = "seconds behind master";
337 status = get_status(value, config.my_threshold); 431 pd_seconds_behind.value = mp_create_pd_value(atof(row[seconds_behind_field]));
338 432 pd_seconds_behind =
339 xasprintf(&perf, "%s %s", perf, 433 mp_pd_set_thresholds(pd_seconds_behind, config.replica_thresholds);
340 fperfdata("seconds behind master", value, "s", true, (double)config.warning_time, true, 434 pd_seconds_behind.uom = "s";
341 (double)config.critical_time, false, 0, false, 0)); 435 mp_add_perfdata_to_subcheck(&sc_replica, pd_seconds_behind);
342 436
343 if (status == STATE_WARNING) { 437 mp_state_enum status = mp_get_pd_status(pd_seconds_behind);
344 printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf); 438
345 exit(STATE_WARNING); 439 sc_replica = mp_set_subcheck_state(sc_replica, status);
346 } else if (status == STATE_CRITICAL) { 440
347 printf("SLOW_REPLICA %s: %s|%s\n", _("CRITICAL"), replica_result, perf); 441 if (status != STATE_OK) {
348 exit(STATE_CRITICAL); 442 xasprintf(&sc_replica.output, "slow replica - %s", sc_replica.output);
443 mp_add_subcheck_to_check(&overall, sc_replica);
444 mp_exit(overall);
349 } 445 }
350 } 446 }
351 } 447 }
@@ -357,20 +453,17 @@ int main(int argc, char **argv) {
357 /* close the connection */ 453 /* close the connection */
358 mysql_close(&mysql); 454 mysql_close(&mysql);
359 455
360 /* print out the result of stats */ 456 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} 457}
369 458
370#define CHECK_REPLICA_OPT CHAR_MAX + 1
371
372/* process command-line arguments */ 459/* process command-line arguments */
373check_mysql_config_wrapper process_arguments(int argc, char **argv) { 460check_mysql_config_wrapper process_arguments(int argc, char **argv) {
461
462 enum {
463 CHECK_REPLICA_OPT = CHAR_MAX + 1,
464 output_format_index,
465 };
466
374 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 467 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
375 {"socket", required_argument, 0, 's'}, 468 {"socket", required_argument, 0, 's'},
376 {"database", required_argument, 0, 'd'}, 469 {"database", required_argument, 0, 'd'},
@@ -393,6 +486,7 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
393 {"cert", required_argument, 0, 'a'}, 486 {"cert", required_argument, 0, 'a'},
394 {"ca-dir", required_argument, 0, 'D'}, 487 {"ca-dir", required_argument, 0, 'D'},
395 {"ciphers", required_argument, 0, 'L'}, 488 {"ciphers", required_argument, 0, 'L'},
489 {"output-format", required_argument, 0, output_format_index},
396 {0, 0, 0, 0}}; 490 {0, 0, 0, 0}};
397 491
398 check_mysql_config_wrapper result = { 492 check_mysql_config_wrapper result = {
@@ -405,12 +499,10 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
405 return result; 499 return result;
406 } 500 }
407 501
408 char *warning = NULL;
409 char *critical = NULL;
410
411 int option = 0; 502 int option = 0;
412 while (true) { 503 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); 504 int option_index =
505 getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
414 506
415 if (option_index == -1 || option_index == EOF) { 507 if (option_index == -1 || option_index == EOF) {
416 break; 508 break;
@@ -478,14 +570,22 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
478 case 'n': 570 case 'n':
479 result.config.ignore_auth = true; /* ignore-auth */ 571 result.config.ignore_auth = true; /* ignore-auth */
480 break; 572 break;
481 case 'w': 573 case 'w': {
482 warning = optarg; 574 mp_range_parsed tmp = mp_parse_range_string(optarg);
483 result.config.warning_time = strtod(warning, NULL); 575 if (tmp.error != MP_PARSING_SUCCES) {
484 break; 576 die(STATE_UNKNOWN, "failed to parse warning time threshold");
485 case 'c': 577 }
486 critical = optarg; 578 result.config.replica_thresholds =
487 result.config.critical_time = strtod(critical, NULL); 579 mp_thresholds_set_warn(result.config.replica_thresholds, tmp.range);
488 break; 580 } break;
581 case 'c': {
582 mp_range_parsed tmp = mp_parse_range_string(optarg);
583 if (tmp.error != MP_PARSING_SUCCES) {
584 die(STATE_UNKNOWN, "failed to parse critical time threshold");
585 }
586 result.config.replica_thresholds =
587 mp_thresholds_set_crit(result.config.replica_thresholds, tmp.range);
588 } break;
489 case 'V': /* version */ 589 case 'V': /* version */
490 print_revision(progname, NP_VERSION); 590 print_revision(progname, NP_VERSION);
491 exit(STATE_UNKNOWN); 591 exit(STATE_UNKNOWN);
@@ -497,13 +597,22 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
497 break; 597 break;
498 case '?': /* help */ 598 case '?': /* help */
499 usage5(); 599 usage5();
600 case output_format_index: {
601 parsed_output_format parser = mp_parse_output_format(optarg);
602 if (!parser.parsing_success) {
603 printf("Invalid output format: %s\n", optarg);
604 exit(STATE_UNKNOWN);
605 }
606
607 result.config.output_format_is_set = true;
608 result.config.output_format = parser.output_format;
609 break;
610 }
500 } 611 }
501 } 612 }
502 613
503 int index = optind; 614 int index = optind;
504 615
505 set_thresholds(&result.config.my_threshold, warning, critical);
506
507 while (argc > index) { 616 while (argc > index) {
508 if (result.config.db_host == NULL) { 617 if (result.config.db_host == NULL) {
509 if (is_host(argv[index])) { 618 if (is_host(argv[index])) {
@@ -580,15 +689,17 @@ void print_help(void) {
580 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 689 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")); 690 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
582 printf(" %s\n", "-S, --check-slave"); 691 printf(" %s\n", "-S, --check-slave");
583 printf(" %s\n", 692 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")); 693 "in favour of check-replica, which does the same"));
585 printf(" %s\n", "--check-replica"); 694 printf(" %s\n", "--check-replica");
586 printf(" %s\n", _("Check if the replica thread is running properly.")); 695 printf(" %s\n", _("Check if the replica thread is running properly."));
587 printf(" %s\n", "-w, --warning"); 696 printf(" %s\n", "-w, --warning");
588 printf(" %s\n", _("Exit with WARNING status if replica server is more than INTEGER seconds")); 697 printf(" %s\n",
698 _("Exit with WARNING status if replica server is more than INTEGER seconds"));
589 printf(" %s\n", _("behind master")); 699 printf(" %s\n", _("behind master"));
590 printf(" %s\n", "-c, --critical"); 700 printf(" %s\n", "-c, --critical");
591 printf(" %s\n", _("Exit with CRITICAL status if replica server is more then INTEGER seconds")); 701 printf(" %s\n",
702 _("Exit with CRITICAL status if replica server is more then INTEGER seconds"));
592 printf(" %s\n", _("behind master")); 703 printf(" %s\n", _("behind master"));
593 printf(" %s\n", "-l, --ssl"); 704 printf(" %s\n", "-l, --ssl");
594 printf(" %s\n", _("Use ssl encryption")); 705 printf(" %s\n", _("Use ssl encryption"));
@@ -603,8 +714,11 @@ void print_help(void) {
603 printf(" %s\n", "-L, --ciphers=STRING"); 714 printf(" %s\n", "-L, --ciphers=STRING");
604 printf(" %s\n", _("List of valid SSL ciphers")); 715 printf(" %s\n", _("List of valid SSL ciphers"));
605 716
717 printf(UT_OUTPUT_FORMAT);
718
606 printf("\n"); 719 printf("\n");
607 printf(" %s\n", _("There are no required arguments. By default, the local database is checked")); 720 printf(" %s\n",
721 _("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")); 722 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).")); 723 printf(" %s\n", _("IP address or FQDN ('localhost' will use the socket as well)."));
610 724