summaryrefslogtreecommitdiffstats
path: root/lib/output.c
diff options
context:
space:
mode:
authorLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2026-05-30 12:30:39 +0200
committerGitHub <noreply@github.com>2026-05-30 12:30:39 +0200
commit44e1913da4d227aaabb7b5ccfae65d879082a5e4 (patch)
treea0054efa808083974a2fc1b728104a3b86eadbe8 /lib/output.c
parente1cde41866912ff4369145842c6e47a93b17d5e2 (diff)
downloadmonitoring-plugins-master.tar.gz
Error summary (#2259)HEADmaster
* lib: properly name function to set summary * lib: set first non-ok subcheck as the summary for the overall check * Fetch summarily recursively from failed subchecks --------- Co-authored-by: Lorenz Kästle <lorenz.kaestle@netways.de>
Diffstat (limited to 'lib/output.c')
-rw-r--r--lib/output.c140
1 files changed, 129 insertions, 11 deletions
diff --git a/lib/output.c b/lib/output.c
index 3c04d63d..9bcd02d9 100644
--- a/lib/output.c
+++ b/lib/output.c
@@ -20,8 +20,53 @@ static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck che
20 unsigned int indentation); 20 unsigned int indentation);
21static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck); 21static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
22 22
23// mp_compare_state compares two state arguments
24// if *first* is WORSE than *second*, the result is < 0
25// if *first* is equal to *second*, the result is 0
26// if *first* is BETTER (less bad) the result is > 0
27static int mp_compare_state(mp_state_enum first, mp_state_enum second);
28
23// == Implementation == 29// == Implementation ==
24 30
31// get_subcheck_failed_output retrieves the output of the
32// worst and first leave node in a subcheck tree
33// or NULL if no such message exists
34// the return string is a copy of the original
35static char *get_subcheck_failed_output(const mp_subcheck tree) {
36 if (tree.subchecks == NULL) {
37 // this is a leave node
38 if (mp_compute_subcheck_state(tree) == STATE_OK) {
39 // ALL OK, nothing to return
40 return NULL;
41 }
42
43 char *result = strdup(tree.output);
44 return result;
45 }
46
47 // not a leave node, go through tree
48 mp_subcheck_list *subcheck = tree.subchecks;
49 mp_subcheck *worst_first_node = NULL;
50 mp_state_enum worst_state = STATE_OK;
51 while (subcheck != NULL) {
52 mp_state_enum current = mp_compute_subcheck_state(subcheck->subcheck);
53 if (mp_compare_state(current, worst_state) < 0) {
54 worst_first_node = &subcheck->subcheck;
55 }
56
57 subcheck = subcheck->next;
58 }
59
60 if (worst_first_node == NULL) {
61 // we did not find a failed subcheck, return the output
62 // of the current node
63 char *result = strdup(tree.output);
64 return result;
65 }
66
67 return get_subcheck_failed_output(*worst_first_node);
68}
69
25/* 70/*
26 * Generate output string for a mp_subcheck object 71 * Generate output string for a mp_subcheck object
27 */ 72 */
@@ -164,7 +209,7 @@ int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subchec
164 * Add a manual summary to a mp_check object, effectively replacing 209 * Add a manual summary to a mp_check object, effectively replacing
165 * the autogenerated one 210 * the autogenerated one
166 */ 211 */
167void mp_add_summary(mp_check check[static 1], char *summary) { check->summary = summary; } 212void mp_set_summary(mp_check check[static 1], char *summary) { check->summary = strdup(summary); }
168 213
169/* 214/*
170 * Generate the summary string of a mp_check object based on its subchecks 215 * Generate the summary string of a mp_check object based on its subchecks
@@ -172,31 +217,61 @@ void mp_add_summary(mp_check check[static 1], char *summary) { check->summary =
172char *get_subcheck_summary(mp_check check) { 217char *get_subcheck_summary(mp_check check) {
173 mp_subcheck_list *subchecks = check.subchecks; 218 mp_subcheck_list *subchecks = check.subchecks;
174 219
175 unsigned int ok = 0; 220 unsigned int ok_count = 0;
176 unsigned int warning = 0; 221 unsigned int warning_count = 0;
177 unsigned int critical = 0; 222 unsigned int critical_count = 0;
178 unsigned int unknown = 0; 223 unsigned int unknown_count = 0;
224 char *result = NULL;
179 while (subchecks != NULL) { 225 while (subchecks != NULL) {
180 switch (mp_compute_subcheck_state(subchecks->subcheck)) { 226 switch (mp_compute_subcheck_state(subchecks->subcheck)) {
181 case STATE_OK: 227 case STATE_OK:
182 ok++; 228 ok_count++;
183 break; 229 break;
184 case STATE_WARNING: 230 case STATE_WARNING:
185 warning++; 231 if (critical_count == 0 && unknown_count == 0 && warning_count == 0) {
232 // set summary to first warning subcheck output
233 asprintf(&result, "%s", get_subcheck_failed_output(subchecks->subcheck));
234 }
235 warning_count++;
186 break; 236 break;
187 case STATE_CRITICAL: 237 case STATE_CRITICAL:
188 critical++; 238 if (critical_count == 0) {
239 // set summary to first critical subcheck output
240 asprintf(&result, "%s", get_subcheck_failed_output(subchecks->subcheck));
241 }
242 critical_count++;
189 break; 243 break;
190 case STATE_UNKNOWN: 244 case STATE_UNKNOWN:
191 unknown++; 245 if (critical_count == 0 && unknown_count == 0) {
246 // set summary to first unknown subcheck output
247 asprintf(&result, "%s", get_subcheck_failed_output(subchecks->subcheck));
248 }
249 unknown_count++;
192 break; 250 break;
193 default: 251 default:
194 die(STATE_UNKNOWN, "Unknown state in get_subcheck_summary"); 252 die(STATE_UNKNOWN, "Unknown state in get_subcheck_summary");
195 } 253 }
196 subchecks = subchecks->next; 254 subchecks = subchecks->next;
197 } 255 }
198 char *result = NULL; 256
199 asprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown); 257 if (result == NULL) {
258 if (ok_count > 0) {
259 asprintf(&result, "ok=%d", ok_count);
260 }
261
262 if (warning_count > 0) {
263 asprintf(&result, "%swarning=%d", (result == NULL ? "" : ", "), warning_count);
264 }
265
266 if (critical_count > 0) {
267 asprintf(&result, "%scritical=%d", (result == NULL ? "" : ", "), critical_count);
268 }
269
270 if (unknown_count > 0) {
271 asprintf(&result, "%sunknown=%d", (result == NULL ? "" : ", "), unknown_count);
272 }
273 }
274
200 return result; 275 return result;
201} 276}
202 277
@@ -658,3 +733,46 @@ mp_state_enum mp_eval_unknown(mp_check overall) {
658 (void)overall; 733 (void)overall;
659 return STATE_UNKNOWN; 734 return STATE_UNKNOWN;
660} 735}
736
737static int mp_compare_state(mp_state_enum first, mp_state_enum second) {
738 switch (first) {
739 case STATE_OK:
740 switch (second) {
741 case STATE_OK:
742 return 0;
743 case STATE_WARNING:
744 case STATE_UNKNOWN:
745 case STATE_CRITICAL:
746 return 1;
747 }
748 case STATE_WARNING:
749 switch (second) {
750 case STATE_OK:
751 return -1;
752 case STATE_WARNING:
753 return 0;
754 case STATE_UNKNOWN:
755 case STATE_CRITICAL:
756 return 1;
757 }
758 case STATE_UNKNOWN:
759 switch (second) {
760 case STATE_OK:
761 case STATE_WARNING:
762 return -1;
763 case STATE_UNKNOWN:
764 return 0;
765 case STATE_CRITICAL:
766 return 1;
767 }
768 case STATE_CRITICAL:
769 switch (second) {
770 case STATE_OK:
771 case STATE_WARNING:
772 case STATE_UNKNOWN:
773 return -1;
774 case STATE_CRITICAL:
775 return 0;
776 }
777 }
778}