-} /* threshold_t *threshold_search */
-
-/*
- * int ut_report_state
- *
- * Checks if the `state' differs from the old state and creates a notification
- * if appropriate.
- * Does not fail.
- */
-static int ut_report_state (const data_set_t *ds,
- const value_list_t *vl,
- const threshold_t *th,
- const gauge_t *values,
- int ds_index,
- int state)
-{ /* {{{ */
- int state_old;
- notification_t n;
-
- char *buf;
- size_t bufsize;
-
- int status;
-
- /* Check if hits matched */
- if ( (th->hits != 0) )
- {
- int hits = uc_get_hits(ds,vl);
- /* The STATE_OKAY always reset hits, or if hits reaise the limit */
- if ( (state == STATE_OKAY) || (hits > th->hits) )
- {
- DEBUG("ut_report_state: reset uc_get_hits = 0");
- uc_set_hits(ds,vl,0); /* reset hit counter and notify */
- } else {
- DEBUG("ut_report_state: th->hits = %d, uc_get_hits = %d",th->hits,uc_get_hits(ds,vl));
- (void) uc_inc_hits(ds,vl,1); /* increase hit counter */
- return (0);
- }
- } /* end check hits */
-
- state_old = uc_get_state (ds, vl);
-
- /* If the state didn't change, only report if `persistent' is specified and
- * the state is not `okay'. */
- if (state == state_old)
- {
- if ((th->flags & UT_FLAG_PERSIST) == 0)
- return (0);
- else if (state == STATE_OKAY)
- return (0);
- }
-
- if (state != state_old)
- uc_set_state (ds, vl, state);
-
- NOTIFICATION_INIT_VL (&n, vl, ds);
-
- buf = n.message;
- bufsize = sizeof (n.message);
-
- if (state == STATE_OKAY)
- n.severity = NOTIF_OKAY;
- else if (state == STATE_WARNING)
- n.severity = NOTIF_WARNING;
- else
- n.severity = NOTIF_FAILURE;
-
- n.time = vl->time;
-
- status = ssnprintf (buf, bufsize, "Host %s, plugin %s",
- vl->host, vl->plugin);
- buf += status;
- bufsize -= status;
-
- if (vl->plugin_instance[0] != '\0')
- {
- status = ssnprintf (buf, bufsize, " (instance %s)",
- vl->plugin_instance);
- buf += status;
- bufsize -= status;
- }
-
- status = ssnprintf (buf, bufsize, " type %s", vl->type);
- buf += status;
- bufsize -= status;
-
- if (vl->type_instance[0] != '\0')
- {
- 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 = ssnprintf (buf, bufsize, ": All data sources are within range again.");
- buf += status;
- bufsize -= status;
- }
- else
- {
- double min;
- double max;
-
- min = (state == STATE_ERROR) ? th->failure_min : th->warning_min;
- max = (state == STATE_ERROR) ? th->failure_max : th->warning_max;
-
- if (th->flags & UT_FLAG_INVERT)
- {
- if (!isnan (min) && !isnan (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 = 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,
- ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
- }
- }
- else /* is not inverted */
- {
- 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,
- ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
- }
- buf += status;
- bufsize -= status;
- }
-
- plugin_dispatch_notification (&n);
-
- plugin_notification_meta_free (n.meta);
- return (0);
-} /* }}} int ut_report_state */
-
-/*
- * int ut_check_one_data_source
- *
- * Checks one data source against the given threshold configuration. If the
- * `DataSource' option is set in the threshold, and the name does NOT match,
- * `okay' is returned. If the threshold does match, its failure and warning
- * min and max values are checked and `failure' or `warning' is returned if
- * appropriate.
- * Does not fail.
- */
-static int ut_check_one_data_source (const data_set_t *ds,
- const value_list_t __attribute__((unused)) *vl,
- const threshold_t *th,
- const gauge_t *values,
- int ds_index)
-{ /* {{{ */
- const char *ds_name;
- int is_warning = 0;
- int is_failure = 0;
- int prev_state = STATE_OKAY;
-
- /* check if this threshold applies to this data source */
- 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)
- {
- is_warning--;
- is_failure--;
- }
-
- /* XXX: This is an experimental code, not optimized, not fast, not reliable,
- * and probably, do not work as you expect. Enjoy! :D */
- if ( (th->hysteresis > 0) && ((prev_state = uc_get_state(ds,vl)) != STATE_OKAY) )
- {
- switch(prev_state)
- {
- case STATE_ERROR:
- if ( (!isnan (th->failure_min) && ((th->failure_min + th->hysteresis) < values[ds_index])) ||
- (!isnan (th->failure_max) && ((th->failure_max - th->hysteresis) > values[ds_index])) )
- return (STATE_OKAY);
- else
- is_failure++;
- case STATE_WARNING:
- if ( (!isnan (th->warning_min) && ((th->warning_min + th->hysteresis) < values[ds_index])) ||
- (!isnan (th->warning_max) && ((th->warning_max - th->hysteresis) > values[ds_index])) )
- return (STATE_OKAY);
- else
- is_warning++;
- }
- }
- else { /* no hysteresis */
- if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
- || (!isnan (th->failure_max) && (th->failure_max < values[ds_index])))
- is_failure++;
-
- if ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
- || (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
- is_warning++;
- }
-
- if (is_failure != 0)
- return (STATE_ERROR);
-
- if (is_warning != 0)
- return (STATE_WARNING);
-
- return (STATE_OKAY);
-} /* }}} int ut_check_one_data_source */
-
-/*
- * int ut_check_one_threshold
- *
- * Checks all data sources of a value list against the given threshold, using
- * the ut_check_one_data_source function above. Returns the worst status,
- * which is `okay' if nothing has failed.
- * Returns less than zero if the data set doesn't have any data sources.
- */
-static int ut_check_one_threshold (const data_set_t *ds,
- const value_list_t *vl,
- const threshold_t *th,
- const gauge_t *values,
- int *ret_ds_index)
-{ /* {{{ */
- 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_copy, i);
- if (ret < status)
- {
- ret = status;
- ds_index = i;
- }
- } /* for (ds->ds_num) */
-
- if (ret_ds_index != NULL)
- *ret_ds_index = ds_index;
-
- return (ret);
-} /* }}} int ut_check_one_threshold */
-
-/*
- * int ut_check_threshold (PUBLIC)
- *
- * Gets a list of matching thresholds and searches for the worst status by one
- * of the thresholds. Then reports that status using the ut_report_state
- * function above.
- * Returns zero on success and if no threshold has been configured. Returns
- * less than zero on failure.
- */
-int ut_check_threshold (const data_set_t *ds, const value_list_t *vl)
-{ /* {{{ */
- threshold_t *th;
- gauge_t *values;
- int status;
-
- int worst_state = -1;
- threshold_t *worst_th = NULL;
- int worst_ds_index = -1;
-
- if (threshold_tree == NULL)
- return (0);
-
- /* Is this lock really necessary? So far, thresholds are only inserted at
- * startup. -octo */
- pthread_mutex_lock (&threshold_lock);
- th = threshold_search (vl);
- pthread_mutex_unlock (&threshold_lock);
- if (th == NULL)
- return (0);
-
- DEBUG ("ut_check_threshold: Found matching threshold(s)");
-
- values = uc_get_rate (ds, vl);
- if (values == NULL)
- return (0);
-
- while (th != NULL)
- {
- int ds_index = -1;
-
- status = ut_check_one_threshold (ds, vl, th, values, &ds_index);
- if (status < 0)
- {
- ERROR ("ut_check_threshold: ut_check_one_threshold failed.");
- sfree (values);
- return (-1);
- }
-
- if (worst_state < status)
- {
- worst_state = status;
- worst_th = th;
- worst_ds_index = ds_index;
- }
-
- th = th->next;
- } /* while (th) */
-
- status = ut_report_state (ds, vl, worst_th, values,
- worst_ds_index, worst_state);
- if (status != 0)
- {
- ERROR ("ut_check_threshold: ut_report_state failed.");
- sfree (values);
- return (-1);
- }
-
- sfree (values);
-
- 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;
- char *plugin_instance = NULL;
- char *type = NULL;
- char *type_instance = NULL;
- int status;
- data_set_t ds;
- value_list_t vl;
- threshold_t *th;
-
- /* If there is no tree nothing is interesting. */
- if (threshold_tree == NULL)
- return (0);
-
- name_copy = strdup (name);
- if (name_copy == NULL)
- {
- ERROR ("ut_check_interesting: strdup failed.");
- return (-1);
- }
-
- status = parse_identifier (name_copy, &host,
- &plugin, &plugin_instance, &type, &type_instance);
- 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));
-
- sstrncpy (vl.host, host, sizeof (vl.host));
- sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
- if (plugin_instance != NULL)
- 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)
- sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
-
- sfree (name_copy);
- host = plugin = plugin_instance = type = type_instance = NULL;
-
- th = threshold_search (&vl);
- if (th == NULL)
- return (0);
- if ((th->flags & UT_FLAG_PERSIST) == 0)
- return (1);
- return (2);
-} /* }}} int ut_check_interesting */