X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Futils_threshold.c;h=fa8c8f9fde2522c2114a41206311254bcd01c529;hb=bacc5b925ea8c63eb57dc4b55f4b4abbe1b1d07c;hp=4da8943cdbf3c4a403dfb2e2b7b5ffb5f5405813;hpb=e3e67d21f20d8ace9d1d1dd60dc3bc9435b316b8;p=collectd.git diff --git a/src/utils_threshold.c b/src/utils_threshold.c index 4da8943c..fa8c8f9f 100644 --- a/src/utils_threshold.c +++ b/src/utils_threshold.c @@ -33,6 +33,7 @@ * {{{ */ #define UT_FLAG_INVERT 0x01 #define UT_FLAG_PERSIST 0x02 +#define UT_FLAG_PERCENTAGE 0x04 typedef struct threshold_s { @@ -184,9 +185,8 @@ static int ut_config_type_instance (threshold_t *th, oconfig_item_t *ci) return (-1); } - strncpy (th->type_instance, ci->values[0].value.string, + sstrncpy (th->type_instance, ci->values[0].value.string, sizeof (th->type_instance)); - th->type_instance[sizeof (th->type_instance) - 1] = '\0'; return (0); } /* int ut_config_type_instance */ @@ -263,6 +263,24 @@ static int ut_config_type_persist (threshold_t *th, oconfig_item_t *ci) return (0); } /* int ut_config_type_persist */ +static int ut_config_type_percentage(threshold_t *th, oconfig_item_t *ci) +{ + if ((ci->values_num != 1) + || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) + { + WARNING ("threshold values: The `Percentage' option needs exactly one " + "boolean argument."); + return (-1); + } + + if (ci->values[0].value.boolean) + th->flags |= UT_FLAG_PERCENTAGE; + else + th->flags &= ~UT_FLAG_PERCENTAGE; + + return (0); +} /* int ut_config_type_percentage */ + static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) { int i; @@ -284,8 +302,7 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) } memcpy (&th, th_orig, sizeof (th)); - strncpy (th.type, ci->values[0].value.string, sizeof (th.type)); - th.type[sizeof (th.type) - 1] = '\0'; + sstrncpy (th.type, ci->values[0].value.string, sizeof (th.type)); th.warning_min = NAN; th.warning_max = NAN; @@ -311,6 +328,8 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) status = ut_config_type_invert (&th, option); else if (strcasecmp ("Persist", option->key) == 0) status = ut_config_type_persist (&th, option); + else if (strcasecmp ("Percentage", option->key) == 0) + status = ut_config_type_percentage (&th, option); else { WARNING ("threshold values: Option `%s' not allowed inside a `Type' " @@ -340,9 +359,8 @@ static int ut_config_plugin_instance (threshold_t *th, oconfig_item_t *ci) return (-1); } - strncpy (th->plugin_instance, ci->values[0].value.string, + sstrncpy (th->plugin_instance, ci->values[0].value.string, sizeof (th->plugin_instance)); - th->plugin_instance[sizeof (th->plugin_instance) - 1] = '\0'; return (0); } /* int ut_config_plugin_instance */ @@ -369,8 +387,7 @@ static int ut_config_plugin (const threshold_t *th_orig, oconfig_item_t *ci) } memcpy (&th, th_orig, sizeof (th)); - strncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin)); - th.plugin[sizeof (th.plugin) - 1] = '\0'; + sstrncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin)); for (i = 0; i < ci->children_num; i++) { @@ -417,8 +434,7 @@ static int ut_config_host (const threshold_t *th_orig, oconfig_item_t *ci) } memcpy (&th, th_orig, sizeof (th)); - strncpy (th.host, ci->values[0].value.string, sizeof (th.host)); - th.host[sizeof (th.host) - 1] = '\0'; + sstrncpy (th.host, ci->values[0].value.string, sizeof (th.host)); for (i = 0; i < ci->children_num; i++) { @@ -472,7 +488,7 @@ int ut_config (const oconfig_item_t *ci) th.warning_max = NAN; th.failure_min = NAN; th.failure_max = NAN; - + for (i = 0; i < ci->children_num; i++) { oconfig_item_t *option = ci->children + i; @@ -501,46 +517,45 @@ int ut_config (const oconfig_item_t *ci) */ /* }}} */ -static threshold_t *threshold_search (const data_set_t *ds, - const value_list_t *vl) +static threshold_t *threshold_search (const value_list_t *vl) { threshold_t *th; if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance, - ds->type, vl->type_instance)) != NULL) + vl->type, vl->type_instance)) != NULL) return (th); else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance, - ds->type, NULL)) != NULL) + vl->type, NULL)) != NULL) return (th); else if ((th = threshold_get (vl->host, vl->plugin, NULL, - ds->type, vl->type_instance)) != NULL) + vl->type, vl->type_instance)) != NULL) return (th); else if ((th = threshold_get (vl->host, vl->plugin, NULL, - ds->type, NULL)) != NULL) + vl->type, NULL)) != NULL) return (th); else if ((th = threshold_get (vl->host, "", NULL, - ds->type, vl->type_instance)) != NULL) + vl->type, vl->type_instance)) != NULL) return (th); else if ((th = threshold_get (vl->host, "", NULL, - ds->type, NULL)) != NULL) + vl->type, NULL)) != NULL) return (th); else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance, - ds->type, vl->type_instance)) != NULL) + vl->type, vl->type_instance)) != NULL) return (th); else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance, - ds->type, NULL)) != NULL) + vl->type, NULL)) != NULL) return (th); else if ((th = threshold_get ("", vl->plugin, NULL, - ds->type, vl->type_instance)) != NULL) + vl->type, vl->type_instance)) != NULL) return (th); else if ((th = threshold_get ("", vl->plugin, NULL, - ds->type, NULL)) != NULL) + vl->type, NULL)) != NULL) return (th); else if ((th = threshold_get ("", "", NULL, - ds->type, vl->type_instance)) != NULL) + vl->type, vl->type_instance)) != NULL) return (th); else if ((th = threshold_get ("", "", NULL, - ds->type, NULL)) != NULL) + vl->type, NULL)) != NULL) return (th); return (NULL); @@ -597,35 +612,43 @@ static int ut_report_state (const data_set_t *ds, n.time = vl->time; - status = snprintf (buf, bufsize, "Host %s, plugin %s", + status = ssnprintf (buf, bufsize, "Host %s, plugin %s", vl->host, vl->plugin); buf += status; bufsize -= status; if (vl->plugin_instance[0] != '\0') { - status = snprintf (buf, bufsize, " (instance %s)", + status = ssnprintf (buf, bufsize, " (instance %s)", vl->plugin_instance); buf += status; bufsize -= status; } - status = snprintf (buf, bufsize, " type %s", ds->type); + status = ssnprintf (buf, bufsize, " type %s", vl->type); buf += status; bufsize -= status; if (vl->type_instance[0] != '\0') { - status = snprintf (buf, bufsize, " (instance %s)", + status = ssnprintf (buf, bufsize, " (instance %s)", vl->type_instance); buf += status; bufsize -= status; } + plugin_notification_meta_add_string (&n, "DataSource", + ds->ds[ds_index].name); + plugin_notification_meta_add_double (&n, "CurrentValue", values[ds_index]); + plugin_notification_meta_add_double (&n, "WarningMin", th->warning_min); + plugin_notification_meta_add_double (&n, "WarningMax", th->warning_max); + plugin_notification_meta_add_double (&n, "FailureMin", th->failure_min); + plugin_notification_meta_add_double (&n, "FailureMax", th->failure_max); + /* Send an okay notification */ if (state == STATE_OKAY) { - status = snprintf (buf, bufsize, ": All data sources are within range again."); + status = ssnprintf (buf, bufsize, ": All data sources are within range again."); buf += status; bufsize -= status; } @@ -641,30 +664,33 @@ static int ut_report_state (const data_set_t *ds, { if (!isnan (min) && !isnan (max)) { - status = snprintf (buf, bufsize, ": Data source \"%s\" is currently " - "%f. That is within the %s region of %f and %f.", - ds->ds[ds_index].name, values[ds_index], - (state == STATE_ERROR) ? "failure" : "warning", - min, max); + status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " + "%f. That is within the %s region of %f%s and %f%s.", + ds->ds[ds_index].name, values[ds_index], + (state == STATE_ERROR) ? "failure" : "warning", + min, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "", + max, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); } else { - status = snprintf (buf, bufsize, ": Data source \"%s\" is currently " - "%f. That is %s the %s threshold of %f.", + status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " + "%f. That is %s the %s threshold of %f%s.", ds->ds[ds_index].name, values[ds_index], isnan (min) ? "below" : "above", (state == STATE_ERROR) ? "failure" : "warning", - isnan (min) ? max : min); + isnan (min) ? max : min, + ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); } } else /* is not inverted */ { - status = snprintf (buf, bufsize, ": Data source \"%s\" is currently " - "%f. That is %s the %s threshold of %f.", + status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " + "%f. That is %s the %s threshold of %f%s.", ds->ds[ds_index].name, values[ds_index], (values[ds_index] < min) ? "below" : "above", (state == STATE_ERROR) ? "failure" : "warning", - (values[ds_index] < min) ? min : max); + (values[ds_index] < min) ? min : max, + ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); } buf += status; bufsize -= status; @@ -672,6 +698,7 @@ static int ut_report_state (const data_set_t *ds, plugin_dispatch_notification (&n); + plugin_notification_meta_free (n.meta); return (0); } /* }}} int ut_report_state */ @@ -686,7 +713,7 @@ static int ut_report_state (const data_set_t *ds, * Does not fail. */ static int ut_check_one_data_source (const data_set_t *ds, - const value_list_t *vl, + const value_list_t __attribute__((unused)) *vl, const threshold_t *th, const gauge_t *values, int ds_index) @@ -696,10 +723,13 @@ static int ut_check_one_data_source (const data_set_t *ds, int is_failure = 0; /* check if this threshold applies to this data source */ - ds_name = ds->ds[ds_index].name; - if ((th->data_source[0] != 0) - && (strcmp (ds_name, th->data_source) != 0)) - return (STATE_OKAY); + if (ds != NULL) + { + ds_name = ds->ds[ds_index].name; + if ((th->data_source[0] != 0) + && (strcmp (ds_name, th->data_source) != 0)) + return (STATE_OKAY); + } if ((th->flags & UT_FLAG_INVERT) != 0) { @@ -739,12 +769,49 @@ static int ut_check_one_threshold (const data_set_t *ds, int ret = -1; int ds_index = -1; int i; + gauge_t values_copy[ds->ds_num]; + + memcpy (values_copy, values, sizeof (values_copy)); + + if ((th->flags & UT_FLAG_PERCENTAGE) != 0) + { + int num = 0; + gauge_t sum=0.0; + + if (ds->ds_num == 1) + { + WARNING ("ut_check_one_threshold: The %s type has only one data " + "source, but you have configured to check this as a percentage. " + "That doesn't make much sense, because the percentage will always " + "be 100%%!", ds->type); + } + + /* Prepare `sum' and `num'. */ + for (i = 0; i < ds->ds_num; i++) + if (!isnan (values[i])) + { + num++; + sum += values[i]; + } + + if ((num == 0) /* All data sources are undefined. */ + || (sum == 0.0)) /* Sum is zero, cannot calculate percentage. */ + { + for (i = 0; i < ds->ds_num; i++) + values_copy[i] = NAN; + } + else /* We can actually calculate the percentage. */ + { + for (i = 0; i < ds->ds_num; i++) + values_copy[i] = 100.0 * values[i] / sum; + } + } /* if (UT_FLAG_PERCENTAGE) */ for (i = 0; i < ds->ds_num; i++) { int status; - status = ut_check_one_data_source (ds, vl, th, values, i); + status = ut_check_one_data_source (ds, vl, th, values_copy, i); if (ret < status) { ret = status; @@ -783,7 +850,7 @@ int ut_check_threshold (const data_set_t *ds, const value_list_t *vl) /* Is this lock really necessary? So far, thresholds are only inserted at * startup. -octo */ pthread_mutex_lock (&threshold_lock); - th = threshold_search (ds, vl); + th = threshold_search (vl); pthread_mutex_unlock (&threshold_lock); if (th == NULL) return (0); @@ -830,8 +897,18 @@ int ut_check_threshold (const data_set_t *ds, const value_list_t *vl) return (0); } /* }}} int ut_check_threshold */ +/* + * int ut_check_interesting (PUBLIC) + * + * Given an identification returns + * 0: No threshold is defined. + * 1: A threshold has been found. The flag `persist' is off. + * 2: A threshold has been found. The flag `persist' is on. + * (That is, it is expected that many notifications are sent until the + * problem disappears.) + */ int ut_check_interesting (const char *name) -{ +{ /* {{{ */ char *name_copy = NULL; char *host = NULL; char *plugin = NULL; @@ -859,38 +936,31 @@ int ut_check_interesting (const char *name) if (status != 0) { ERROR ("ut_check_interesting: parse_identifier failed."); + sfree (name_copy); return (-1); } memset (&ds, '\0', sizeof (ds)); memset (&vl, '\0', sizeof (vl)); - strncpy (vl.host, host, sizeof (vl.host)); - vl.host[sizeof (vl.host) - 1] = '\0'; - strncpy (vl.plugin, plugin, sizeof (vl.plugin)); - vl.plugin[sizeof (vl.plugin) - 1] = '\0'; + sstrncpy (vl.host, host, sizeof (vl.host)); + sstrncpy (vl.plugin, plugin, sizeof (vl.plugin)); if (plugin_instance != NULL) - { - strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance)); - vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0'; - } - strncpy (ds.type, type, sizeof (ds.type)); - ds.type[sizeof (ds.type) - 1] = '\0'; + sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance)); + sstrncpy (ds.type, type, sizeof (ds.type)); + sstrncpy (vl.type, type, sizeof (vl.type)); if (type_instance != NULL) - { - strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); - vl.type_instance[sizeof (vl.type_instance) - 1] = '\0'; - } + sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); sfree (name_copy); host = plugin = plugin_instance = type = type_instance = NULL; - th = threshold_search (&ds, &vl); + th = threshold_search (&vl); if (th == NULL) return (0); if ((th->flags & UT_FLAG_PERSIST) == 0) return (1); return (2); -} /* int ut_check_interesting */ +} /* }}} int ut_check_interesting */ -/* vim: set sw=2 ts=8 sts=2 tw=78 fdm=marker : */ +/* vim: set sw=2 ts=8 sts=2 tw=78 et fdm=marker : */