diff options
| -rw-r--r-- | plugins/Makefile.am | 1 | ||||
| -rw-r--r-- | plugins/check_load.c | 420 | ||||
| -rw-r--r-- | plugins/check_load.d/config.h | 30 |
3 files changed, 274 insertions, 177 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 30ca63d1..f395e594 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am | |||
| @@ -56,6 +56,7 @@ EXTRA_DIST = t \ | |||
| 56 | check_game.d \ | 56 | check_game.d \ |
| 57 | check_radius.d \ | 57 | check_radius.d \ |
| 58 | check_time.d \ | 58 | check_time.d \ |
| 59 | check_load.d \ | ||
| 59 | check_nagios.d \ | 60 | check_nagios.d \ |
| 60 | check_dbi.d \ | 61 | check_dbi.d \ |
| 61 | check_tcp.d \ | 62 | check_tcp.d \ |
diff --git a/plugins/check_load.c b/plugins/check_load.c index e3a45f58..57be8c69 100644 --- a/plugins/check_load.c +++ b/plugins/check_load.c | |||
| @@ -28,6 +28,9 @@ | |||
| 28 | * | 28 | * |
| 29 | *****************************************************************************/ | 29 | *****************************************************************************/ |
| 30 | 30 | ||
| 31 | #include "output.h" | ||
| 32 | #include "perfdata.h" | ||
| 33 | #include "thresholds.h" | ||
| 31 | const char *progname = "check_load"; | 34 | const char *progname = "check_load"; |
| 32 | const char *copyright = "1999-2022"; | 35 | const char *copyright = "1999-2022"; |
| 33 | const char *email = "devel@monitoring-plugins.org"; | 36 | const char *email = "devel@monitoring-plugins.org"; |
| @@ -36,6 +39,10 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 36 | #include "./runcmd.h" | 39 | #include "./runcmd.h" |
| 37 | #include "./utils.h" | 40 | #include "./utils.h" |
| 38 | #include "./popen.h" | 41 | #include "./popen.h" |
| 42 | #include "states.h" | ||
| 43 | #include "check_load.d/config.h" | ||
| 44 | |||
| 45 | #include "../gl/stdlib.h" | ||
| 39 | 46 | ||
| 40 | #include <string.h> | 47 | #include <string.h> |
| 41 | 48 | ||
| @@ -50,70 +57,68 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 50 | # define LOADAVG_15MIN 2 | 57 | # define LOADAVG_15MIN 2 |
| 51 | #endif /* !defined LOADAVG_1MIN */ | 58 | #endif /* !defined LOADAVG_1MIN */ |
| 52 | 59 | ||
| 53 | static int process_arguments(int argc, char **argv); | 60 | typedef struct { |
| 54 | static int validate_arguments(void); | 61 | int errorcode; |
| 62 | check_load_config config; | ||
| 63 | } check_load_config_wrapper; | ||
| 64 | static check_load_config_wrapper process_arguments(int argc, char **argv); | ||
| 65 | static check_load_config_wrapper validate_arguments(check_load_config_wrapper /*config_wrapper*/); | ||
| 66 | |||
| 55 | void print_help(void); | 67 | void print_help(void); |
| 56 | void print_usage(void); | 68 | void print_usage(void); |
| 57 | static int print_top_consuming_processes(); | 69 | typedef struct { |
| 58 | 70 | int errorcode; | |
| 59 | static int n_procs_to_show = 0; | 71 | char **top_processes; |
| 60 | 72 | } top_processes_result; | |
| 61 | /* strictly for pretty-print usage in loops */ | 73 | static top_processes_result print_top_consuming_processes(int /*n_procs_to_show*/); |
| 62 | static const int nums[3] = {1, 5, 15}; | 74 | |
| 63 | 75 | typedef struct { | |
| 64 | /* provide some fairly sane defaults */ | 76 | mp_range load[3]; |
| 65 | double wload[3] = {0.0, 0.0, 0.0}; | 77 | } parsed_thresholds; |
| 66 | double cload[3] = {0.0, 0.0, 0.0}; | 78 | static parsed_thresholds get_threshold(char *arg) { |
| 67 | #define la1 la[0] | 79 | size_t index; |
| 68 | #define la5 la[1] | 80 | char *str = arg; |
| 69 | #define la15 la[2] | 81 | char *tmp_pointer; |
| 70 | 82 | bool valid = false; | |
| 71 | char *status_line; | 83 | |
| 72 | bool take_into_account_cpus = false; | 84 | parsed_thresholds result = { |
| 73 | 85 | .load[0] = mp_range_init(), | |
| 74 | static void get_threshold(char *arg, double *th) { | 86 | .load[1] = mp_range_init(), |
| 75 | size_t i, n; | 87 | .load[2] = mp_range_init(), |
| 76 | int valid = 0; | 88 | }; |
| 77 | char *str = arg, *p; | 89 | |
| 78 | 90 | size_t arg_length = strlen(arg); | |
| 79 | n = strlen(arg); | 91 | for (index = 0; index < 3; index++) { |
| 80 | for (i = 0; i < 3; i++) { | 92 | double tmp = strtod(str, &tmp_pointer); |
| 81 | th[i] = strtod(str, &p); | 93 | if (tmp_pointer == str) { |
| 82 | if (p == str) { | ||
| 83 | break; | 94 | break; |
| 84 | } | 95 | } |
| 85 | 96 | ||
| 86 | valid = 1; | 97 | result.load[index] = mp_range_set_end(result.load[index], mp_create_pd_value(tmp)); |
| 87 | str = p + 1; | 98 | |
| 88 | if (n <= (size_t)(str - arg)) { | 99 | valid = true; |
| 100 | str = tmp_pointer + 1; | ||
| 101 | if (arg_length <= (size_t)(str - arg)) { | ||
| 89 | break; | 102 | break; |
| 90 | } | 103 | } |
| 91 | } | 104 | } |
| 92 | 105 | ||
| 93 | /* empty argument or non-floatish, so warn about it and die */ | 106 | /* empty argument or non-floatish, so warn about it and die */ |
| 94 | if (!i && !valid) { | 107 | if (!index && !valid) { |
| 95 | usage(_("Warning threshold must be float or float triplet!\n")); | 108 | usage(_("Warning threshold must be float or float triplet!\n")); |
| 96 | } | 109 | } |
| 97 | 110 | ||
| 98 | if (i != 2) { | 111 | if (index != 2) { |
| 99 | /* one or more numbers were given, so fill array with last | 112 | /* one or more numbers were given, so fill array with last |
| 100 | * we got (most likely to NOT produce the least expected result) */ | 113 | * we got (most likely to NOT produce the least expected result) */ |
| 101 | for (n = i; n < 3; n++) { | 114 | for (size_t tmp_index = index; tmp_index < 3; tmp_index++) { |
| 102 | th[n] = th[i]; | 115 | result.load[tmp_index] = result.load[index]; |
| 103 | } | 116 | } |
| 104 | } | 117 | } |
| 118 | return result; | ||
| 105 | } | 119 | } |
| 106 | 120 | ||
| 107 | int main(int argc, char **argv) { | 121 | int main(int argc, char **argv) { |
| 108 | int result = -1; | ||
| 109 | int i; | ||
| 110 | long numcpus; | ||
| 111 | |||
| 112 | double la[3] = {0.0, 0.0, 0.0}; /* NetBSD complains about uninitialized arrays */ | ||
| 113 | #ifndef HAVE_GETLOADAVG | ||
| 114 | char input_buffer[MAX_INPUT_BUFFER]; | ||
| 115 | #endif | ||
| 116 | |||
| 117 | setlocale(LC_ALL, ""); | 122 | setlocale(LC_ALL, ""); |
| 118 | bindtextdomain(PACKAGE, LOCALEDIR); | 123 | bindtextdomain(PACKAGE, LOCALEDIR); |
| 119 | textdomain(PACKAGE); | 124 | textdomain(PACKAGE); |
| @@ -122,112 +127,138 @@ int main(int argc, char **argv) { | |||
| 122 | /* Parse extra opts if any */ | 127 | /* Parse extra opts if any */ |
| 123 | argv = np_extra_opts(&argc, argv, progname); | 128 | argv = np_extra_opts(&argc, argv, progname); |
| 124 | 129 | ||
| 125 | if (process_arguments(argc, argv) == ERROR) { | 130 | check_load_config_wrapper tmp_config = process_arguments(argc, argv); |
| 131 | if (tmp_config.errorcode == ERROR) { | ||
| 126 | usage4(_("Could not parse arguments")); | 132 | usage4(_("Could not parse arguments")); |
| 127 | } | 133 | } |
| 128 | 134 | ||
| 129 | #ifdef HAVE_GETLOADAVG | 135 | const check_load_config config = tmp_config.config; |
| 130 | result = getloadavg(la, 3); | ||
| 131 | if (result != 3) { | ||
| 132 | return STATE_UNKNOWN; | ||
| 133 | } | ||
| 134 | #else | ||
| 135 | child_process = spopen(PATH_TO_UPTIME); | ||
| 136 | if (child_process == NULL) { | ||
| 137 | printf(_("Error opening %s\n"), PATH_TO_UPTIME); | ||
| 138 | return STATE_UNKNOWN; | ||
| 139 | } | ||
| 140 | child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r"); | ||
| 141 | if (child_stderr == NULL) { | ||
| 142 | printf(_("Could not open stderr for %s\n"), PATH_TO_UPTIME); | ||
| 143 | } | ||
| 144 | fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); | ||
| 145 | if (strstr(input_buffer, "load average:")) { | ||
| 146 | sscanf(input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15); | ||
| 147 | } else if (strstr(input_buffer, "load averages:")) { | ||
| 148 | sscanf(input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15); | ||
| 149 | } else { | ||
| 150 | printf(_("could not parse load from uptime %s: %d\n"), PATH_TO_UPTIME, result); | ||
| 151 | return STATE_UNKNOWN; | ||
| 152 | } | ||
| 153 | 136 | ||
| 154 | result = spclose(child_process); | 137 | double load_values[3] = {0, 0, 0}; |
| 155 | if (result) { | ||
| 156 | printf(_("Error code %d returned in %s\n"), result, PATH_TO_UPTIME); | ||
| 157 | return STATE_UNKNOWN; | ||
| 158 | } | ||
| 159 | #endif | ||
| 160 | 138 | ||
| 161 | if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) { | 139 | int error = getloadavg(load_values, 3); |
| 162 | #ifdef HAVE_GETLOADAVG | 140 | if (error != 3) { |
| 163 | printf(_("Error in getloadavg()\n")); | 141 | die(STATE_UNKNOWN, _("Failed to retrieve load values")); |
| 164 | #else | ||
| 165 | printf(_("Error processing %s\n"), PATH_TO_UPTIME); | ||
| 166 | #endif | ||
| 167 | return STATE_UNKNOWN; | ||
| 168 | } | 142 | } |
| 169 | 143 | ||
| 170 | /* we got this far, so assume OK until we've measured */ | 144 | mp_check overall = mp_check_init(); |
| 171 | result = STATE_OK; | 145 | if (config.output_format_set) { |
| 172 | 146 | mp_set_format(config.output_format); | |
| 173 | xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15); | 147 | } |
| 174 | xasprintf(&status_line, ("total %s"), status_line); | ||
| 175 | 148 | ||
| 176 | double scaled_la[3] = {0.0, 0.0, 0.0}; | ||
| 177 | bool is_using_scaled_load_values = false; | 149 | bool is_using_scaled_load_values = false; |
| 178 | 150 | long numcpus; | |
| 179 | if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) { | 151 | if (config.take_into_account_cpus && ((numcpus = GET_NUMBER_OF_CPUS()) > 0)) { |
| 180 | is_using_scaled_load_values = true; | 152 | is_using_scaled_load_values = true; |
| 181 | 153 | ||
| 182 | scaled_la[0] = la[0] / numcpus; | 154 | double scaled_la[3] = {0.0, 0.0, 0.0}; |
| 183 | scaled_la[1] = la[1] / numcpus; | 155 | scaled_la[0] = load_values[0] / numcpus; |
| 184 | scaled_la[2] = la[2] / numcpus; | 156 | scaled_la[1] = load_values[1] / numcpus; |
| 157 | scaled_la[2] = load_values[2] / numcpus; | ||
| 158 | |||
| 159 | mp_subcheck scaled_load_sc = mp_subcheck_init(); | ||
| 160 | scaled_load_sc = mp_set_subcheck_default_state(scaled_load_sc, STATE_OK); | ||
| 161 | scaled_load_sc.output = "Scaled Load (divided by number of CPUs"; | ||
| 162 | |||
| 163 | mp_perfdata pd_scaled_load1 = perfdata_init(); | ||
| 164 | pd_scaled_load1.label = "scaled_load1"; | ||
| 165 | pd_scaled_load1 = mp_set_pd_value(pd_scaled_load1, scaled_la[0]); | ||
| 166 | pd_scaled_load1 = mp_pd_set_thresholds(pd_scaled_load1, config.th_load[0]); | ||
| 167 | |||
| 168 | mp_subcheck scaled_load_sc1 = mp_subcheck_init(); | ||
| 169 | scaled_load_sc1 = mp_set_subcheck_state(scaled_load_sc1, mp_get_pd_status(pd_scaled_load1)); | ||
| 170 | mp_add_perfdata_to_subcheck(&scaled_load_sc1, pd_scaled_load1); | ||
| 171 | xasprintf(&scaled_load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_scaled_load1.value)); | ||
| 172 | mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc1); | ||
| 173 | |||
| 174 | mp_perfdata pd_scaled_load5 = perfdata_init(); | ||
| 175 | pd_scaled_load5.label = "scaled_load5"; | ||
| 176 | pd_scaled_load5 = mp_set_pd_value(pd_scaled_load5, scaled_la[1]); | ||
| 177 | pd_scaled_load5 = mp_pd_set_thresholds(pd_scaled_load5, config.th_load[1]); | ||
| 178 | |||
| 179 | mp_subcheck scaled_load_sc5 = mp_subcheck_init(); | ||
| 180 | scaled_load_sc5 = mp_set_subcheck_state(scaled_load_sc5, mp_get_pd_status(pd_scaled_load5)); | ||
| 181 | mp_add_perfdata_to_subcheck(&scaled_load_sc5, pd_scaled_load5); | ||
| 182 | xasprintf(&scaled_load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_scaled_load5.value)); | ||
| 183 | mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc5); | ||
| 184 | |||
| 185 | mp_perfdata pd_scaled_load15 = perfdata_init(); | ||
| 186 | pd_scaled_load15.label = "scaled_load15"; | ||
| 187 | pd_scaled_load15 = mp_set_pd_value(pd_scaled_load15, scaled_la[2]); | ||
| 188 | pd_scaled_load15 = mp_pd_set_thresholds(pd_scaled_load15, config.th_load[2]); | ||
| 189 | |||
| 190 | mp_subcheck scaled_load_sc15 = mp_subcheck_init(); | ||
| 191 | scaled_load_sc15 = mp_set_subcheck_state(scaled_load_sc15, mp_get_pd_status(pd_scaled_load15)); | ||
| 192 | mp_add_perfdata_to_subcheck(&scaled_load_sc15, pd_scaled_load15); | ||
| 193 | xasprintf(&scaled_load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_scaled_load15.value)); | ||
| 194 | mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc15); | ||
| 195 | |||
| 196 | mp_add_subcheck_to_check(&overall, scaled_load_sc); | ||
| 197 | } | ||
| 198 | |||
| 199 | mp_subcheck load_sc = mp_subcheck_init(); | ||
| 200 | load_sc = mp_set_subcheck_default_state(load_sc, STATE_OK); | ||
| 201 | load_sc.output = "Total Load"; | ||
| 185 | 202 | ||
| 186 | char *tmp = NULL; | 203 | mp_perfdata pd_load1 = perfdata_init(); |
| 187 | xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]); | 204 | pd_load1.label = "load1"; |
| 188 | xasprintf(&status_line, "scaled %s - %s", tmp, status_line); | 205 | pd_load1 = mp_set_pd_value(pd_load1, load_values[0]); |
| 206 | if (!is_using_scaled_load_values) { | ||
| 207 | pd_load1 = mp_pd_set_thresholds(pd_load1, config.th_load[0]); | ||
| 189 | } | 208 | } |
| 190 | 209 | ||
| 191 | for (i = 0; i < 3; i++) { | 210 | mp_subcheck load_sc1 = mp_subcheck_init(); |
| 192 | if (is_using_scaled_load_values) { | 211 | load_sc1 = mp_set_subcheck_state(load_sc1, mp_get_pd_status(pd_load1)); |
| 193 | if (scaled_la[i] > cload[i]) { | 212 | mp_add_perfdata_to_subcheck(&load_sc1, pd_load1); |
| 194 | result = STATE_CRITICAL; | 213 | xasprintf(&load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_load1.value)); |
| 195 | break; | 214 | mp_add_subcheck_to_subcheck(&load_sc, load_sc1); |
| 196 | } else if (scaled_la[i] > wload[i]) { | 215 | |
| 197 | result = STATE_WARNING; | 216 | mp_perfdata pd_load5 = perfdata_init(); |
| 198 | } | 217 | pd_load5.label = "load5"; |
| 199 | } else { | 218 | pd_load5 = mp_set_pd_value(pd_load5, load_values[1]); |
| 200 | if (la[i] > cload[i]) { | 219 | if (!is_using_scaled_load_values) { |
| 201 | result = STATE_CRITICAL; | 220 | pd_load5 = mp_pd_set_thresholds(pd_load5, config.th_load[1]); |
| 202 | break; | ||
| 203 | } else if (la[i] > wload[i]) { | ||
| 204 | result = STATE_WARNING; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | 221 | } |
| 208 | 222 | ||
| 209 | printf("LOAD %s - %s|", state_text(result), status_line); | 223 | mp_subcheck load_sc5 = mp_subcheck_init(); |
| 210 | for (i = 0; i < 3; i++) { | 224 | load_sc5 = mp_set_subcheck_state(load_sc5, mp_get_pd_status(pd_load5)); |
| 211 | if (is_using_scaled_load_values) { | 225 | mp_add_perfdata_to_subcheck(&load_sc5, pd_load5); |
| 212 | printf("load%d=%.3f;;;0; ", nums[i], la[i]); | 226 | xasprintf(&load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_load5.value)); |
| 213 | printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]); | 227 | mp_add_subcheck_to_subcheck(&load_sc, load_sc5); |
| 214 | } else { | 228 | |
| 215 | printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]); | 229 | mp_perfdata pd_load15 = perfdata_init(); |
| 216 | } | 230 | pd_load15.label = "load15"; |
| 231 | pd_load15 = mp_set_pd_value(pd_load15, load_values[2]); | ||
| 232 | if (!is_using_scaled_load_values) { | ||
| 233 | pd_load15 = mp_pd_set_thresholds(pd_load15, config.th_load[2]); | ||
| 217 | } | 234 | } |
| 218 | 235 | ||
| 219 | putchar('\n'); | 236 | mp_subcheck load_sc15 = mp_subcheck_init(); |
| 220 | if (n_procs_to_show > 0) { | 237 | load_sc15 = mp_set_subcheck_state(load_sc15, mp_get_pd_status(pd_load15)); |
| 221 | print_top_consuming_processes(); | 238 | mp_add_perfdata_to_subcheck(&load_sc15, pd_load15); |
| 239 | xasprintf(&load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_load15.value)); | ||
| 240 | mp_add_subcheck_to_subcheck(&load_sc, load_sc15); | ||
| 241 | |||
| 242 | mp_add_subcheck_to_check(&overall, load_sc); | ||
| 243 | |||
| 244 | if (config.n_procs_to_show > 0) { | ||
| 245 | mp_subcheck top_proc_sc = mp_subcheck_init(); | ||
| 246 | top_proc_sc = mp_set_subcheck_state(top_proc_sc, STATE_OK); | ||
| 247 | top_processes_result top_proc = print_top_consuming_processes(config.n_procs_to_show); | ||
| 248 | top_proc_sc.output = ""; | ||
| 249 | |||
| 250 | if (top_proc.errorcode == OK) { | ||
| 251 | for (int i = 0; i < config.n_procs_to_show; i++) { | ||
| 252 | xasprintf(&top_proc_sc.output, "%s\n%s", top_proc_sc.output, top_proc.top_processes[i]); | ||
| 253 | } | ||
| 254 | } | ||
| 222 | } | 255 | } |
| 223 | return result; | 256 | |
| 257 | mp_exit(overall); | ||
| 224 | } | 258 | } |
| 225 | 259 | ||
| 226 | /* process command-line arguments */ | 260 | /* process command-line arguments */ |
| 227 | static int process_arguments(int argc, char **argv) { | 261 | static check_load_config_wrapper process_arguments(int argc, char **argv) { |
| 228 | int c = 0; | ||
| 229 | |||
| 230 | int option = 0; | ||
| 231 | static struct option longopts[] = {{"warning", required_argument, 0, 'w'}, | 262 | static struct option longopts[] = {{"warning", required_argument, 0, 'w'}, |
| 232 | {"critical", required_argument, 0, 'c'}, | 263 | {"critical", required_argument, 0, 'c'}, |
| 233 | {"percpu", no_argument, 0, 'r'}, | 264 | {"percpu", no_argument, 0, 'r'}, |
| @@ -236,26 +267,45 @@ static int process_arguments(int argc, char **argv) { | |||
| 236 | {"procs-to-show", required_argument, 0, 'n'}, | 267 | {"procs-to-show", required_argument, 0, 'n'}, |
| 237 | {0, 0, 0, 0}}; | 268 | {0, 0, 0, 0}}; |
| 238 | 269 | ||
| 270 | check_load_config_wrapper result = { | ||
| 271 | .errorcode = OK, | ||
| 272 | .config = check_load_config_init(), | ||
| 273 | }; | ||
| 274 | |||
| 239 | if (argc < 2) { | 275 | if (argc < 2) { |
| 240 | return ERROR; | 276 | result.errorcode = ERROR; |
| 277 | return result; | ||
| 241 | } | 278 | } |
| 242 | 279 | ||
| 243 | while (1) { | 280 | while (true) { |
| 244 | c = getopt_long(argc, argv, "Vhrc:w:n:", longopts, &option); | 281 | int option = 0; |
| 282 | int option_index = getopt_long(argc, argv, "Vhrc:w:n:", longopts, &option); | ||
| 245 | 283 | ||
| 246 | if (c == -1 || c == EOF) { | 284 | if (option_index == -1 || option_index == EOF) { |
| 247 | break; | 285 | break; |
| 248 | } | 286 | } |
| 249 | 287 | ||
| 250 | switch (c) { | 288 | switch (option_index) { |
| 251 | case 'w': /* warning time threshold */ | 289 | case 'w': /* warning time threshold */ { |
| 252 | get_threshold(optarg, wload); | 290 | parsed_thresholds warning_range = get_threshold(optarg); |
| 253 | break; | 291 | result.config.th_load[0].warning = warning_range.load[0]; |
| 254 | case 'c': /* critical time threshold */ | 292 | result.config.th_load[0].warning_is_set = true; |
| 255 | get_threshold(optarg, cload); | 293 | result.config.th_load[1].warning = warning_range.load[1]; |
| 256 | break; | 294 | result.config.th_load[1].warning_is_set = true; |
| 295 | result.config.th_load[2].warning = warning_range.load[2]; | ||
| 296 | result.config.th_load[2].warning_is_set = true; | ||
| 297 | } break; | ||
| 298 | case 'c': /* critical time threshold */ { | ||
| 299 | parsed_thresholds critical_range = get_threshold(optarg); | ||
| 300 | result.config.th_load[0].critical = critical_range.load[0]; | ||
| 301 | result.config.th_load[0].critical_is_set = true; | ||
| 302 | result.config.th_load[1].critical = critical_range.load[1]; | ||
| 303 | result.config.th_load[1].critical_is_set = true; | ||
| 304 | result.config.th_load[2].critical = critical_range.load[2]; | ||
| 305 | result.config.th_load[2].critical_is_set = true; | ||
| 306 | } break; | ||
| 257 | case 'r': /* Divide load average by number of CPUs */ | 307 | case 'r': /* Divide load average by number of CPUs */ |
| 258 | take_into_account_cpus = true; | 308 | result.config.take_into_account_cpus = true; |
| 259 | break; | 309 | break; |
| 260 | case 'V': /* version */ | 310 | case 'V': /* version */ |
| 261 | print_revision(progname, NP_VERSION); | 311 | print_revision(progname, NP_VERSION); |
| @@ -264,49 +314,49 @@ static int process_arguments(int argc, char **argv) { | |||
| 264 | print_help(); | 314 | print_help(); |
| 265 | exit(STATE_UNKNOWN); | 315 | exit(STATE_UNKNOWN); |
| 266 | case 'n': | 316 | case 'n': |
| 267 | n_procs_to_show = atoi(optarg); | 317 | result.config.n_procs_to_show = atoi(optarg); |
| 268 | break; | 318 | break; |
| 269 | case '?': /* help */ | 319 | case '?': /* help */ |
| 270 | usage5(); | 320 | usage5(); |
| 271 | } | 321 | } |
| 272 | } | 322 | } |
| 273 | 323 | ||
| 274 | c = optind; | 324 | int index = optind; |
| 275 | if (c == argc) { | 325 | if (index == argc) { |
| 276 | return validate_arguments(); | 326 | return validate_arguments(result); |
| 277 | } | 327 | } |
| 278 | 328 | ||
| 279 | /* handle the case if both arguments are missing, | 329 | /* handle the case if both arguments are missing, |
| 280 | * but not if only one is given without -c or -w flag */ | 330 | * but not if only one is given without -c or -w flag */ |
| 281 | if (c - argc == 2) { | 331 | if (index - argc == 2) { |
| 282 | get_threshold(argv[c++], wload); | 332 | parsed_thresholds warning_range = get_threshold(argv[index++]); |
| 283 | get_threshold(argv[c++], cload); | 333 | result.config.th_load[0].warning = warning_range.load[0]; |
| 284 | } else if (c - argc == 1) { | 334 | result.config.th_load[0].warning_is_set = true; |
| 285 | get_threshold(argv[c++], cload); | 335 | result.config.th_load[1].warning = warning_range.load[1]; |
| 336 | result.config.th_load[1].warning_is_set = true; | ||
| 337 | result.config.th_load[2].warning = warning_range.load[2]; | ||
| 338 | result.config.th_load[2].warning_is_set = true; | ||
| 339 | parsed_thresholds critical_range = get_threshold(argv[index++]); | ||
| 340 | result.config.th_load[0].critical = critical_range.load[0]; | ||
| 341 | result.config.th_load[0].critical_is_set = true; | ||
| 342 | result.config.th_load[1].critical = critical_range.load[1]; | ||
| 343 | result.config.th_load[1].critical_is_set = true; | ||
| 344 | result.config.th_load[2].critical = critical_range.load[2]; | ||
| 345 | result.config.th_load[2].critical_is_set = true; | ||
| 346 | } else if (index - argc == 1) { | ||
| 347 | parsed_thresholds critical_range = get_threshold(argv[index++]); | ||
| 348 | result.config.th_load[0].critical = critical_range.load[0]; | ||
| 349 | result.config.th_load[0].critical_is_set = true; | ||
| 350 | result.config.th_load[1].critical = critical_range.load[1]; | ||
| 351 | result.config.th_load[1].critical_is_set = true; | ||
| 352 | result.config.th_load[2].critical = critical_range.load[2]; | ||
| 353 | result.config.th_load[2].critical_is_set = true; | ||
| 286 | } | 354 | } |
| 287 | 355 | ||
| 288 | return validate_arguments(); | 356 | return validate_arguments(result); |
| 289 | } | 357 | } |
| 290 | 358 | ||
| 291 | static int validate_arguments(void) { | 359 | static check_load_config_wrapper validate_arguments(check_load_config_wrapper config_wrapper) { return config_wrapper; } |
| 292 | int i = 0; | ||
| 293 | |||
| 294 | /* match cload first, as it will give the most friendly error message | ||
| 295 | * if user hasn't given the -c switch properly */ | ||
| 296 | for (i = 0; i < 3; i++) { | ||
| 297 | if (cload[i] < 0) { | ||
| 298 | die(STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]); | ||
| 299 | } | ||
| 300 | if (wload[i] < 0) { | ||
| 301 | die(STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]); | ||
| 302 | } | ||
| 303 | if (wload[i] > cload[i]) { | ||
| 304 | die(STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | return OK; | ||
| 309 | } | ||
| 310 | 360 | ||
| 311 | void print_help(void) { | 361 | void print_help(void) { |
| 312 | print_revision(progname, NP_VERSION); | 362 | print_revision(progname, NP_VERSION); |
| @@ -363,23 +413,39 @@ int cmpstringp(const void *p1, const void *p2) { | |||
| 363 | } | 413 | } |
| 364 | #endif /* PS_USES_PROCPCPU */ | 414 | #endif /* PS_USES_PROCPCPU */ |
| 365 | 415 | ||
| 366 | static int print_top_consuming_processes() { | 416 | static top_processes_result print_top_consuming_processes(int n_procs_to_show) { |
| 367 | int i = 0; | 417 | top_processes_result result = { |
| 368 | struct output chld_out, chld_err; | 418 | .errorcode = OK, |
| 419 | }; | ||
| 420 | struct output chld_out; | ||
| 421 | struct output chld_err; | ||
| 369 | if (np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0) { | 422 | if (np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0) { |
| 370 | fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND); | 423 | fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND); |
| 371 | return STATE_UNKNOWN; | 424 | result.errorcode = ERROR; |
| 425 | return result; | ||
| 372 | } | 426 | } |
| 427 | |||
| 373 | if (chld_out.lines < 2) { | 428 | if (chld_out.lines < 2) { |
| 374 | fprintf(stderr, _("some error occurred getting procs list.\n")); | 429 | fprintf(stderr, _("some error occurred getting procs list.\n")); |
| 375 | return STATE_UNKNOWN; | 430 | result.errorcode = ERROR; |
| 431 | return result; | ||
| 376 | } | 432 | } |
| 433 | |||
| 377 | #ifdef PS_USES_PROCPCPU | 434 | #ifdef PS_USES_PROCPCPU |
| 378 | qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char *), cmpstringp); | 435 | qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char *), cmpstringp); |
| 379 | #endif /* PS_USES_PROCPCPU */ | 436 | #endif /* PS_USES_PROCPCPU */ |
| 380 | int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) ? (int)chld_out.lines : n_procs_to_show + 1; | 437 | int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) ? (int)chld_out.lines : n_procs_to_show + 1; |
| 381 | for (i = 0; i < lines_to_show; i += 1) { | 438 | |
| 382 | printf("%s\n", chld_out.line[i]); | 439 | result.top_processes = calloc(lines_to_show, sizeof(char *)); |
| 440 | if (result.top_processes == NULL) { | ||
| 441 | // Failed allocation | ||
| 442 | result.errorcode = ERROR; | ||
| 443 | return result; | ||
| 383 | } | 444 | } |
| 384 | return OK; | 445 | |
| 446 | for (int i = 0; i < lines_to_show; i += 1) { | ||
| 447 | xasprintf(&result.top_processes[i], "%s", chld_out.line[i]); | ||
| 448 | } | ||
| 449 | |||
| 450 | return result; | ||
| 385 | } | 451 | } |
diff --git a/plugins/check_load.d/config.h b/plugins/check_load.d/config.h new file mode 100644 index 00000000..d399c19c --- /dev/null +++ b/plugins/check_load.d/config.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "output.h" | ||
| 4 | #include "thresholds.h" | ||
| 5 | typedef struct { | ||
| 6 | mp_thresholds th_load[3]; | ||
| 7 | |||
| 8 | bool take_into_account_cpus; | ||
| 9 | int n_procs_to_show; | ||
| 10 | |||
| 11 | mp_output_format output_format; | ||
| 12 | bool output_format_set; | ||
| 13 | } check_load_config; | ||
| 14 | |||
| 15 | check_load_config check_load_config_init() { | ||
| 16 | check_load_config tmp = { | ||
| 17 | .th_load = | ||
| 18 | { | ||
| 19 | mp_thresholds_init(), | ||
| 20 | mp_thresholds_init(), | ||
| 21 | mp_thresholds_init(), | ||
| 22 | }, | ||
| 23 | |||
| 24 | .take_into_account_cpus = false, | ||
| 25 | .n_procs_to_show = 0, | ||
| 26 | |||
| 27 | .output_format_set = false, | ||
| 28 | }; | ||
| 29 | return tmp; | ||
| 30 | } | ||
