diff options
-rw-r--r-- | plugins/check_dbi.c | 127 |
1 files changed, 90 insertions, 37 deletions
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c index f0099440..4a0a4d69 100644 --- a/plugins/check_dbi.c +++ b/plugins/check_dbi.c | |||
@@ -38,7 +38,13 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; | |||
38 | 38 | ||
39 | #include "netutils.h" | 39 | #include "netutils.h" |
40 | 40 | ||
41 | /* required for NAN */ | ||
42 | #ifndef _ISOC99_SOURCE | ||
43 | #define _ISOC99_SOURCE | ||
44 | #endif | ||
45 | |||
41 | #include <assert.h> | 46 | #include <assert.h> |
47 | #include <math.h> | ||
42 | 48 | ||
43 | #include <dbi/dbi.h> | 49 | #include <dbi/dbi.h> |
44 | 50 | ||
@@ -47,6 +53,7 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; | |||
47 | typedef enum { | 53 | typedef enum { |
48 | METRIC_CONN_TIME, | 54 | METRIC_CONN_TIME, |
49 | METRIC_QUERY_RESULT, | 55 | METRIC_QUERY_RESULT, |
56 | METRIC_QUERY_TIME, | ||
50 | } np_dbi_metric_t; | 57 | } np_dbi_metric_t; |
51 | 58 | ||
52 | typedef struct { | 59 | typedef struct { |
@@ -224,24 +231,38 @@ main (int argc, char **argv) | |||
224 | 231 | ||
225 | if (metric == METRIC_QUERY_RESULT) | 232 | if (metric == METRIC_QUERY_RESULT) |
226 | status = get_status (query_val, dbi_thresholds); | 233 | status = get_status (query_val, dbi_thresholds); |
234 | else if (metric == METRIC_QUERY_TIME) | ||
235 | status = get_status (query_time, dbi_thresholds); | ||
227 | } | 236 | } |
228 | 237 | ||
229 | if (verbose) | 238 | if (verbose) |
230 | printf("Closing connection\n"); | 239 | printf("Closing connection\n"); |
231 | dbi_conn_close (conn); | 240 | dbi_conn_close (conn); |
232 | 241 | ||
242 | /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error | ||
243 | * which should have been reported and handled (abort) before */ | ||
244 | assert ((metric != METRIC_QUERY_RESULT) || (! isnan (query_val))); | ||
245 | |||
233 | printf ("%s - connection time: %fs", state_text (status), conn_time); | 246 | printf ("%s - connection time: %fs", state_text (status), conn_time); |
234 | if (np_dbi_query) | 247 | if (np_dbi_query) { |
235 | printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); | 248 | if (isnan (query_val)) |
249 | printf (", '%s' query execution time: %fs", np_dbi_query, query_time); | ||
250 | else | ||
251 | printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); | ||
252 | } | ||
236 | 253 | ||
237 | printf (" | conntime=%fs;%s;%s;0;", conn_time, | 254 | printf (" | conntime=%fs;%s;%s;0;", conn_time, |
238 | ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", | 255 | ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", |
239 | ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : ""); | 256 | ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : ""); |
240 | if (np_dbi_query) | 257 | if (np_dbi_query) { |
241 | printf (" query=%f;%s;%s;; querytime=%fs;;;0;", query_val, | 258 | if (! isnan (query_val)) |
242 | ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", | 259 | printf (" query=%f;%s;%s;;", query_val, |
243 | ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : "", | 260 | ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", |
244 | query_time); | 261 | ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : ""); |
262 | printf (" querytime=%fs;%s;%s;0;", query_time, | ||
263 | ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "", | ||
264 | ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : ""); | ||
265 | } | ||
245 | printf ("\n"); | 266 | printf ("\n"); |
246 | return status; | 267 | return status; |
247 | } | 268 | } |
@@ -292,6 +313,8 @@ process_arguments (int argc, char **argv) | |||
292 | metric = METRIC_CONN_TIME; | 313 | metric = METRIC_CONN_TIME; |
293 | else if (! strcasecmp (optarg, "QUERY_RESULT")) | 314 | else if (! strcasecmp (optarg, "QUERY_RESULT")) |
294 | metric = METRIC_QUERY_RESULT; | 315 | metric = METRIC_QUERY_RESULT; |
316 | else if (! strcasecmp (optarg, "QUERY_TIME")) | ||
317 | metric = METRIC_QUERY_TIME; | ||
295 | else | 318 | else |
296 | usage2 (_("Invalid metric"), optarg); | 319 | usage2 (_("Invalid metric"), optarg); |
297 | break; | 320 | break; |
@@ -364,11 +387,13 @@ validate_arguments () | |||
364 | if (! np_dbi_driver) | 387 | if (! np_dbi_driver) |
365 | usage ("Must specify a DBI driver"); | 388 | usage ("Must specify a DBI driver"); |
366 | 389 | ||
367 | if ((metric == METRIC_QUERY_RESULT) && (! np_dbi_query)) | 390 | if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) |
391 | && (! np_dbi_query)) | ||
368 | usage ("Must specify a query to execute (metric == QUERY_RESULT)"); | 392 | usage ("Must specify a query to execute (metric == QUERY_RESULT)"); |
369 | 393 | ||
370 | if ((metric != METRIC_CONN_TIME) | 394 | if ((metric != METRIC_CONN_TIME) |
371 | && (metric != METRIC_QUERY_RESULT)) | 395 | && (metric != METRIC_QUERY_RESULT) |
396 | && (metric != METRIC_QUERY_TIME)) | ||
372 | usage ("Invalid metric specified"); | 397 | usage ("Invalid metric specified"); |
373 | 398 | ||
374 | return OK; | 399 | return OK; |
@@ -410,6 +435,8 @@ print_help (void) | |||
410 | printf (" %s\n", _("Metric to check thresholds against. Available metrics:")); | 435 | printf (" %s\n", _("Metric to check thresholds against. Available metrics:")); |
411 | printf (" CONN_TIME - %s\n", _("time used for setting up the database connection")); | 436 | printf (" CONN_TIME - %s\n", _("time used for setting up the database connection")); |
412 | printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query")); | 437 | printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query")); |
438 | printf (" QUERY_TIME - %s\n", _("time used to execute the query")); | ||
439 | printf (" %s\n", _("(ignore the query result)")); | ||
413 | printf ("\n"); | 440 | printf ("\n"); |
414 | 441 | ||
415 | printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 442 | printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
@@ -441,10 +468,16 @@ print_usage (void) | |||
441 | printf (" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n"); | 468 | printf (" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n"); |
442 | } | 469 | } |
443 | 470 | ||
471 | #define CHECK_IGNORE_ERROR(s) \ | ||
472 | do { \ | ||
473 | if (metric != METRIC_QUERY_RESULT) \ | ||
474 | return (s); \ | ||
475 | } while (0) | ||
476 | |||
444 | double | 477 | double |
445 | get_field (dbi_conn conn, dbi_result res, unsigned short *field_type) | 478 | get_field (dbi_conn conn, dbi_result res, unsigned short *field_type) |
446 | { | 479 | { |
447 | double val = 0.0; | 480 | double val = NAN; |
448 | 481 | ||
449 | if (*field_type == DBI_TYPE_INTEGER) { | 482 | if (*field_type == DBI_TYPE_INTEGER) { |
450 | val = (double)dbi_result_get_longlong_idx (res, 1); | 483 | val = (double)dbi_result_get_longlong_idx (res, 1); |
@@ -458,9 +491,10 @@ get_field (dbi_conn conn, dbi_result res, unsigned short *field_type) | |||
458 | 491 | ||
459 | val_str = dbi_result_get_string_idx (res, 1); | 492 | val_str = dbi_result_get_string_idx (res, 1); |
460 | if ((! val_str) || (strcmp (val_str, "ERROR") == 0)) { | 493 | if ((! val_str) || (strcmp (val_str, "ERROR") == 0)) { |
494 | CHECK_IGNORE_ERROR (NAN); | ||
461 | np_dbi_print_error (conn, "CRITICAL - failed to fetch string value"); | 495 | np_dbi_print_error (conn, "CRITICAL - failed to fetch string value"); |
462 | *field_type = DBI_TYPE_ERROR; | 496 | *field_type = DBI_TYPE_ERROR; |
463 | return 0.0; | 497 | return NAN; |
464 | } | 498 | } |
465 | 499 | ||
466 | if (verbose > 2) | 500 | if (verbose > 2) |
@@ -468,9 +502,10 @@ get_field (dbi_conn conn, dbi_result res, unsigned short *field_type) | |||
468 | 502 | ||
469 | val = strtod (val_str, &endptr); | 503 | val = strtod (val_str, &endptr); |
470 | if (endptr == val_str) { | 504 | if (endptr == val_str) { |
505 | CHECK_IGNORE_ERROR (NAN); | ||
471 | printf ("CRITICAL - result value is not a numeric: %s\n", val_str); | 506 | printf ("CRITICAL - result value is not a numeric: %s\n", val_str); |
472 | *field_type = DBI_TYPE_ERROR; | 507 | *field_type = DBI_TYPE_ERROR; |
473 | return 0.0; | 508 | return NAN; |
474 | } | 509 | } |
475 | else if ((endptr != NULL) && (*endptr != '\0')) { | 510 | else if ((endptr != NULL) && (*endptr != '\0')) { |
476 | if (verbose) | 511 | if (verbose) |
@@ -478,6 +513,7 @@ get_field (dbi_conn conn, dbi_result res, unsigned short *field_type) | |||
478 | } | 513 | } |
479 | } | 514 | } |
480 | else { | 515 | else { |
516 | CHECK_IGNORE_ERROR (NAN); | ||
481 | printf ("CRITICAL - cannot parse value of type %s (%i)\n", | 517 | printf ("CRITICAL - cannot parse value of type %s (%i)\n", |
482 | (*field_type == DBI_TYPE_BINARY) | 518 | (*field_type == DBI_TYPE_BINARY) |
483 | ? "BINARY" | 519 | ? "BINARY" |
@@ -486,55 +522,43 @@ get_field (dbi_conn conn, dbi_result res, unsigned short *field_type) | |||
486 | : "<unknown>", | 522 | : "<unknown>", |
487 | *field_type); | 523 | *field_type); |
488 | *field_type = DBI_TYPE_ERROR; | 524 | *field_type = DBI_TYPE_ERROR; |
489 | return 0.0; | 525 | return NAN; |
490 | } | 526 | } |
491 | return val; | 527 | return val; |
492 | } | 528 | } |
493 | 529 | ||
494 | int | 530 | double |
495 | do_query (dbi_conn conn, double *res_val, double *res_time) | 531 | get_query_result (dbi_conn conn, dbi_result res, double *res_val) |
496 | { | 532 | { |
497 | dbi_result res; | ||
498 | |||
499 | unsigned short field_type; | 533 | unsigned short field_type; |
500 | double val = 0.0; | 534 | double val = NAN; |
501 | |||
502 | struct timeval timeval_start, timeval_end; | ||
503 | |||
504 | assert (np_dbi_query); | ||
505 | |||
506 | if (verbose) | ||
507 | printf ("Executing query '%s'\n", np_dbi_query); | ||
508 | |||
509 | gettimeofday (&timeval_start, NULL); | ||
510 | |||
511 | res = dbi_conn_query (conn, np_dbi_query); | ||
512 | if (! res) { | ||
513 | np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); | ||
514 | return STATE_CRITICAL; | ||
515 | } | ||
516 | 535 | ||
517 | if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) { | 536 | if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) { |
537 | CHECK_IGNORE_ERROR (STATE_OK); | ||
518 | np_dbi_print_error (conn, "CRITICAL - failed to fetch rows"); | 538 | np_dbi_print_error (conn, "CRITICAL - failed to fetch rows"); |
519 | return STATE_CRITICAL; | 539 | return STATE_CRITICAL; |
520 | } | 540 | } |
521 | 541 | ||
522 | if (dbi_result_get_numrows (res) < 1) { | 542 | if (dbi_result_get_numrows (res) < 1) { |
543 | CHECK_IGNORE_ERROR (STATE_OK); | ||
523 | printf ("WARNING - no rows returned\n"); | 544 | printf ("WARNING - no rows returned\n"); |
524 | return STATE_WARNING; | 545 | return STATE_WARNING; |
525 | } | 546 | } |
526 | 547 | ||
527 | if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) { | 548 | if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) { |
549 | CHECK_IGNORE_ERROR (STATE_OK); | ||
528 | np_dbi_print_error (conn, "CRITICAL - failed to fetch fields"); | 550 | np_dbi_print_error (conn, "CRITICAL - failed to fetch fields"); |
529 | return STATE_CRITICAL; | 551 | return STATE_CRITICAL; |
530 | } | 552 | } |
531 | 553 | ||
532 | if (dbi_result_get_numfields (res) < 1) { | 554 | if (dbi_result_get_numfields (res) < 1) { |
555 | CHECK_IGNORE_ERROR (STATE_OK); | ||
533 | printf ("WARNING - no fields returned\n"); | 556 | printf ("WARNING - no fields returned\n"); |
534 | return STATE_WARNING; | 557 | return STATE_WARNING; |
535 | } | 558 | } |
536 | 559 | ||
537 | if (dbi_result_first_row (res) != 1) { | 560 | if (dbi_result_first_row (res) != 1) { |
561 | CHECK_IGNORE_ERROR (STATE_OK); | ||
538 | np_dbi_print_error (conn, "CRITICAL - failed to fetch first row"); | 562 | np_dbi_print_error (conn, "CRITICAL - failed to fetch first row"); |
539 | return STATE_CRITICAL; | 563 | return STATE_CRITICAL; |
540 | } | 564 | } |
@@ -543,20 +567,49 @@ do_query (dbi_conn conn, double *res_val, double *res_time) | |||
543 | if (field_type != DBI_TYPE_ERROR) | 567 | if (field_type != DBI_TYPE_ERROR) |
544 | val = get_field (conn, res, &field_type); | 568 | val = get_field (conn, res, &field_type); |
545 | 569 | ||
546 | gettimeofday (&timeval_end, NULL); | 570 | *res_val = val; |
547 | *res_time = timediff (timeval_start, timeval_end); | ||
548 | 571 | ||
549 | if (field_type == DBI_TYPE_ERROR) { | 572 | if (field_type == DBI_TYPE_ERROR) { |
573 | CHECK_IGNORE_ERROR (STATE_OK); | ||
550 | np_dbi_print_error (conn, "CRITICAL - failed to fetch data"); | 574 | np_dbi_print_error (conn, "CRITICAL - failed to fetch data"); |
551 | return STATE_CRITICAL; | 575 | return STATE_CRITICAL; |
552 | } | 576 | } |
553 | 577 | ||
554 | *res_val = val; | ||
555 | |||
556 | dbi_result_free (res); | 578 | dbi_result_free (res); |
557 | return STATE_OK; | 579 | return STATE_OK; |
558 | } | 580 | } |
559 | 581 | ||
582 | #undef CHECK_IGNORE_ERROR | ||
583 | |||
584 | int | ||
585 | do_query (dbi_conn conn, double *res_val, double *res_time) | ||
586 | { | ||
587 | dbi_result res; | ||
588 | |||
589 | struct timeval timeval_start, timeval_end; | ||
590 | int status = STATE_OK; | ||
591 | |||
592 | assert (np_dbi_query); | ||
593 | |||
594 | if (verbose) | ||
595 | printf ("Executing query '%s'\n", np_dbi_query); | ||
596 | |||
597 | gettimeofday (&timeval_start, NULL); | ||
598 | |||
599 | res = dbi_conn_query (conn, np_dbi_query); | ||
600 | if (! res) { | ||
601 | np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); | ||
602 | return STATE_CRITICAL; | ||
603 | } | ||
604 | |||
605 | status = get_query_result (conn, res, res_val); | ||
606 | |||
607 | gettimeofday (&timeval_end, NULL); | ||
608 | *res_time = timediff (timeval_start, timeval_end); | ||
609 | |||
610 | return status; | ||
611 | } | ||
612 | |||
560 | double | 613 | double |
561 | timediff (struct timeval start, struct timeval end) | 614 | timediff (struct timeval start, struct timeval end) |
562 | { | 615 | { |