diff options
author | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-03-13 23:41:12 +0100 |
---|---|---|
committer | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-03-13 23:41:12 +0100 |
commit | 08a475a14fff2d0eee2e49f4765cb286cac8d2e2 (patch) | |
tree | c82e2353e6db519648983d24fe63f1ca480a119c | |
parent | f2900e0ccf18f321857e4072681ad9c10a0cb67f (diff) | |
download | monitoring-plugins-08a475a1.tar.gz |
Refactor check_load + new ouput
-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 | } | ||