/**
* collectd - src/utils_threshold.c
- * Copyright (C) 2007,2008 Florian octo Forster
+ * Copyright (C) 2007-2009 Florian octo Forster
+ * Copyright (C) 2008-2009 Sebastian Harl
+ * Copyright (C) 2009 Andrés J. Díaz
+ *
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
*
* Author:
* Florian octo Forster <octo at verplant.org>
+ * Sebastian Harl <sh at tokkee.org>
+ * Andrés J. Díaz <ajdiaz at connectical.com>
**/
#include "collectd.h"
#include "plugin.h"
#include "utils_avltree.h"
#include "utils_cache.h"
+#include "utils_threshold.h"
+#include "utils_subst.h"
#include <assert.h>
#include <pthread.h>
* {{{ */
#define UT_FLAG_INVERT 0x01
#define UT_FLAG_PERSIST 0x02
-
-typedef struct threshold_s
-{
- char host[DATA_MAX_NAME_LEN];
- char plugin[DATA_MAX_NAME_LEN];
- char plugin_instance[DATA_MAX_NAME_LEN];
- char type[DATA_MAX_NAME_LEN];
- char type_instance[DATA_MAX_NAME_LEN];
- char data_source[DATA_MAX_NAME_LEN];
- gauge_t warning_min;
- gauge_t warning_max;
- gauge_t failure_min;
- gauge_t failure_max;
- int flags;
- struct threshold_s *next;
-} threshold_t;
+#define UT_FLAG_PERCENTAGE 0x04
+#define UT_FLAG_INTERESTING 0x08
/* }}} */
/*
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 */
return (0);
} /* int ut_config_type_min */
-static int ut_config_type_invert (threshold_t *th, oconfig_item_t *ci)
+static int ut_config_type_hits (threshold_t *th, oconfig_item_t *ci)
{
if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
{
- WARNING ("threshold values: The `Invert' option needs exactly one "
- "boolean argument.");
+ WARNING ("threshold values: The `%s' option needs exactly one "
+ "number argument.", ci->key);
return (-1);
}
- if (ci->values[0].value.boolean)
- th->flags |= UT_FLAG_INVERT;
- else
- th->flags &= ~UT_FLAG_INVERT;
+ th->hits = ci->values[0].value.number;
return (0);
-} /* int ut_config_type_invert */
+} /* int ut_config_type_hits */
-static int ut_config_type_persist (threshold_t *th, oconfig_item_t *ci)
+static int ut_config_type_hysteresis (threshold_t *th, oconfig_item_t *ci)
{
if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
{
- WARNING ("threshold values: The `Persist' option needs exactly one "
- "boolean argument.");
+ WARNING ("threshold values: The `%s' option needs exactly one "
+ "number argument.", ci->key);
return (-1);
}
- if (ci->values[0].value.boolean)
- th->flags |= UT_FLAG_PERSIST;
- else
- th->flags &= ~UT_FLAG_PERSIST;
+ th->hysteresis = ci->values[0].value.number;
return (0);
-} /* int ut_config_type_persist */
+} /* int ut_config_type_hysteresis */
+
+static int ut_config_type_message (threshold_t *th, oconfig_item_t *ci)
+{
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("threshold values: The `%s' option needs exactly one "
+ "string argument.", ci->key);
+ return (-1);
+ }
+
+ if (ci->values[0].value.string[0] == 0)
+ {
+ WARNING ("threshold values: The `%s' option does not accept empty strings.",
+ ci->key);
+ return (-1);
+ }
+
+ th->message = strdup (ci->values[0].value.string);
+ if (th->message == NULL)
+ {
+ ERROR ("ut_config_type_message: sstrdup failed.");
+ return (-1);
+ }
+
+ return (0);
+} /* int ut_config_type_message */
+
+static int ut_config_type_missingmessage (threshold_t *th, oconfig_item_t *ci)
+{
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("threshold values: The `%s' option needs exactly one "
+ "string argument.", ci->key);
+ return (-1);
+ }
+
+ if (ci->values[0].value.string[0] == 0)
+ {
+ WARNING ("threshold values: The `%s' option does not accept empty strings.",
+ ci->key);
+ return (-1);
+ }
+
+ th->missing_message = strdup (ci->values[0].value.string);
+ if (th->missing_message == NULL)
+ {
+ ERROR ("ut_config_type_missingmessage: sstrdup failed.");
+ return (-1);
+ }
+
+ return (0);
+} /* int ut_config_type_missingmessage */
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;
th.failure_min = NAN;
th.failure_max = NAN;
+ th.hits = 0;
+ th.hysteresis = 0;
+ th.message = NULL;
+ th.flags = UT_FLAG_INTERESTING; /* interesting by default */
for (i = 0; i < ci->children_num; i++)
{
else if ((strcasecmp ("WarningMin", option->key) == 0)
|| (strcasecmp ("FailureMin", option->key) == 0))
status = ut_config_type_min (&th, option);
+ else if (strcasecmp ("Interesting", option->key) == 0)
+ status = cf_util_get_flag (option, &th.flags, UT_FLAG_INTERESTING);
else if (strcasecmp ("Invert", option->key) == 0)
- status = ut_config_type_invert (&th, option);
+ status = cf_util_get_flag (option, &th.flags, UT_FLAG_INVERT);
else if (strcasecmp ("Persist", option->key) == 0)
- status = ut_config_type_persist (&th, option);
+ status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERSIST);
+ else if (strcasecmp ("Percentage", option->key) == 0)
+ status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERCENTAGE);
+ else if (strcasecmp ("Hits", option->key) == 0)
+ status = ut_config_type_hits (&th, option);
+ else if (strcasecmp ("Hysteresis", option->key) == 0)
+ status = ut_config_type_hysteresis (&th, option);
+ else if (strcasecmp ("Message", option->key) == 0)
+ status = ut_config_type_message (&th, option);
+ else if (strcasecmp ("MissingMessage", option->key) == 0)
+ status = ut_config_type_missingmessage (&th, option);
else
{
WARNING ("threshold values: Option `%s' not allowed inside a `Type' "
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 */
}
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++)
{
}
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++)
{
th.warning_max = NAN;
th.failure_min = NAN;
th.failure_max = NAN;
+
+ th.hits = 0;
+ th.hysteresis = 0;
+ th.flags = UT_FLAG_INTERESTING; /* interesting by default */
for (i = 0; i < ci->children_num; i++)
{
*/
/* }}} */
-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);
} /* threshold_t *threshold_search */
+/* char *ut_build_message
+ *
+ * Return a custom formated message for dataset, values and previously created
+ * notification (which must include time and other fields), if th is present,
+ * templates for threshold will be interpreted, if th is NULL these will be
+ * skipped.
+ */
+int ut_build_message(char *out, size_t bufsize, const char *fmt,
+ const data_set_t *ds, int ds_index, const value_list_t *vl, const gauge_t *values,
+ const notification_t *n, const threshold_t *th)
+{
+ /* TODO: We could provide here a way to use meta information on thresholds
+ * directly in the future. */
+ char msg[NOTIF_MAX_MSG_LEN];
+ int rates_failed;
+
+ int i;
+
+ sstrncpy (msg, fmt, sizeof (msg));
+
+#define REPLACE_FIELD(t,v) do { \
+ char temp[NOTIF_MAX_MSG_LEN]; \
+ if (subst_string (temp, sizeof (temp), msg, (t), (v)) != NULL) \
+ sstrncpy (msg, temp, sizeof (msg)); \
+} while (0)
+
+#define REPLACE_FIELD_F(t,f) do { \
+ char f_str[64]; \
+ ssnprintf (f_str, sizeof (f_str), "%g", (f)); \
+ REPLACE_FIELD ((t), f_str); \
+} while (0)
+
+#define REPLACE_FIELD_I(t,i) do { \
+ char i_str[64]; \
+ ssnprintf (i_str, sizeof (i_str), "%i", (i)); \
+ REPLACE_FIELD ((t), i_str); \
+} while (0)
+
+ REPLACE_FIELD ("%{host}", n->host);
+ REPLACE_FIELD ("%{plugin}", n->plugin);
+ REPLACE_FIELD ("%{plugin_instance}", n->plugin_instance);
+ REPLACE_FIELD ("%{type}", n->type);
+ REPLACE_FIELD ("%{type_instance}", n->type_instance);
+
+ /* ds_index is set to -1 if the value is missing (there is no data source /
+ * value we could reasonably use. */
+ if (ds_index >= 0)
+ {
+ REPLACE_FIELD ("%{data_source}", ds->ds[ds_index].name);
+
+ /* This is the offending value, its equivalent to %{ds:value}, if
+ * value is the data_source name. */
+ REPLACE_FIELD_F ("%{value}", (double) values[ds_index]);
+ }
+
+ /* Now replace all %{ds:<template>} like target_notification does */
+ rates_failed = 0;
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ char template[DATA_MAX_NAME_LEN];
+ char value_str[DATA_MAX_NAME_LEN];
+
+ ssnprintf (template, sizeof (template), "%%{ds:%s}", ds->ds[i].name);
+
+ /* If this is a gauge value, use the current value. */
+ if (ds->ds[i].type == DS_TYPE_GAUGE)
+ ssnprintf (value_str, sizeof (value_str),
+ "%g", (double) vl->values[i].gauge);
+ /* If it's a counter, try to use the current rate. This may fail, if the
+ * value has been renamed. */
+ else if (values != NULL)
+ ssnprintf (value_str, sizeof (value_str),
+ "%g", (double) values[i]);
+ /* Since we don't know any better, use the string `unknown'. */
+ else
+ sstrncpy (value_str, "unknown", sizeof (value_str));
+
+ REPLACE_FIELD (template, value_str);
+ }
+
+ if (th != NULL)
+ {
+ REPLACE_FIELD_F ("%{warning_min}", th->warning_min);
+ REPLACE_FIELD_F ("%{warning_max}", th->warning_max);
+ REPLACE_FIELD_F ("%{failure_min}", th->failure_min);
+ REPLACE_FIELD_F ("%{failure_max}", th->failure_max);
+ REPLACE_FIELD_F ("%{hysteresis}", th->hysteresis);
+ REPLACE_FIELD_I ("%{hits}", th->hits);
+ }
+
+ sstrncpy (out, msg, bufsize);
+ return (0);
+} /* int ut_build_message */
+
/*
* int ut_report_state
*
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
n.time = vl->time;
- status = snprintf (buf, bufsize, "Host %s, plugin %s",
- vl->host, vl->plugin);
- buf += status;
- bufsize -= status;
-
- if (vl->plugin_instance[0] != '\0')
+ /* Format custom message if present */
+ if (th->message != NULL)
{
- status = snprintf (buf, bufsize, " (instance %s)",
- vl->plugin_instance);
+ status = ut_build_message (buf, bufsize, th->message,
+ ds, ds_index, vl, values,
+ &n, th);
buf += status;
bufsize -= status;
}
-
- status = snprintf (buf, bufsize, " type %s", ds->type);
- buf += status;
- bufsize -= status;
-
- if (vl->type_instance[0] != '\0')
+ else /* No custom message. Using default message for threshold */
{
- status = snprintf (buf, bufsize, " (instance %s)",
- vl->type_instance);
+ status = ssnprintf (buf, bufsize, "Host %s, plugin %s",
+ vl->host, vl->plugin);
buf += status;
bufsize -= status;
- }
- /* Send an okay notification */
- if (state == STATE_OKAY)
- {
- status = snprintf (buf, bufsize, ": All data sources are within range again.");
+ 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;
- }
- 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 (vl->type_instance[0] != '\0')
+ {
+ status = ssnprintf (buf, bufsize, " (instance %s)",
+ vl->type_instance);
+ buf += status;
+ bufsize -= status;
+ }
- if (th->flags & UT_FLAG_INVERT)
+ /* Build okay notification message */
+ if (state == STATE_OKAY)
+ {
+ status = ssnprintf (buf, bufsize, ": All data sources are within range again.");
+ buf += status;
+ bufsize -= status;
+ }
+ else /* build non-okay notification message */
{
- if (!isnan (min) && !isnan (max))
+ 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)
{
- 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);
+ 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
+ else /* is not inverted */
{
- status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
- "%f. That is %s the %s threshold of %f.",
- ds->ds[ds_index].name, values[ds_index],
- isnan (min) ? "below" : "above",
- (state == STATE_ERROR) ? "failure" : "warning",
- isnan (min) ? max : min);
+ 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;
}
- else /* is not inverted */
- {
- status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
- "%f. That is %s the %s threshold of %f.",
- 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);
- }
- buf += status;
- bufsize -= status;
}
+ /* adds meta to notification */
+ 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);
+
plugin_dispatch_notification (&n);
+ plugin_notification_meta_free (n.meta);
return (0);
} /* }}} int ut_report_state */
* 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)
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 */
- 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)
{
is_failure--;
}
- if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
- || (!isnan (th->failure_max) && (th->failure_max < values[ds_index])))
- 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 ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
- || (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
- is_warning++;
if (is_warning != 0)
return (STATE_WARNING);
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;
/* 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);
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;
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_INTERESTING) == 0)
+ return (0);
+
if ((th->flags & UT_FLAG_PERSIST) == 0)
return (1);
return (2);
-} /* int ut_check_interesting */
+} /* }}} int ut_check_interesting */
+
+int ut_search_threshold (const value_list_t *vl, /* {{{ */
+ threshold_t *ret_threshold)
+{
+ threshold_t *t;
+
+ if (vl == NULL)
+ return (EINVAL);
+
+ t = threshold_search (vl);
+ if (t == NULL)
+ return (ENOENT);
+
+ memcpy (ret_threshold, t, sizeof (*ret_threshold));
+ ret_threshold->next = NULL;
+
+ return (0);
+} /* }}} int ut_search_threshold */
-/* 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 : */