d393994b6a7f8820699250a4d8d9bccd6fd86026
1 /**
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
7 *
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.
11 *
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.
16 *
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
20 *
21 * Author:
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>
26 **/
28 #include "collectd.h"
30 #include "common.h"
31 #include "plugin.h"
32 #include "utils_avltree.h"
33 #include "utils_cache.h"
34 #include "utils_threshold.h"
35 #include "write_riemann_threshold.h"
37 #include <ltdl.h>
39 /*
40 * Threshold management
41 * ====================
42 * The following functions add, delete, etc. configured thresholds to
43 * the underlying AVL trees.
44 */
46 /*
47 * int ut_check_one_data_source
48 *
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
53 * appropriate.
54 * Does not fail.
55 */
56 static int ut_check_one_data_source (const data_set_t *ds,
57 const value_list_t __attribute__((unused)) *vl,
58 const threshold_t *th,
59 const gauge_t *values,
60 int ds_index)
61 { /* {{{ */
62 const char *ds_name;
63 int is_warning = 0;
64 int is_failure = 0;
65 int prev_state = STATE_OKAY;
67 /* check if this threshold applies to this data source */
68 if (ds != NULL)
69 {
70 ds_name = ds->ds[ds_index].name;
71 if ((th->data_source[0] != 0)
72 && (strcmp (ds_name, th->data_source) != 0))
73 return (STATE_OKAY);
74 }
76 if ((th->flags & UT_FLAG_INVERT) != 0)
77 {
78 is_warning--;
79 is_failure--;
80 }
82 /* XXX: This is an experimental code, not optimized, not fast, not reliable,
83 * and probably, do not work as you expect. Enjoy! :D */
84 if ( (th->hysteresis > 0) && ((prev_state = uc_get_state(ds,vl)) != STATE_OKAY) )
85 {
86 switch(prev_state)
87 {
88 case STATE_ERROR:
89 if ( (!isnan (th->failure_min) && ((th->failure_min + th->hysteresis) < values[ds_index])) ||
90 (!isnan (th->failure_max) && ((th->failure_max - th->hysteresis) > values[ds_index])) )
91 return (STATE_OKAY);
92 else
93 is_failure++;
94 case STATE_WARNING:
95 if ( (!isnan (th->warning_min) && ((th->warning_min + th->hysteresis) < values[ds_index])) ||
96 (!isnan (th->warning_max) && ((th->warning_max - th->hysteresis) > values[ds_index])) )
97 return (STATE_OKAY);
98 else
99 is_warning++;
100 }
101 }
102 else { /* no hysteresis */
103 if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
104 || (!isnan (th->failure_max) && (th->failure_max < values[ds_index])))
105 is_failure++;
107 if ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
108 || (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
109 is_warning++;
110 }
112 if (is_failure != 0)
113 return (STATE_ERROR);
115 if (is_warning != 0)
116 return (STATE_WARNING);
118 return (STATE_OKAY);
119 } /* }}} int ut_check_one_data_source */
121 /*
122 * int ut_check_one_threshold
123 *
124 * Checks all data sources of a value list against the given threshold, using
125 * the ut_check_one_data_source function above. Returns the worst status,
126 * which is `okay' if nothing has failed.
127 * Returns less than zero if the data set doesn't have any data sources.
128 */
129 static int ut_check_one_threshold (const data_set_t *ds,
130 const value_list_t *vl,
131 const threshold_t *th,
132 const gauge_t *values,
133 int *statuses)
134 { /* {{{ */
135 int ret = -1;
136 int status;
137 gauge_t values_copy[ds->ds_num];
139 memcpy (values_copy, values, sizeof (values_copy));
141 if ((th->flags & UT_FLAG_PERCENTAGE) != 0)
142 {
143 int num = 0;
144 gauge_t sum=0.0;
146 if (ds->ds_num == 1)
147 {
148 WARNING ("ut_check_one_threshold: The %s type has only one data "
149 "source, but you have configured to check this as a percentage. "
150 "That doesn't make much sense, because the percentage will always "
151 "be 100%%!", ds->type);
152 }
154 /* Prepare `sum' and `num'. */
155 for (size_t i = 0; i < ds->ds_num; i++)
156 if (!isnan (values[i]))
157 {
158 num++;
159 sum += values[i];
160 }
162 if ((num == 0) /* All data sources are undefined. */
163 || (sum == 0.0)) /* Sum is zero, cannot calculate percentage. */
164 {
165 for (size_t i = 0; i < ds->ds_num; i++)
166 values_copy[i] = NAN;
167 }
168 else /* We can actually calculate the percentage. */
169 {
170 for (size_t i = 0; i < ds->ds_num; i++)
171 values_copy[i] = 100.0 * values[i] / sum;
172 }
173 } /* if (UT_FLAG_PERCENTAGE) */
175 for (size_t i = 0; i < ds->ds_num; i++)
176 {
177 status = ut_check_one_data_source (ds, vl, th, values_copy, i);
178 if (status != -1) {
179 ret = 0;
180 if (statuses[i] < status)
181 statuses[i] = status;
182 }
183 } /* for (ds->ds_num) */
185 return (ret);
186 } /* }}} int ut_check_one_threshold */
188 /*
189 * int ut_check_threshold
190 *
191 * Gets a list of matching thresholds and searches for the worst status by one
192 * of the thresholds. Then reports that status using the ut_report_state
193 * function above.
194 * Returns zero on success and if no threshold has been configured. Returns
195 * less than zero on failure.
196 */
197 int write_riemann_threshold_check (const data_set_t *ds, const value_list_t *vl,
198 int *statuses)
199 { /* {{{ */
200 threshold_t *th;
201 gauge_t *values;
202 int status;
204 assert (vl->values_len > 0);
205 memset(statuses, 0, vl->values_len * sizeof(*statuses));
207 if (threshold_tree == NULL)
208 return 0;
210 /* Is this lock really necessary? So far, thresholds are only inserted at
211 * startup. -octo */
212 pthread_mutex_lock (&threshold_lock);
213 th = threshold_search (vl);
214 pthread_mutex_unlock (&threshold_lock);
215 if (th == NULL)
216 return (0);
218 DEBUG ("ut_check_threshold: Found matching threshold(s)");
220 values = uc_get_rate (ds, vl);
221 if (values == NULL)
222 return (0);
224 while (th != NULL)
225 {
226 status = ut_check_one_threshold (ds, vl, th, values, statuses);
227 if (status < 0)
228 {
229 ERROR ("ut_check_threshold: ut_check_one_threshold failed.");
230 sfree (values);
231 return (-1);
232 }
234 th = th->next;
235 } /* while (th) */
237 sfree (values);
239 return (0);
240 } /* }}} int ut_check_threshold */
243 /* vim: set sw=2 ts=8 sts=2 tw=78 et fdm=marker : */