[monitoring-plugins] Error summary (#2259)
GitHub
git at monitoring-plugins.org
Sat May 30 12:40:12 CEST 2026
Module: monitoring-plugins
Branch: master
Commit: 44e1913da4d227aaabb7b5ccfae65d879082a5e4
Author: Lorenz Kästle <12514511+RincewindsHat at users.noreply.github.com>
Committer: GitHub <noreply at github.com>
Date: Sat May 30 12:30:39 2026 +0200
URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=44e1913d
Error summary (#2259)
* 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 at netways.de>
---
lib/output.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
lib/output.h | 2 +-
2 files changed, 130 insertions(+), 12 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
unsigned int indentation);
static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
+// mp_compare_state compares two state arguments
+// if *first* is WORSE than *second*, the result is < 0
+// if *first* is equal to *second*, the result is 0
+// if *first* is BETTER (less bad) the result is > 0
+static int mp_compare_state(mp_state_enum first, mp_state_enum second);
+
// == Implementation ==
+// get_subcheck_failed_output retrieves the output of the
+// worst and first leave node in a subcheck tree
+// or NULL if no such message exists
+// the return string is a copy of the original
+static char *get_subcheck_failed_output(const mp_subcheck tree) {
+ if (tree.subchecks == NULL) {
+ // this is a leave node
+ if (mp_compute_subcheck_state(tree) == STATE_OK) {
+ // ALL OK, nothing to return
+ return NULL;
+ }
+
+ char *result = strdup(tree.output);
+ return result;
+ }
+
+ // not a leave node, go through tree
+ mp_subcheck_list *subcheck = tree.subchecks;
+ mp_subcheck *worst_first_node = NULL;
+ mp_state_enum worst_state = STATE_OK;
+ while (subcheck != NULL) {
+ mp_state_enum current = mp_compute_subcheck_state(subcheck->subcheck);
+ if (mp_compare_state(current, worst_state) < 0) {
+ worst_first_node = &subcheck->subcheck;
+ }
+
+ subcheck = subcheck->next;
+ }
+
+ if (worst_first_node == NULL) {
+ // we did not find a failed subcheck, return the output
+ // of the current node
+ char *result = strdup(tree.output);
+ return result;
+ }
+
+ return get_subcheck_failed_output(*worst_first_node);
+}
+
/*
* Generate output string for a mp_subcheck object
*/
@@ -164,7 +209,7 @@ int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subchec
* Add a manual summary to a mp_check object, effectively replacing
* the autogenerated one
*/
-void mp_add_summary(mp_check check[static 1], char *summary) { check->summary = summary; }
+void mp_set_summary(mp_check check[static 1], char *summary) { check->summary = strdup(summary); }
/*
* 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 =
char *get_subcheck_summary(mp_check check) {
mp_subcheck_list *subchecks = check.subchecks;
- unsigned int ok = 0;
- unsigned int warning = 0;
- unsigned int critical = 0;
- unsigned int unknown = 0;
+ unsigned int ok_count = 0;
+ unsigned int warning_count = 0;
+ unsigned int critical_count = 0;
+ unsigned int unknown_count = 0;
+ char *result = NULL;
while (subchecks != NULL) {
switch (mp_compute_subcheck_state(subchecks->subcheck)) {
case STATE_OK:
- ok++;
+ ok_count++;
break;
case STATE_WARNING:
- warning++;
+ if (critical_count == 0 && unknown_count == 0 && warning_count == 0) {
+ // set summary to first warning subcheck output
+ asprintf(&result, "%s", get_subcheck_failed_output(subchecks->subcheck));
+ }
+ warning_count++;
break;
case STATE_CRITICAL:
- critical++;
+ if (critical_count == 0) {
+ // set summary to first critical subcheck output
+ asprintf(&result, "%s", get_subcheck_failed_output(subchecks->subcheck));
+ }
+ critical_count++;
break;
case STATE_UNKNOWN:
- unknown++;
+ if (critical_count == 0 && unknown_count == 0) {
+ // set summary to first unknown subcheck output
+ asprintf(&result, "%s", get_subcheck_failed_output(subchecks->subcheck));
+ }
+ unknown_count++;
break;
default:
die(STATE_UNKNOWN, "Unknown state in get_subcheck_summary");
}
subchecks = subchecks->next;
}
- char *result = NULL;
- asprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown);
+
+ if (result == NULL) {
+ if (ok_count > 0) {
+ asprintf(&result, "ok=%d", ok_count);
+ }
+
+ if (warning_count > 0) {
+ asprintf(&result, "%swarning=%d", (result == NULL ? "" : ", "), warning_count);
+ }
+
+ if (critical_count > 0) {
+ asprintf(&result, "%scritical=%d", (result == NULL ? "" : ", "), critical_count);
+ }
+
+ if (unknown_count > 0) {
+ asprintf(&result, "%sunknown=%d", (result == NULL ? "" : ", "), unknown_count);
+ }
+ }
+
return result;
}
@@ -658,3 +733,46 @@ mp_state_enum mp_eval_unknown(mp_check overall) {
(void)overall;
return STATE_UNKNOWN;
}
+
+static int mp_compare_state(mp_state_enum first, mp_state_enum second) {
+ switch (first) {
+ case STATE_OK:
+ switch (second) {
+ case STATE_OK:
+ return 0;
+ case STATE_WARNING:
+ case STATE_UNKNOWN:
+ case STATE_CRITICAL:
+ return 1;
+ }
+ case STATE_WARNING:
+ switch (second) {
+ case STATE_OK:
+ return -1;
+ case STATE_WARNING:
+ return 0;
+ case STATE_UNKNOWN:
+ case STATE_CRITICAL:
+ return 1;
+ }
+ case STATE_UNKNOWN:
+ switch (second) {
+ case STATE_OK:
+ case STATE_WARNING:
+ return -1;
+ case STATE_UNKNOWN:
+ return 0;
+ case STATE_CRITICAL:
+ return 1;
+ }
+ case STATE_CRITICAL:
+ switch (second) {
+ case STATE_OK:
+ case STATE_WARNING:
+ case STATE_UNKNOWN:
+ return -1;
+ case STATE_CRITICAL:
+ return 0;
+ }
+ }
+}
diff --git a/lib/output.h b/lib/output.h
index f5011268..6ca63cfe 100644
--- a/lib/output.h
+++ b/lib/output.h
@@ -87,7 +87,7 @@ int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck);
void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], mp_perfdata);
-void mp_add_summary(mp_check check[static 1], char *summary);
+void mp_set_summary(mp_check check[static 1], char *summary);
mp_state_enum mp_compute_check_state(mp_check);
mp_state_enum mp_compute_subcheck_state(mp_subcheck);
More information about the Commits
mailing list