diff options
Diffstat (limited to 'plugins/check_dbi.c')
| -rw-r--r-- | plugins/check_dbi.c | 430 |
1 files changed, 290 insertions, 140 deletions
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c index 786fc1b6..84e3cb5b 100644 --- a/plugins/check_dbi.c +++ b/plugins/check_dbi.c | |||
| @@ -29,12 +29,14 @@ | |||
| 29 | * | 29 | * |
| 30 | *****************************************************************************/ | 30 | *****************************************************************************/ |
| 31 | 31 | ||
| 32 | #include "states.h" | ||
| 33 | const char *progname = "check_dbi"; | 32 | const char *progname = "check_dbi"; |
| 34 | const char *copyright = "2011-2024"; | 33 | const char *copyright = "2011-2024"; |
| 35 | const char *email = "devel@monitoring-plugins.org"; | 34 | const char *email = "devel@monitoring-plugins.org"; |
| 36 | 35 | ||
| 37 | #include "../lib/monitoringplug.h" | 36 | #include "../lib/monitoringplug.h" |
| 37 | #include "perfdata.h" | ||
| 38 | #include "output.h" | ||
| 39 | #include "states.h" | ||
| 38 | #include "check_dbi.d/config.h" | 40 | #include "check_dbi.d/config.h" |
| 39 | #include "common.h" | 41 | #include "common.h" |
| 40 | #include "utils.h" | 42 | #include "utils.h" |
| @@ -72,9 +74,15 @@ static double timediff(struct timeval /*start*/, struct timeval /*end*/); | |||
| 72 | 74 | ||
| 73 | static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...); | 75 | static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...); |
| 74 | 76 | ||
| 75 | static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, | 77 | typedef struct { |
| 76 | double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/, | 78 | char *result_string; |
| 77 | mp_dbi_type /*type*/, char * /*np_dbi_query*/); | 79 | double result_number; |
| 80 | double query_duration; | ||
| 81 | int error_code; | ||
| 82 | const char *error_string; | ||
| 83 | mp_state_enum query_processing_status; | ||
| 84 | } do_query_result; | ||
| 85 | static do_query_result do_query(dbi_conn conn, mp_dbi_metric metric, mp_dbi_type type, char *query); | ||
| 78 | 86 | ||
| 79 | int main(int argc, char **argv) { | 87 | int main(int argc, char **argv) { |
| 80 | setlocale(LC_ALL, ""); | 88 | setlocale(LC_ALL, ""); |
| @@ -104,16 +112,17 @@ int main(int argc, char **argv) { | |||
| 104 | 112 | ||
| 105 | dbi_inst instance_p = NULL; | 113 | dbi_inst instance_p = NULL; |
| 106 | if (dbi_initialize_r(NULL, &instance_p) < 0) { | 114 | if (dbi_initialize_r(NULL, &instance_p) < 0) { |
| 107 | printf( | 115 | printf("failed to initialize DBI; possibly you don't have any drivers installed.\n"); |
| 108 | "UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n"); | 116 | exit(STATE_UNKNOWN); |
| 109 | return STATE_UNKNOWN; | ||
| 110 | } | 117 | } |
| 111 | 118 | ||
| 119 | // Try to prevent libdbi from printing stuff on stderr | ||
| 120 | // Who thought that would be a good idea anyway? | ||
| 112 | dbi_set_verbosity_r(0, instance_p); | 121 | dbi_set_verbosity_r(0, instance_p); |
| 113 | 122 | ||
| 114 | if (instance_p == NULL) { | 123 | if (instance_p == NULL) { |
| 115 | printf("UNKNOWN - failed to initialize DBI.\n"); | 124 | printf("failed to initialize DBI.\n"); |
| 116 | return STATE_UNKNOWN; | 125 | exit(STATE_UNKNOWN); |
| 117 | } | 126 | } |
| 118 | 127 | ||
| 119 | if (verbose) { | 128 | if (verbose) { |
| @@ -122,15 +131,14 @@ int main(int argc, char **argv) { | |||
| 122 | 131 | ||
| 123 | dbi_driver driver = dbi_driver_open_r(config.dbi_driver, instance_p); | 132 | dbi_driver driver = dbi_driver_open_r(config.dbi_driver, instance_p); |
| 124 | if (!driver) { | 133 | if (!driver) { |
| 125 | printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", | 134 | printf("failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver); |
| 126 | config.dbi_driver); | ||
| 127 | 135 | ||
| 128 | printf("Known drivers:\n"); | 136 | printf("Known drivers:\n"); |
| 129 | for (driver = dbi_driver_list_r(NULL, instance_p); driver; | 137 | for (driver = dbi_driver_list_r(NULL, instance_p); driver; |
| 130 | driver = dbi_driver_list_r(driver, instance_p)) { | 138 | driver = dbi_driver_list_r(driver, instance_p)) { |
| 131 | printf(" - %s\n", dbi_driver_get_name(driver)); | 139 | printf(" - %s\n", dbi_driver_get_name(driver)); |
| 132 | } | 140 | } |
| 133 | return STATE_UNKNOWN; | 141 | exit(STATE_UNKNOWN); |
| 134 | } | 142 | } |
| 135 | 143 | ||
| 136 | /* make a connection to the database */ | 144 | /* make a connection to the database */ |
| @@ -141,7 +149,7 @@ int main(int argc, char **argv) { | |||
| 141 | if (!conn) { | 149 | if (!conn) { |
| 142 | printf("UNKNOWN - failed top open connection object.\n"); | 150 | printf("UNKNOWN - failed top open connection object.\n"); |
| 143 | dbi_conn_close(conn); | 151 | dbi_conn_close(conn); |
| 144 | return STATE_UNKNOWN; | 152 | exit(STATE_UNKNOWN); |
| 145 | } | 153 | } |
| 146 | 154 | ||
| 147 | for (size_t i = 0; i < config.dbi_options_num; ++i) { | 155 | for (size_t i = 0; i < config.dbi_options_num; ++i) { |
| @@ -155,10 +163,10 @@ int main(int argc, char **argv) { | |||
| 155 | if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) { | 163 | if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) { |
| 156 | continue; | 164 | continue; |
| 157 | } | 165 | } |
| 158 | /* else: status != 0 */ | ||
| 159 | 166 | ||
| 160 | np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", | 167 | // Failing to set option |
| 161 | config.dbi_options[i].key, config.dbi_options[i].value); | 168 | np_dbi_print_error(conn, "failed to set option '%s' to '%s'", config.dbi_options[i].key, |
| 169 | config.dbi_options[i].value); | ||
| 162 | printf("Known driver options:\n"); | 170 | printf("Known driver options:\n"); |
| 163 | 171 | ||
| 164 | for (opt = dbi_conn_get_option_list(conn, NULL); opt; | 172 | for (opt = dbi_conn_get_option_list(conn, NULL); opt; |
| @@ -166,7 +174,7 @@ int main(int argc, char **argv) { | |||
| 166 | printf(" - %s\n", opt); | 174 | printf(" - %s\n", opt); |
| 167 | } | 175 | } |
| 168 | dbi_conn_close(conn); | 176 | dbi_conn_close(conn); |
| 169 | return STATE_UNKNOWN; | 177 | exit(STATE_UNKNOWN); |
| 170 | } | 178 | } |
| 171 | 179 | ||
| 172 | if (config.host) { | 180 | if (config.host) { |
| @@ -194,31 +202,60 @@ int main(int argc, char **argv) { | |||
| 194 | } | 202 | } |
| 195 | 203 | ||
| 196 | if (dbi_conn_connect(conn) < 0) { | 204 | if (dbi_conn_connect(conn) < 0) { |
| 197 | np_dbi_print_error(conn, "UNKNOWN - failed to connect to database"); | 205 | np_dbi_print_error(conn, "failed to connect to database"); |
| 198 | return STATE_UNKNOWN; | 206 | exit(STATE_UNKNOWN); |
| 199 | } | 207 | } |
| 200 | 208 | ||
| 201 | struct timeval end_timeval; | 209 | struct timeval end_timeval; |
| 202 | gettimeofday(&end_timeval, NULL); | 210 | gettimeofday(&end_timeval, NULL); |
| 203 | double conn_time = timediff(start_timeval, end_timeval); | 211 | double conn_time = timediff(start_timeval, end_timeval); |
| 212 | if (verbose) { | ||
| 213 | printf("Time elapsed: %f\n", conn_time); | ||
| 214 | } | ||
| 215 | |||
| 216 | mp_check overall = mp_check_init(); | ||
| 217 | |||
| 218 | mp_subcheck sc_connection_time = mp_subcheck_init(); | ||
| 219 | sc_connection_time = mp_set_subcheck_default_state(sc_connection_time, STATE_OK); | ||
| 220 | xasprintf(&sc_connection_time.output, "Connection time: %f", conn_time); | ||
| 221 | |||
| 222 | mp_perfdata pd_conn_duration = perfdata_init(); | ||
| 223 | pd_conn_duration.label = "conntime"; | ||
| 224 | pd_conn_duration = mp_set_pd_value(pd_conn_duration, conn_time); | ||
| 225 | |||
| 226 | if (config.metric == METRIC_CONN_TIME) { | ||
| 227 | // TODO set pd thresholds | ||
| 228 | mp_state_enum status = get_status(conn_time, config.dbi_thresholds); | ||
| 229 | sc_connection_time = mp_set_subcheck_state(sc_connection_time, status); | ||
| 230 | if (status != STATE_OK) { | ||
| 231 | xasprintf(&sc_connection_time.output, "%s violates thresholds", | ||
| 232 | sc_connection_time.output); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | mp_add_perfdata_to_subcheck(&sc_connection_time, pd_conn_duration); | ||
| 237 | mp_add_subcheck_to_check(&overall, sc_connection_time); | ||
| 204 | 238 | ||
| 205 | unsigned int server_version = dbi_conn_get_engine_version(conn); | 239 | unsigned int server_version = dbi_conn_get_engine_version(conn); |
| 206 | if (verbose) { | 240 | if (verbose) { |
| 207 | printf("Connected to server version %u\n", server_version); | 241 | printf("Connected to server version %u\n", server_version); |
| 208 | } | 242 | } |
| 209 | 243 | ||
| 210 | int status = STATE_UNKNOWN; | 244 | mp_subcheck sc_server_version = mp_subcheck_init(); |
| 245 | sc_server_version = mp_set_subcheck_default_state(sc_server_version, STATE_OK); | ||
| 246 | xasprintf(&sc_server_version.output, "Connected to server version %u", server_version); | ||
| 247 | |||
| 211 | if (config.metric == METRIC_SERVER_VERSION) { | 248 | if (config.metric == METRIC_SERVER_VERSION) { |
| 212 | status = get_status(server_version, config.dbi_thresholds); | 249 | mp_state_enum status = get_status(server_version, config.dbi_thresholds); |
| 213 | } | ||
| 214 | 250 | ||
| 215 | if (verbose) { | 251 | sc_server_version = mp_set_subcheck_state(sc_server_version, status); |
| 216 | printf("Time elapsed: %f\n", conn_time); | ||
| 217 | } | ||
| 218 | 252 | ||
| 219 | if (config.metric == METRIC_CONN_TIME) { | 253 | if (status != STATE_OK) { |
| 220 | status = get_status(conn_time, config.dbi_thresholds); | 254 | xasprintf(&sc_server_version.output, "%s violates thresholds", |
| 221 | } | 255 | sc_server_version.output); |
| 256 | } | ||
| 257 | }; | ||
| 258 | mp_add_subcheck_to_check(&overall, sc_server_version); | ||
| 222 | 259 | ||
| 223 | /* select a database */ | 260 | /* select a database */ |
| 224 | if (config.dbi_database) { | 261 | if (config.dbi_database) { |
| @@ -226,58 +263,152 @@ int main(int argc, char **argv) { | |||
| 226 | printf("Selecting database '%s'\n", config.dbi_database); | 263 | printf("Selecting database '%s'\n", config.dbi_database); |
| 227 | } | 264 | } |
| 228 | 265 | ||
| 266 | mp_subcheck sc_select_db = mp_subcheck_init(); | ||
| 267 | sc_select_db = mp_set_subcheck_default_state(sc_select_db, STATE_OK); | ||
| 268 | |||
| 229 | if (dbi_conn_select_db(conn, config.dbi_database)) { | 269 | if (dbi_conn_select_db(conn, config.dbi_database)) { |
| 230 | np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", | 270 | np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", |
| 231 | config.dbi_database); | 271 | config.dbi_database); |
| 232 | return STATE_UNKNOWN; | 272 | exit(STATE_UNKNOWN); |
| 273 | } else { | ||
| 274 | mp_add_subcheck_to_check(&overall, sc_select_db); | ||
| 233 | } | 275 | } |
| 234 | } | 276 | } |
| 235 | 277 | ||
| 236 | const char *query_val_str = NULL; | 278 | // Do a query (if configured) |
| 237 | double query_val = 0.0; | ||
| 238 | double query_time = 0.0; | ||
| 239 | if (config.dbi_query) { | 279 | if (config.dbi_query) { |
| 280 | mp_subcheck sc_query = mp_subcheck_init(); | ||
| 281 | sc_query = mp_set_subcheck_default_state(sc_query, STATE_UNKNOWN); | ||
| 282 | |||
| 240 | /* execute query */ | 283 | /* execute query */ |
| 241 | status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, | 284 | do_query_result query_res = do_query(conn, config.metric, config.type, config.dbi_query); |
| 242 | config.dbi_query); | 285 | |
| 243 | if (status != STATE_OK) { | 286 | if (query_res.error_code != 0) { |
| 244 | /* do_query prints an error message in this case */ | 287 | xasprintf(&sc_query.output, "Query failed: %s", query_res.error_string); |
| 245 | return status; | 288 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); |
| 246 | } | 289 | } else if (query_res.query_processing_status != STATE_OK) { |
| 290 | if (query_res.error_string) { | ||
| 291 | xasprintf(&sc_query.output, "Failed to process query: %s", query_res.error_string); | ||
| 292 | } else { | ||
| 293 | xasprintf(&sc_query.output, "Failed to process query"); | ||
| 294 | } | ||
| 295 | sc_query = mp_set_subcheck_state(sc_query, query_res.query_processing_status); | ||
| 296 | } else { | ||
| 297 | // query succeeded in general | ||
| 298 | xasprintf(&sc_query.output, "Query '%s' succeeded", config.dbi_query); | ||
| 299 | |||
| 300 | // that's a OK by default now | ||
| 301 | sc_query = mp_set_subcheck_default_state(sc_query, STATE_OK); | ||
| 302 | |||
| 303 | // query duration first | ||
| 304 | mp_perfdata pd_query_duration = perfdata_init(); | ||
| 305 | pd_query_duration = mp_set_pd_value(pd_query_duration, query_res.query_duration); | ||
| 306 | pd_query_duration.label = "querytime"; | ||
| 307 | if (config.metric == METRIC_QUERY_TIME) { | ||
| 308 | // TODO set thresholds | ||
| 309 | } | ||
| 310 | |||
| 311 | mp_add_perfdata_to_subcheck(&sc_query, pd_query_duration); | ||
| 247 | 312 | ||
| 248 | if (config.metric == METRIC_QUERY_RESULT) { | 313 | if (config.metric == METRIC_QUERY_RESULT) { |
| 249 | if (config.expect) { | 314 | if (config.expect) { |
| 250 | if ((!query_val_str) || strcmp(query_val_str, config.expect)) { | 315 | if ((!query_res.result_string) || |
| 251 | status = STATE_CRITICAL; | 316 | strcmp(query_res.result_string, config.expect)) { |
| 317 | xasprintf(&sc_query.output, "Found string '%s' in query result", | ||
| 318 | config.expect); | ||
| 319 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 320 | } else { | ||
| 321 | xasprintf(&sc_query.output, "Did not find string '%s' in query result", | ||
| 322 | config.expect); | ||
| 323 | sc_query = mp_set_subcheck_state(sc_query, STATE_OK); | ||
| 324 | } | ||
| 325 | } else if (config.expect_re_str) { | ||
| 326 | int comp_err; | ||
| 327 | regex_t expect_re = {}; | ||
| 328 | comp_err = regcomp(&expect_re, config.expect_re_str, config.expect_re_cflags); | ||
| 329 | if (comp_err != 0) { | ||
| 330 | // TODO error, failed to compile regex | ||
| 331 | // TODO move this to config sanitatisation | ||
| 332 | printf("Failed to compile regex from string '%s'", config.expect_re_str); | ||
| 333 | exit(STATE_UNKNOWN); | ||
| 334 | } | ||
| 335 | |||
| 336 | int err = | ||
| 337 | regexec(&expect_re, query_res.result_string, 0, NULL, /* flags = */ 0); | ||
| 338 | if (!err) { | ||
| 339 | sc_query = mp_set_subcheck_state(sc_query, STATE_OK); | ||
| 340 | xasprintf(&sc_query.output, "Found regular expression '%s' in query result", | ||
| 341 | config.expect_re_str); | ||
| 342 | } else if (err == REG_NOMATCH) { | ||
| 343 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 344 | xasprintf(&sc_query.output, | ||
| 345 | "Did not find regular expression '%s' in query result", | ||
| 346 | config.expect_re_str); | ||
| 347 | } else { | ||
| 348 | char errmsg[1024]; | ||
| 349 | regerror(err, &expect_re, errmsg, sizeof(errmsg)); | ||
| 350 | xasprintf(&sc_query.output, | ||
| 351 | "ERROR - failed to execute regular expression: %s\n", errmsg); | ||
| 352 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 353 | } | ||
| 252 | } else { | 354 | } else { |
| 253 | status = STATE_OK; | 355 | // no string matching |
| 254 | } | 356 | if (isnan(query_res.result_number)) { |
| 255 | } else if (config.expect_re_str) { | 357 | // The query result is not a number, but no string checking was configured |
| 256 | int comp_err; | 358 | // so we expected a number |
| 257 | regex_t expect_re = {}; | 359 | // this is a CRITICAL |
| 258 | comp_err = regcomp(&expect_re, config.expect_re_str, config.expect_re_cflags); | 360 | xasprintf(&sc_query.output, "Query '%s' result is not numeric", |
| 259 | if (comp_err != 0) { | 361 | config.dbi_query, query_res.result_string); |
| 260 | // TODO error, failed to compile regex | 362 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); |
| 261 | return STATE_UNKNOWN; | 363 | |
| 364 | } else { | ||
| 365 | mp_state_enum query_numerical_result = | ||
| 366 | get_status(query_res.result_number, config.dbi_thresholds); | ||
| 367 | sc_query = mp_set_subcheck_state(sc_query, query_numerical_result); | ||
| 368 | |||
| 369 | mp_perfdata pd_query_val = perfdata_init(); | ||
| 370 | pd_query_val = mp_set_pd_value(pd_query_val, query_res.result_number); | ||
| 371 | pd_query_val.label = "query"; | ||
| 372 | mp_add_perfdata_to_subcheck(&sc_query, pd_query_val); | ||
| 373 | |||
| 374 | // TODO set pd thresholds | ||
| 375 | // if (config.dbi_thresholds->warning) { | ||
| 376 | // pd_query_val.warn= config.dbi_thresholds->warning | ||
| 377 | // } else { | ||
| 378 | // } | ||
| 379 | |||
| 380 | if (query_numerical_result == STATE_OK) { | ||
| 381 | xasprintf(&sc_query.output, | ||
| 382 | "Query result '%f' is within given thresholds", | ||
| 383 | query_res.result_number); | ||
| 384 | } else { | ||
| 385 | xasprintf(&sc_query.output, | ||
| 386 | "Query result '%f' violates the given thresholds", | ||
| 387 | query_res.result_number); | ||
| 388 | } | ||
| 389 | } | ||
| 262 | } | 390 | } |
| 263 | 391 | } else if (config.metric == METRIC_QUERY_TIME) { | |
| 264 | int err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0); | 392 | mp_state_enum query_time_status = |
| 265 | if (!err) { | 393 | get_status(query_res.query_duration, config.dbi_thresholds); |
| 266 | status = STATE_OK; | 394 | mp_set_subcheck_state(sc_query, query_time_status); |
| 267 | } else if (err == REG_NOMATCH) { | 395 | |
| 268 | status = STATE_CRITICAL; | 396 | if (query_time_status == STATE_OK) { |
| 397 | xasprintf(&sc_query.output, "Query duration '%f' is withing given thresholds", | ||
| 398 | query_res.query_duration); | ||
| 269 | } else { | 399 | } else { |
| 270 | char errmsg[1024]; | 400 | xasprintf(&sc_query.output, "Query duration '%f' violates the given thresholds", |
| 271 | regerror(err, &expect_re, errmsg, sizeof(errmsg)); | 401 | query_res.query_duration); |
| 272 | printf("ERROR - failed to execute regular expression: %s\n", errmsg); | ||
| 273 | status = STATE_CRITICAL; | ||
| 274 | } | 402 | } |
| 275 | } else { | 403 | } else { |
| 276 | status = get_status(query_val, config.dbi_thresholds); | 404 | /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error |
| 405 | * which should have been reported and handled (abort) before | ||
| 406 | * ... unless we expected a string to be returned */ | ||
| 407 | assert((!isnan(query_res.result_number)) || (config.type == TYPE_STRING)); | ||
| 277 | } | 408 | } |
| 278 | } else if (config.metric == METRIC_QUERY_TIME) { | ||
| 279 | status = get_status(query_time, config.dbi_thresholds); | ||
| 280 | } | 409 | } |
| 410 | |||
| 411 | mp_add_subcheck_to_check(&overall, sc_query); | ||
| 281 | } | 412 | } |
| 282 | 413 | ||
| 283 | if (verbose) { | 414 | if (verbose) { |
| @@ -285,63 +416,7 @@ int main(int argc, char **argv) { | |||
| 285 | } | 416 | } |
| 286 | dbi_conn_close(conn); | 417 | dbi_conn_close(conn); |
| 287 | 418 | ||
| 288 | /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error | 419 | mp_exit(overall); |
| 289 | * which should have been reported and handled (abort) before | ||
| 290 | * ... unless we expected a string to be returned */ | ||
| 291 | assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || | ||
| 292 | (config.type == TYPE_STRING)); | ||
| 293 | |||
| 294 | assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str)); | ||
| 295 | |||
| 296 | printf("%s - connection time: %fs", state_text(status), conn_time); | ||
| 297 | if (config.dbi_query) { | ||
| 298 | if (config.type == TYPE_STRING) { | ||
| 299 | assert(config.expect || config.expect_re_str); | ||
| 300 | printf(", '%s' returned '%s' in %fs", config.dbi_query, | ||
| 301 | query_val_str ? query_val_str : "<nothing>", query_time); | ||
| 302 | if (status != STATE_OK) { | ||
| 303 | if (config.expect) { | ||
| 304 | printf(" (expected '%s')", config.expect); | ||
| 305 | } else if (config.expect_re_str) { | ||
| 306 | printf(" (expected regex /%s/%s)", config.expect_re_str, | ||
| 307 | ((config.expect_re_cflags & REG_ICASE) ? "i" : "")); | ||
| 308 | } | ||
| 309 | } | ||
| 310 | } else if (isnan(query_val)) { | ||
| 311 | printf(", '%s' query execution time: %fs", config.dbi_query, query_time); | ||
| 312 | } else { | ||
| 313 | printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | printf( | ||
| 318 | " | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, | ||
| 319 | ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "", | ||
| 320 | ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", | ||
| 321 | server_version, | ||
| 322 | ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range | ||
| 323 | : "", | ||
| 324 | ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range | ||
| 325 | : ""); | ||
| 326 | if (config.dbi_query) { | ||
| 327 | if (!isnan(query_val)) { /* this is also true when -e is used */ | ||
| 328 | printf(" query=%f;%s;%s;;", query_val, | ||
| 329 | ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) | ||
| 330 | ? config.warning_range | ||
| 331 | : "", | ||
| 332 | ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) | ||
| 333 | ? config.critical_range | ||
| 334 | : ""); | ||
| 335 | } | ||
| 336 | printf(" querytime=%fs;%s;%s;0;", query_time, | ||
| 337 | ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range | ||
| 338 | : "", | ||
| 339 | ((config.metric == METRIC_QUERY_TIME) && config.critical_range) | ||
| 340 | ? config.critical_range | ||
| 341 | : ""); | ||
| 342 | } | ||
| 343 | printf("\n"); | ||
| 344 | return status; | ||
| 345 | } | 420 | } |
| 346 | 421 | ||
| 347 | /* process command-line arguments */ | 422 | /* process command-line arguments */ |
| @@ -349,7 +424,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) { | |||
| 349 | 424 | ||
| 350 | int option = 0; | 425 | int option = 0; |
| 351 | static struct option longopts[] = {STD_LONG_OPTS, | 426 | static struct option longopts[] = {STD_LONG_OPTS, |
| 352 | |||
| 353 | {"expect", required_argument, 0, 'e'}, | 427 | {"expect", required_argument, 0, 'e'}, |
| 354 | {"regex", required_argument, 0, 'r'}, | 428 | {"regex", required_argument, 0, 'r'}, |
| 355 | {"regexi", required_argument, 0, 'R'}, | 429 | {"regexi", required_argument, 0, 'R'}, |
| @@ -533,6 +607,10 @@ check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrap | |||
| 533 | usage("Options -r/-R require metric QUERY_RESULT"); | 607 | usage("Options -r/-R require metric QUERY_RESULT"); |
| 534 | } | 608 | } |
| 535 | 609 | ||
| 610 | if (config_wrapper.config.type == TYPE_STRING) { | ||
| 611 | assert(config_wrapper.config.expect || config_wrapper.config.expect_re_str); | ||
| 612 | } | ||
| 613 | |||
| 536 | config_wrapper.errorcode = OK; | 614 | config_wrapper.errorcode = OK; |
| 537 | return config_wrapper; | 615 | return config_wrapper; |
| 538 | } | 616 | } |
| @@ -783,38 +861,110 @@ mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_v | |||
| 783 | return STATE_OK; | 861 | return STATE_OK; |
| 784 | } | 862 | } |
| 785 | 863 | ||
| 786 | mp_state_enum do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time, | 864 | static do_query_result do_query(dbi_conn conn, mp_dbi_metric metric, mp_dbi_type type, |
| 787 | mp_dbi_metric metric, mp_dbi_type type, char *np_dbi_query) { | 865 | char *query) { |
| 788 | dbi_result res; | 866 | assert(query); |
| 789 | |||
| 790 | struct timeval timeval_start; | ||
| 791 | struct timeval timeval_end; | ||
| 792 | mp_state_enum status = STATE_OK; | ||
| 793 | |||
| 794 | assert(np_dbi_query); | ||
| 795 | 867 | ||
| 796 | if (verbose) { | 868 | if (verbose) { |
| 797 | printf("Executing query '%s'\n", np_dbi_query); | 869 | printf("Executing query '%s'\n", query); |
| 798 | } | 870 | } |
| 799 | 871 | ||
| 872 | do_query_result result = { | ||
| 873 | .query_duration = 0, | ||
| 874 | .result_string = NULL, | ||
| 875 | .result_number = 0, | ||
| 876 | .error_code = 0, | ||
| 877 | .query_processing_status = STATE_UNKNOWN, | ||
| 878 | }; | ||
| 879 | |||
| 880 | struct timeval timeval_start; | ||
| 800 | gettimeofday(&timeval_start, NULL); | 881 | gettimeofday(&timeval_start, NULL); |
| 801 | 882 | ||
| 802 | res = dbi_conn_query(conn, np_dbi_query); | 883 | dbi_result res = dbi_conn_query(conn, query); |
| 803 | if (!res) { | 884 | if (!res) { |
| 804 | np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); | 885 | dbi_conn_error(conn, &result.error_string); |
| 805 | return STATE_CRITICAL; | 886 | result.error_code = 1; |
| 887 | return result; | ||
| 806 | } | 888 | } |
| 807 | 889 | ||
| 808 | status = get_query_result(conn, res, res_val_str, res_val, metric, type); | 890 | struct timeval timeval_end; |
| 809 | |||
| 810 | gettimeofday(&timeval_end, NULL); | 891 | gettimeofday(&timeval_end, NULL); |
| 811 | *res_time = timediff(timeval_start, timeval_end); | 892 | result.query_duration = timediff(timeval_start, timeval_end); |
| 812 | 893 | ||
| 813 | if (verbose) { | 894 | if (verbose) { |
| 814 | printf("Time elapsed: %f\n", *res_time); | 895 | printf("Query duration: %f\n", result.query_duration); |
| 896 | } | ||
| 897 | |||
| 898 | // Default state is OK, all error will be set explicitely | ||
| 899 | mp_state_enum query_processing_state = STATE_OK; | ||
| 900 | { | ||
| 901 | |||
| 902 | if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) { | ||
| 903 | if (metric != METRIC_QUERY_RESULT) { | ||
| 904 | query_processing_state = STATE_OK; | ||
| 905 | } else { | ||
| 906 | dbi_conn_error(conn, &result.error_string); | ||
| 907 | query_processing_state = STATE_CRITICAL; | ||
| 908 | } | ||
| 909 | } else if (dbi_result_get_numrows(res) < 1) { | ||
| 910 | if (metric != METRIC_QUERY_RESULT) { | ||
| 911 | query_processing_state = STATE_OK; | ||
| 912 | } else { | ||
| 913 | result.error_string = "no rows returned"; | ||
| 914 | // printf("WARNING - no rows returned\n"); | ||
| 915 | query_processing_state = STATE_WARNING; | ||
| 916 | } | ||
| 917 | } else if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) { | ||
| 918 | if (metric != METRIC_QUERY_RESULT) { | ||
| 919 | query_processing_state = STATE_OK; | ||
| 920 | } else { | ||
| 921 | dbi_conn_error(conn, &result.error_string); | ||
| 922 | // np_dbi_print_error(conn, "CRITICAL - failed to fetch fields"); | ||
| 923 | query_processing_state = STATE_CRITICAL; | ||
| 924 | } | ||
| 925 | } else if (dbi_result_get_numfields(res) < 1) { | ||
| 926 | if (metric != METRIC_QUERY_RESULT) { | ||
| 927 | query_processing_state = STATE_OK; | ||
| 928 | } else { | ||
| 929 | result.error_string = "no fields returned"; | ||
| 930 | // printf("WARNING - no fields returned\n"); | ||
| 931 | query_processing_state = STATE_WARNING; | ||
| 932 | } | ||
| 933 | } else if (dbi_result_first_row(res) != 1) { | ||
| 934 | if (metric != METRIC_QUERY_RESULT) { | ||
| 935 | query_processing_state = STATE_OK; | ||
| 936 | } else { | ||
| 937 | dbi_conn_error(conn, &result.error_string); | ||
| 938 | // np_dbi_print_error(conn, "CRITICAL - failed to fetch first row"); | ||
| 939 | query_processing_state = STATE_CRITICAL; | ||
| 940 | } | ||
| 941 | } else { | ||
| 942 | unsigned short field_type = dbi_result_get_field_type_idx(res, 1); | ||
| 943 | if (field_type != DBI_TYPE_ERROR) { | ||
| 944 | if (type == TYPE_STRING) { | ||
| 945 | result.result_string = | ||
| 946 | strdup(get_field_str(conn, res, field_type, metric, type)); | ||
| 947 | } else { | ||
| 948 | result.result_number = get_field(conn, res, &field_type, metric, type); | ||
| 949 | } | ||
| 950 | } else { | ||
| 951 | // Error when retrieving the field, that is OK if the Query result is not of | ||
| 952 | // interest | ||
| 953 | if (metric != METRIC_QUERY_RESULT) { | ||
| 954 | query_processing_state = STATE_OK; | ||
| 955 | } else { | ||
| 956 | dbi_conn_error(conn, &result.error_string); | ||
| 957 | // np_dbi_print_error(conn, "CRITICAL - failed to fetch data"); | ||
| 958 | query_processing_state = STATE_CRITICAL; | ||
| 959 | } | ||
| 960 | } | ||
| 961 | } | ||
| 815 | } | 962 | } |
| 963 | dbi_result_free(res); | ||
| 964 | |||
| 965 | result.query_processing_status = query_processing_state; | ||
| 816 | 966 | ||
| 817 | return status; | 967 | return result; |
| 818 | } | 968 | } |
| 819 | 969 | ||
| 820 | double timediff(struct timeval start, struct timeval end) { | 970 | double timediff(struct timeval start, struct timeval end) { |
