Error summary (#2259)
Some checks are pending
Tests Debian:Testing and Fedora:Rawhide / Running unit and integrationt tests (push) Waiting to run
Tests Debian:Testing and Fedora:Rawhide / Running rpm build test on fedora:rawhide (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
Spellcheck / codespell (push) Waiting to run
Tests / Running unit and integrationt tests (push) Waiting to run
Tests / Running rpm build test on almalinux:9 (push) Waiting to run
Tests / Running rpm build test on fedora:latest (push) Waiting to run
Tests / Running rpm build test on rockylinux:8 (push) Waiting to run

* 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>
This commit is contained in:
Lorenz Kästle 2026-05-30 12:30:39 +02:00 committed by GitHub
parent e1cde41866
commit 44e1913da4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 130 additions and 12 deletions

View file

@ -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;
}
}
}

View file

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