X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fthreshold.c;h=45ee3b4d02c61b722419577ee607580dcdb4cb26;hb=1fc00932fd49fa535551cc4bba09c4e4be059ab4;hp=887dbca34e718c84482e58fb18f88a33c60f5777;hpb=82e27678f8972d2625b466e7e7ba9daaa6395c98;p=collectd.git diff --git a/src/threshold.c b/src/threshold.c index 887dbca3..45ee3b4d 100644 --- a/src/threshold.c +++ b/src/threshold.c @@ -28,75 +28,17 @@ #include "plugin.h" #include "utils_avltree.h" #include "utils_cache.h" +#include "utils_threshold.h" #include #include /* - * Private data structures - * {{{ */ -#define UT_FLAG_INVERT 0x01 -#define UT_FLAG_PERSIST 0x02 -#define UT_FLAG_PERCENTAGE 0x04 -#define UT_FLAG_INTERESTING 0x08 -#define UT_FLAG_PERSIST_OK 0x10 -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; - gauge_t hysteresis; - unsigned int flags; - int hits; - struct threshold_s *next; -} threshold_t; -/* }}} */ - -/* - * Private (static) variables - * {{{ */ -static c_avl_tree_t *threshold_tree = NULL; -static pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER; -/* }}} */ - -/* * Threshold management * ==================== * The following functions add, delete, search, etc. configured thresholds to * the underlying AVL trees. */ -/* - * threshold_t *threshold_get - * - * Retrieve one specific threshold configuration. For looking up a threshold - * matching a value_list_t, see "threshold_search" below. Returns NULL if the - * specified threshold doesn't exist. - */ -static threshold_t *threshold_get (const char *hostname, - const char *plugin, const char *plugin_instance, - const char *type, const char *type_instance) -{ /* {{{ */ - char name[6 * DATA_MAX_NAME_LEN]; - threshold_t *th = NULL; - - format_name (name, sizeof (name), - (hostname == NULL) ? "" : hostname, - (plugin == NULL) ? "" : plugin, plugin_instance, - (type == NULL) ? "" : type, type_instance); - name[sizeof (name) - 1] = '\0'; - - if (c_avl_get (threshold_tree, name, (void *) &th) == 0) - return (th); - else - return (NULL); -} /* }}} threshold_t *threshold_get */ /* * int ut_threshold_add @@ -171,58 +113,6 @@ static int ut_threshold_add (const threshold_t *th) return (status); } /* }}} int ut_threshold_add */ -/* - * threshold_t *threshold_search - * - * Searches for a threshold configuration using all the possible variations of - * "Host", "Plugin" and "Type" blocks. Returns NULL if no threshold could be - * found. - * XXX: This is likely the least efficient function in collectd. - */ -static threshold_t *threshold_search (const value_list_t *vl) -{ /* {{{ */ - threshold_t *th; - - if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance, - vl->type, vl->type_instance)) != NULL) - return (th); - else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance, - vl->type, NULL)) != NULL) - return (th); - else if ((th = threshold_get (vl->host, vl->plugin, NULL, - vl->type, vl->type_instance)) != NULL) - return (th); - else if ((th = threshold_get (vl->host, vl->plugin, NULL, - vl->type, NULL)) != NULL) - return (th); - else if ((th = threshold_get (vl->host, "", NULL, - vl->type, vl->type_instance)) != NULL) - return (th); - else if ((th = threshold_get (vl->host, "", NULL, - vl->type, NULL)) != NULL) - return (th); - else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance, - vl->type, vl->type_instance)) != NULL) - return (th); - else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance, - vl->type, NULL)) != NULL) - return (th); - else if ((th = threshold_get ("", vl->plugin, NULL, - vl->type, vl->type_instance)) != NULL) - return (th); - else if ((th = threshold_get ("", vl->plugin, NULL, - vl->type, NULL)) != NULL) - return (th); - else if ((th = threshold_get ("", "", NULL, - vl->type, vl->type_instance)) != NULL) - return (th); - else if ((th = threshold_get ("", "", NULL, - vl->type, NULL)) != NULL) - return (th); - - return (NULL); -} /* }}} threshold_t *threshold_search */ - /* * Configuration * ============= @@ -361,7 +251,6 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) for (i = 0; i < ci->children_num; i++) { oconfig_item_t *option = ci->children + i; - status = 0; if (strcasecmp ("Instance", option->key) == 0) status = ut_config_type_instance (&th, option); @@ -449,7 +338,6 @@ static int ut_config_plugin (const threshold_t *th_orig, oconfig_item_t *ci) for (i = 0; i < ci->children_num; i++) { oconfig_item_t *option = ci->children + i; - status = 0; if (strcasecmp ("Type", option->key) == 0) status = ut_config_type (&th, option); @@ -496,7 +384,6 @@ static int ut_config_host (const threshold_t *th_orig, oconfig_item_t *ci) for (i = 0; i < ci->children_num; i++) { oconfig_item_t *option = ci->children + i; - status = 0; if (strcasecmp ("Type", option->key) == 0) status = ut_config_type (&th, option); @@ -625,13 +512,12 @@ static int ut_report_state (const data_set_t *ds, if (state == STATE_OKAY) { if (state_old == STATE_MISSING) - status = ssnprintf (buf, bufsize, - ": Value is no longer missing."); + ssnprintf (buf, bufsize, ": Value is no longer missing."); else - status = ssnprintf (buf, bufsize, - ": All data sources are within range again."); - buf += status; - bufsize -= status; + ssnprintf (buf, bufsize, + ": All data sources are within range again. " + "Current value of \"%s\" is %f.", + ds->ds[ds_index].name, values[ds_index]); } else { @@ -645,7 +531,7 @@ static int ut_report_state (const data_set_t *ds, { if (!isnan (min) && !isnan (max)) { - status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " + 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", @@ -654,13 +540,13 @@ static int ut_report_state (const data_set_t *ds, } 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) ? "%" : ""); + 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 if (th->flags & UT_FLAG_PERCENTAGE) @@ -683,7 +569,7 @@ static int ut_report_state (const data_set_t *ds, else value = 100.0 * values[ds_index] / sum; - status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " + ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " "%g (%.2f%%). That is %s the %s threshold of %.2f%%.", ds->ds[ds_index].name, values[ds_index], value, (value < min) ? "below" : "above", @@ -692,15 +578,13 @@ static int ut_report_state (const data_set_t *ds, } else /* is not inverted */ { - status = ssnprintf (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); + ssnprintf (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; } plugin_dispatch_notification (&n); @@ -747,23 +631,40 @@ static int ut_check_one_data_source (const data_set_t *ds, /* 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) + if (th->hysteresis > 0) + { + prev_state = uc_get_state(ds,vl); + /* The purpose of hysteresis is elliminating flapping state when the value + * oscilates around the thresholds. In other words, what is important is + * the previous state; if the new value would trigger a transition, make + * sure that we artificially widen the range which is considered to apply + * for the previous state, and only trigger the notification if the value + * is outside of this expanded range. + * + * There is no hysteresis for the OKAY state. + * */ + gauge_t hysteresis_for_warning = 0, hysteresis_for_failure = 0; + 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++; + hysteresis_for_failure = th->hysteresis; + break; 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++; - } + hysteresis_for_warning = th->hysteresis; + break; + case STATE_OKAY: + /* do nothing -- the hysteresis only applies to the non-normal states */ + break; + } + + if ((!isnan (th->failure_min) && (th->failure_min + hysteresis_for_failure > values[ds_index])) + || (!isnan (th->failure_max) && (th->failure_max - hysteresis_for_failure < values[ds_index]))) + is_failure++; + + if ((!isnan (th->warning_min) && (th->warning_min + hysteresis_for_warning > values[ds_index])) + || (!isnan (th->warning_max) && (th->warning_max - hysteresis_for_warning < values[ds_index]))) + is_warning++; + } else { /* no hysteresis */ if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index])) @@ -773,7 +674,7 @@ static int ut_check_one_data_source (const data_set_t *ds, 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); @@ -862,7 +763,7 @@ static int ut_check_one_threshold (const data_set_t *ds, * * 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. + * function above. * Returns zero on success and if no threshold has been configured. Returns * less than zero on failure. */ @@ -967,10 +868,11 @@ static int ut_missing (const value_list_t *vl, return (0); } /* }}} int ut_missing */ -int ut_config (oconfig_item_t *ci) +static int ut_config (oconfig_item_t *ci) { /* {{{ */ int i; int status = 0; + int old_size = c_avl_size (threshold_tree); threshold_t th; @@ -993,11 +895,10 @@ int ut_config (oconfig_item_t *ci) th.hits = 0; th.hysteresis = 0; th.flags = UT_FLAG_INTERESTING; /* interesting by default */ - + for (i = 0; i < ci->children_num; i++) { oconfig_item_t *option = ci->children + i; - status = 0; if (strcasecmp ("Type", option->key) == 0) status = ut_config_type (&th, option); @@ -1015,7 +916,9 @@ int ut_config (oconfig_item_t *ci) break; } - if (c_avl_size (threshold_tree) > 0) { + /* register callbacks if this is the first time we see a valid config */ + if ((old_size == 0) && (c_avl_size (threshold_tree) > 0)) + { plugin_register_missing ("threshold", ut_missing, /* user data = */ NULL); plugin_register_write ("threshold", ut_check_threshold,