2 * collectd - src/threshold.c
3 * Copyright (C) 2007-2010 Florian Forster
4 * Copyright (C) 2008-2009 Sebastian Harl
5 * Copyright (C) 2009 Andrés J. Díaz
6 * Copyright (C) 2014 Pierre-Yves Ritschard
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; only version 2 of the License is applicable.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Pierre-Yves Ritschard <pyr at spootnik.org>
23 * Florian octo Forster <octo at collectd.org>
24 * Sebastian Harl <sh at tokkee.org>
25 * Andrés J. Díaz <ajdiaz at connectical.com>
32 #include "utils_avltree.h"
33 #include "utils_cache.h"
34 #include "utils_threshold.h"
35 #include "write_riemann_threshold.h"
40 * Threshold management
41 * ====================
42 * The following functions add, delete, etc. configured thresholds to
43 * the underlying AVL trees.
47 * int ut_check_one_data_source
49 * Checks one data source against the given threshold configuration. If the
50 * `DataSource' option is set in the threshold, and the name does NOT match,
51 * `okay' is returned. If the threshold does match, its failure and warning
52 * min and max values are checked and `failure' or `warning' is returned if
56 static int ut_check_one_data_source(
57 const data_set_t *ds, const value_list_t __attribute__((unused)) * vl,
58 const threshold_t *th, const gauge_t *values, int ds_index) { /* {{{ */
62 int prev_state = STATE_OKAY;
64 /* check if this threshold applies to this data source */
66 ds_name = ds->ds[ds_index].name;
67 if ((th->data_source[0] != 0) && (strcmp(ds_name, th->data_source) != 0))
71 if ((th->flags & UT_FLAG_INVERT) != 0) {
76 /* XXX: This is an experimental code, not optimized, not fast, not reliable,
77 * and probably, do not work as you expect. Enjoy! :D */
78 if ((th->hysteresis > 0) &&
79 ((prev_state = uc_get_state(ds, vl)) != STATE_OKAY)) {
82 if ((!isnan(th->failure_min) &&
83 ((th->failure_min + th->hysteresis) < values[ds_index])) ||
84 (!isnan(th->failure_max) &&
85 ((th->failure_max - th->hysteresis) > values[ds_index])))
90 if ((!isnan(th->warning_min) &&
91 ((th->warning_min + th->hysteresis) < values[ds_index])) ||
92 (!isnan(th->warning_max) &&
93 ((th->warning_max - th->hysteresis) > values[ds_index])))
98 } else { /* no hysteresis */
99 if ((!isnan(th->failure_min) && (th->failure_min > values[ds_index])) ||
100 (!isnan(th->failure_max) && (th->failure_max < values[ds_index])))
103 if ((!isnan(th->warning_min) && (th->warning_min > values[ds_index])) ||
104 (!isnan(th->warning_max) && (th->warning_max < values[ds_index])))
109 return (STATE_ERROR);
112 return (STATE_WARNING);
115 } /* }}} int ut_check_one_data_source */
118 * int ut_check_one_threshold
120 * Checks all data sources of a value list against the given threshold, using
121 * the ut_check_one_data_source function above. Returns the worst status,
122 * which is `okay' if nothing has failed.
123 * Returns less than zero if the data set doesn't have any data sources.
125 static int ut_check_one_threshold(const data_set_t *ds, const value_list_t *vl,
126 const threshold_t *th, const gauge_t *values,
127 int *statuses) { /* {{{ */
130 gauge_t values_copy[ds->ds_num];
132 memcpy(values_copy, values, sizeof(values_copy));
134 if ((th->flags & UT_FLAG_PERCENTAGE) != 0) {
138 if (ds->ds_num == 1) {
140 "ut_check_one_threshold: The %s type has only one data "
141 "source, but you have configured to check this as a percentage. "
142 "That doesn't make much sense, because the percentage will always "
147 /* Prepare `sum' and `num'. */
148 for (size_t i = 0; i < ds->ds_num; i++)
149 if (!isnan(values[i])) {
154 if ((num == 0) /* All data sources are undefined. */
155 || (sum == 0.0)) /* Sum is zero, cannot calculate percentage. */
157 for (size_t i = 0; i < ds->ds_num; i++)
158 values_copy[i] = NAN;
159 } else /* We can actually calculate the percentage. */
161 for (size_t i = 0; i < ds->ds_num; i++)
162 values_copy[i] = 100.0 * values[i] / sum;
164 } /* if (UT_FLAG_PERCENTAGE) */
166 for (size_t i = 0; i < ds->ds_num; i++) {
167 status = ut_check_one_data_source(ds, vl, th, values_copy, i);
170 if (statuses[i] < status)
171 statuses[i] = status;
173 } /* for (ds->ds_num) */
176 } /* }}} int ut_check_one_threshold */
179 * int ut_check_threshold
181 * Gets a list of matching thresholds and searches for the worst status by one
182 * of the thresholds. Then reports that status using the ut_report_state
184 * Returns zero on success and if no threshold has been configured. Returns
185 * less than zero on failure.
187 int write_riemann_threshold_check(const data_set_t *ds, const value_list_t *vl,
188 int *statuses) { /* {{{ */
193 assert(vl->values_len > 0);
194 memset(statuses, 0, vl->values_len * sizeof(*statuses));
196 if (threshold_tree == NULL)
199 /* Is this lock really necessary? So far, thresholds are only inserted at
201 pthread_mutex_lock(&threshold_lock);
202 th = threshold_search(vl);
203 pthread_mutex_unlock(&threshold_lock);
207 DEBUG("ut_check_threshold: Found matching threshold(s)");
209 values = uc_get_rate(ds, vl);
214 status = ut_check_one_threshold(ds, vl, th, values, statuses);
216 ERROR("ut_check_threshold: ut_check_one_threshold failed.");
227 } /* }}} int ut_check_threshold */
229 /* vim: set sw=2 ts=8 sts=2 tw=78 et fdm=marker : */