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);