Merge branch 'collectd-4.2'
[collectd.git] / src / utils_threshold.c
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  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "utils_avltree.h"
26 #include "utils_cache.h"
27
28 #include <assert.h>
29 #include <pthread.h>
30
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;
45
46 /*
47  * Private (static) variables
48  */
49 static avl_tree_t     *threshold_tree = NULL;
50 static pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER;
51
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;
64
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   }
72
73   name_copy = strdup (name);
74   if (name_copy == NULL)
75   {
76     ERROR ("ut_threshold_add: strdup failed.");
77     return (-1);
78   }
79
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));
88
89   DEBUG ("ut_threshold_add: Adding entry `%s'", name);
90
91   pthread_mutex_lock (&threshold_lock);
92   status = avl_insert (threshold_tree, name_copy, th_copy);
93   pthread_mutex_unlock (&threshold_lock);
94
95   if (status != 0)
96   {
97     ERROR ("ut_threshold_add: avl_insert (%s) failed.", name);
98     sfree (name_copy);
99     sfree (th_copy);
100   }
101
102   return (status);
103 } /* int ut_threshold_add */
104 /*
105  * End of the threshold management functions
106  */
107
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   }
123
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';
127
128   return (0);
129 } /* int ut_config_type_instance */
130
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   }
140
141   th->max = ci->values[0].value.number;
142
143   return (0);
144 } /* int ut_config_type_max */
145
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   }
155
156   th->min = ci->values[0].value.number;
157
158   return (0);
159 } /* int ut_config_type_min */
160
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   }
170
171   th->invert = (ci->values[0].value.boolean) ? 1 : 0;
172
173   return (0);
174 } /* int ut_config_type_invert */
175
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;
181
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   }
189
190   if (ci->children_num < 1)
191   {
192     WARNING ("threshold values: The `Type' block needs at least one option.");
193     return (-1);
194   }
195
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';
199
200   for (i = 0; i < ci->children_num; i++)
201   {
202     oconfig_item_t *option = ci->children + i;
203     status = 0;
204
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     }
219
220     if (status != 0)
221       break;
222   }
223
224   if (status == 0)
225   {
226     status = ut_threshold_add (&th);
227   }
228
229   return (status);
230 } /* int ut_config_type */
231
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   }
241
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';
245
246   return (0);
247 } /* int ut_config_plugin_instance */
248
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;
254
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   }
262
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   }
269
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';
273
274   for (i = 0; i < ci->children_num; i++)
275   {
276     oconfig_item_t *option = ci->children + i;
277     status = 0;
278
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     }
289
290     if (status != 0)
291       break;
292   }
293
294   return (status);
295 } /* int ut_config_plugin */
296
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;
302
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   }
310
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   }
317
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';
321
322   for (i = 0; i < ci->children_num; i++)
323   {
324     oconfig_item_t *option = ci->children + i;
325     status = 0;
326
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     }
337
338     if (status != 0)
339       break;
340   }
341
342   return (status);
343 } /* int ut_config_host */
344
345 int ut_config (const oconfig_item_t *ci)
346 {
347   int i;
348   int status = 0;
349
350   threshold_t th;
351
352   memset (&th, '\0', sizeof (th));
353   th.min = NAN;
354   th.max = NAN;
355     
356   for (i = 0; i < ci->children_num; i++)
357   {
358     oconfig_item_t *option = ci->children + i;
359     status = 0;
360
361     if (strcasecmp ("Type", option->key) == 0)
362       status = ut_config_type (&th, option);
363     else if (strcasecmp ("Plugin", option->key) == 0)
364       status = ut_config_plugin (&th, option);
365     else if (strcasecmp ("Host", option->key) == 0)
366       status = ut_config_host (&th, option);
367     else
368     {
369       WARNING ("threshold values: Option `%s' not allowed here.", option->key);
370       status = -1;
371     }
372
373     if (status != 0)
374       break;
375   }
376
377   return (status);
378 } /* int um_config */
379 /*
380  * End of the functions used to configure threshold values.
381  */
382
383 /* vim: set sw=2 ts=8 sts=2 tw=78 : */