1 /**
2 * collectd - src/utils_threshold.c
3 * Copyright (C) 2007 Florian octo Forster
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Author:
19 * Florian octo Forster <octo at verplant.org>
20 **/
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "utils_avltree.h"
26 #include "utils_cache.h"
28 #include <assert.h>
29 #include <pthread.h>
31 /*
32 * Private data structures
33 */
34 typedef struct threshold_s
35 {
36 char host[DATA_MAX_NAME_LEN];
37 char plugin[DATA_MAX_NAME_LEN];
38 char plugin_instance[DATA_MAX_NAME_LEN];
39 char type[DATA_MAX_NAME_LEN];
40 char type_instance[DATA_MAX_NAME_LEN];
41 gauge_t min;
42 gauge_t max;
43 int invert;
44 } threshold_t;
46 /*
47 * Private (static) variables
48 */
49 static avl_tree_t *threshold_tree = NULL;
50 static pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER;
52 /*
53 * Threshold management
54 * ====================
55 * The following functions add, delete, search, etc. configured thresholds to
56 * the underlying AVL trees.
57 */
58 static int ut_threshold_add (const threshold_t *th)
59 {
60 char name[6 * DATA_MAX_NAME_LEN];
61 char *name_copy;
62 threshold_t *th_copy;
63 int status = 0;
65 if (format_name (name, sizeof (name), th->host,
66 th->plugin, th->plugin_instance,
67 th->type, th->type_instance) != 0)
68 {
69 ERROR ("ut_threshold_add: format_name failed.");
70 return (-1);
71 }
73 name_copy = strdup (name);
74 if (name_copy == NULL)
75 {
76 ERROR ("ut_threshold_add: strdup failed.");
77 return (-1);
78 }
80 th_copy = (threshold_t *) malloc (sizeof (threshold_t));
81 if (th_copy == NULL)
82 {
83 sfree (name_copy);
84 ERROR ("ut_threshold_add: malloc failed.");
85 return (-1);
86 }
87 memcpy (th_copy, th, sizeof (threshold_t));
89 DEBUG ("ut_threshold_add: Adding entry `%s'", name);
91 pthread_mutex_lock (&threshold_lock);
92 status = avl_insert (threshold_tree, name_copy, th_copy);
93 pthread_mutex_unlock (&threshold_lock);
95 if (status != 0)
96 {
97 ERROR ("ut_threshold_add: avl_insert (%s) failed.", name);
98 sfree (name_copy);
99 sfree (th_copy);
100 }
102 return (status);
103 } /* int ut_threshold_add */
104 /*
105 * End of the threshold management functions
106 */
108 /*
109 * Configuration
110 * =============
111 * The following approximately two hundred functions are used to convert the
112 * threshold values..
113 */
114 static int ut_config_type_instance (threshold_t *th, oconfig_item_t *ci)
115 {
116 if ((ci->values_num != 1)
117 || (ci->values[0].type != OCONFIG_TYPE_STRING))
118 {
119 WARNING ("threshold values: The `Instance' option needs exactly one "
120 "string argument.");
121 return (-1);
122 }
124 strncpy (th->type_instance, ci->values[0].value.string,
125 sizeof (th->type_instance));
126 th->type_instance[sizeof (th->type_instance) - 1] = '\0';
128 return (0);
129 } /* int ut_config_type_instance */
131 static int ut_config_type_max (threshold_t *th, oconfig_item_t *ci)
132 {
133 if ((ci->values_num != 1)
134 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
135 {
136 WARNING ("threshold values: The `Max' option needs exactly one "
137 "number argument.");
138 return (-1);
139 }
141 th->max = ci->values[0].value.number;
143 return (0);
144 } /* int ut_config_type_max */
146 static int ut_config_type_min (threshold_t *th, oconfig_item_t *ci)
147 {
148 if ((ci->values_num != 1)
149 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
150 {
151 WARNING ("threshold values: The `Min' option needs exactly one "
152 "number argument.");
153 return (-1);
154 }
156 th->min = ci->values[0].value.number;
158 return (0);
159 } /* int ut_config_type_min */
161 static int ut_config_type_invert (threshold_t *th, oconfig_item_t *ci)
162 {
163 if ((ci->values_num != 1)
164 || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
165 {
166 WARNING ("threshold values: The `Invert' option needs exactly one "
167 "boolean argument.");
168 return (-1);
169 }
171 th->invert = (ci->values[0].value.boolean) ? 1 : 0;
173 return (0);
174 } /* int ut_config_type_invert */
176 static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
177 {
178 int i;
179 threshold_t th;
180 int status = 0;
182 if ((ci->values_num != 1)
183 || (ci->values[0].type != OCONFIG_TYPE_STRING))
184 {
185 WARNING ("threshold values: The `Type' block needs exactly one string "
186 "argument.");
187 return (-1);
188 }
190 if (ci->children_num < 1)
191 {
192 WARNING ("threshold values: The `Type' block needs at least one option.");
193 return (-1);
194 }
196 memcpy (&th, th_orig, sizeof (th));
197 strncpy (th.type, ci->values[0].value.string, sizeof (th.type));
198 th.type[sizeof (th.type) - 1] = '\0';
200 for (i = 0; i < ci->children_num; i++)
201 {
202 oconfig_item_t *option = ci->children + i;
203 status = 0;
205 if (strcasecmp ("Instance", option->key) == 0)
206 status = ut_config_type_instance (&th, option);
207 else if (strcasecmp ("Max", option->key) == 0)
208 status = ut_config_type_max (&th, option);
209 else if (strcasecmp ("Min", option->key) == 0)
210 status = ut_config_type_min (&th, option);
211 else if (strcasecmp ("Invert", option->key) == 0)
212 status = ut_config_type_invert (&th, option);
213 else
214 {
215 WARNING ("threshold values: Option `%s' not allowed inside a `Type' "
216 "block.", option->key);
217 status = -1;
218 }
220 if (status != 0)
221 break;
222 }
224 if (status == 0)
225 {
226 status = ut_threshold_add (&th);
227 }
229 return (status);
230 } /* int ut_config_type */
232 static int ut_config_plugin_instance (threshold_t *th, oconfig_item_t *ci)
233 {
234 if ((ci->values_num != 1)
235 || (ci->values[0].type != OCONFIG_TYPE_STRING))
236 {
237 WARNING ("threshold values: The `Instance' option needs exactly one "
238 "string argument.");
239 return (-1);
240 }
242 strncpy (th->plugin_instance, ci->values[0].value.string,
243 sizeof (th->plugin_instance));
244 th->plugin_instance[sizeof (th->plugin_instance) - 1] = '\0';
246 return (0);
247 } /* int ut_config_plugin_instance */
249 static int ut_config_plugin (const threshold_t *th_orig, oconfig_item_t *ci)
250 {
251 int i;
252 threshold_t th;
253 int status = 0;
255 if ((ci->values_num != 1)
256 || (ci->values[0].type != OCONFIG_TYPE_STRING))
257 {
258 WARNING ("threshold values: The `Plugin' block needs exactly one string "
259 "argument.");
260 return (-1);
261 }
263 if (ci->children_num < 1)
264 {
265 WARNING ("threshold values: The `Plugin' block needs at least one nested "
266 "block.");
267 return (-1);
268 }
270 memcpy (&th, th_orig, sizeof (th));
271 strncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
272 th.plugin[sizeof (th.plugin) - 1] = '\0';
274 for (i = 0; i < ci->children_num; i++)
275 {
276 oconfig_item_t *option = ci->children + i;
277 status = 0;
279 if (strcasecmp ("Type", option->key) == 0)
280 status = ut_config_type (&th, option);
281 else if (strcasecmp ("Instance", option->key) == 0)
282 status = ut_config_plugin_instance (&th, option);
283 else
284 {
285 WARNING ("threshold values: Option `%s' not allowed inside a `Plugin' "
286 "block.", option->key);
287 status = -1;
288 }
290 if (status != 0)
291 break;
292 }
294 return (status);
295 } /* int ut_config_plugin */
297 static int ut_config_host (const threshold_t *th_orig, oconfig_item_t *ci)
298 {
299 int i;
300 threshold_t th;
301 int status = 0;
303 if ((ci->values_num != 1)
304 || (ci->values[0].type != OCONFIG_TYPE_STRING))
305 {
306 WARNING ("threshold values: The `Host' block needs exactly one string "
307 "argument.");
308 return (-1);
309 }
311 if (ci->children_num < 1)
312 {
313 WARNING ("threshold values: The `Host' block needs at least one nested "
314 "block.");
315 return (-1);
316 }
318 memcpy (&th, th_orig, sizeof (th));
319 strncpy (th.host, ci->values[0].value.string, sizeof (th.host));
320 th.host[sizeof (th.host) - 1] = '\0';
322 for (i = 0; i < ci->children_num; i++)
323 {
324 oconfig_item_t *option = ci->children + i;
325 status = 0;
327 if (strcasecmp ("Type", option->key) == 0)
328 status = ut_config_type (&th, option);
329 else if (strcasecmp ("Plugin", option->key) == 0)
330 status = ut_config_plugin (&th, option);
331 else
332 {
333 WARNING ("threshold values: Option `%s' not allowed inside a `Host' "
334 "block.", option->key);
335 status = -1;
336 }
338 if (status != 0)
339 break;
340 }
342 return (status);
343 } /* int ut_config_host */
345 int ut_config (const oconfig_item_t *ci)
346 {
347 int i;
348 int status = 0;
350 threshold_t th;
352 if (threshold_tree == NULL)
353 {
354 threshold_tree = avl_create ((void *) strcmp);
355 if (threshold_tree == NULL)
356 {
357 ERROR ("ut_config: avl_create failed.");
358 return (-1);
359 }
360 }
362 memset (&th, '\0', sizeof (th));
363 th.min = NAN;
364 th.max = NAN;
366 for (i = 0; i < ci->children_num; i++)
367 {
368 oconfig_item_t *option = ci->children + i;
369 status = 0;
371 if (strcasecmp ("Type", option->key) == 0)
372 status = ut_config_type (&th, option);
373 else if (strcasecmp ("Plugin", option->key) == 0)
374 status = ut_config_plugin (&th, option);
375 else if (strcasecmp ("Host", option->key) == 0)
376 status = ut_config_host (&th, option);
377 else
378 {
379 WARNING ("threshold values: Option `%s' not allowed here.", option->key);
380 status = -1;
381 }
383 if (status != 0)
384 break;
385 }
387 return (status);
388 } /* int um_config */
389 /*
390 * End of the functions used to configure threshold values.
391 */
393 /* vim: set sw=2 ts=8 sts=2 tw=78 : */