d51789db22ace6273d7eaf5b47d59c44aa59fed1
1 /**
2 * collectd - src/utils_threshold.c
3 * Copyright (C) 2007,2008 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 #define UT_FLAG_INVERT 0x01
35 #define UT_FLAG_PERSIST 0x02
36 #define UT_FLAG_PERCENTAGE 0x04
38 typedef struct threshold_s
39 {
40 char host[DATA_MAX_NAME_LEN];
41 char plugin[DATA_MAX_NAME_LEN];
42 char plugin_instance[DATA_MAX_NAME_LEN];
43 char type[DATA_MAX_NAME_LEN];
44 char type_instance[DATA_MAX_NAME_LEN];
45 char data_source[DATA_MAX_NAME_LEN];
46 gauge_t warning_min;
47 gauge_t warning_max;
48 gauge_t failure_min;
49 gauge_t failure_max;
50 int flags;
51 struct threshold_s *next;
52 } threshold_t;
53 /* }}} */
55 /*
56 * Private (static) variables
57 * {{{ */
58 static c_avl_tree_t *threshold_tree = NULL;
59 static pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER;
60 /* }}} */
62 /*
63 * Threshold management
64 * ====================
65 * The following functions add, delete, search, etc. configured thresholds to
66 * the underlying AVL trees.
67 * {{{ */
68 static threshold_t *threshold_get (const char *hostname,
69 const char *plugin, const char *plugin_instance,
70 const char *type, const char *type_instance)
71 {
72 char name[6 * DATA_MAX_NAME_LEN];
73 threshold_t *th = NULL;
75 format_name (name, sizeof (name),
76 (hostname == NULL) ? "" : hostname,
77 (plugin == NULL) ? "" : plugin, plugin_instance,
78 (type == NULL) ? "" : type, type_instance);
79 name[sizeof (name) - 1] = '\0';
81 if (c_avl_get (threshold_tree, name, (void *) &th) == 0)
82 return (th);
83 else
84 return (NULL);
85 } /* threshold_t *threshold_get */
87 static int ut_threshold_add (const threshold_t *th)
88 {
89 char name[6 * DATA_MAX_NAME_LEN];
90 char *name_copy;
91 threshold_t *th_copy;
92 threshold_t *th_ptr;
93 int status = 0;
95 if (format_name (name, sizeof (name), th->host,
96 th->plugin, th->plugin_instance,
97 th->type, th->type_instance) != 0)
98 {
99 ERROR ("ut_threshold_add: format_name failed.");
100 return (-1);
101 }
103 name_copy = strdup (name);
104 if (name_copy == NULL)
105 {
106 ERROR ("ut_threshold_add: strdup failed.");
107 return (-1);
108 }
110 th_copy = (threshold_t *) malloc (sizeof (threshold_t));
111 if (th_copy == NULL)
112 {
113 sfree (name_copy);
114 ERROR ("ut_threshold_add: malloc failed.");
115 return (-1);
116 }
117 memcpy (th_copy, th, sizeof (threshold_t));
118 th_ptr = NULL;
120 DEBUG ("ut_threshold_add: Adding entry `%s'", name);
122 pthread_mutex_lock (&threshold_lock);
124 th_ptr = threshold_get (th->host, th->plugin, th->plugin_instance,
125 th->type, th->type_instance);
127 while ((th_ptr != NULL) && (th_ptr->next != NULL))
128 th_ptr = th_ptr->next;
130 if (th_ptr == NULL) /* no such threshold yet */
131 {
132 status = c_avl_insert (threshold_tree, name_copy, th_copy);
133 }
134 else /* th_ptr points to the last threshold in the list */
135 {
136 th_ptr->next = th_copy;
137 /* name_copy isn't needed */
138 sfree (name_copy);
139 }
141 pthread_mutex_unlock (&threshold_lock);
143 if (status != 0)
144 {
145 ERROR ("ut_threshold_add: c_avl_insert (%s) failed.", name);
146 sfree (name_copy);
147 sfree (th_copy);
148 }
150 return (status);
151 } /* int ut_threshold_add */
152 /*
153 * End of the threshold management functions
154 * }}} */
156 /*
157 * Configuration
158 * =============
159 * The following approximately two hundred functions are used to handle the
160 * configuration and fill the threshold list.
161 * {{{ */
162 static int ut_config_type_datasource (threshold_t *th, oconfig_item_t *ci)
163 {
164 if ((ci->values_num != 1)
165 || (ci->values[0].type != OCONFIG_TYPE_STRING))
166 {
167 WARNING ("threshold values: The `DataSource' option needs exactly one "
168 "string argument.");
169 return (-1);
170 }
172 sstrncpy (th->data_source, ci->values[0].value.string,
173 sizeof (th->data_source));
175 return (0);
176 } /* int ut_config_type_datasource */
178 static int ut_config_type_instance (threshold_t *th, oconfig_item_t *ci)
179 {
180 if ((ci->values_num != 1)
181 || (ci->values[0].type != OCONFIG_TYPE_STRING))
182 {
183 WARNING ("threshold values: The `Instance' option needs exactly one "
184 "string argument.");
185 return (-1);
186 }
188 sstrncpy (th->type_instance, ci->values[0].value.string,
189 sizeof (th->type_instance));
191 return (0);
192 } /* int ut_config_type_instance */
194 static int ut_config_type_max (threshold_t *th, oconfig_item_t *ci)
195 {
196 if ((ci->values_num != 1)
197 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
198 {
199 WARNING ("threshold values: The `%s' option needs exactly one "
200 "number argument.", ci->key);
201 return (-1);
202 }
204 if (strcasecmp (ci->key, "WarningMax") == 0)
205 th->warning_max = ci->values[0].value.number;
206 else
207 th->failure_max = ci->values[0].value.number;
209 return (0);
210 } /* int ut_config_type_max */
212 static int ut_config_type_min (threshold_t *th, oconfig_item_t *ci)
213 {
214 if ((ci->values_num != 1)
215 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
216 {
217 WARNING ("threshold values: The `%s' option needs exactly one "
218 "number argument.", ci->key);
219 return (-1);
220 }
222 if (strcasecmp (ci->key, "WarningMin") == 0)
223 th->warning_min = ci->values[0].value.number;
224 else
225 th->failure_min = ci->values[0].value.number;
227 return (0);
228 } /* int ut_config_type_min */
230 static int ut_config_type_invert (threshold_t *th, oconfig_item_t *ci)
231 {
232 if ((ci->values_num != 1)
233 || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
234 {
235 WARNING ("threshold values: The `Invert' option needs exactly one "
236 "boolean argument.");
237 return (-1);
238 }
240 if (ci->values[0].value.boolean)
241 th->flags |= UT_FLAG_INVERT;
242 else
243 th->flags &= ~UT_FLAG_INVERT;
245 return (0);
246 } /* int ut_config_type_invert */
248 static int ut_config_type_persist (threshold_t *th, oconfig_item_t *ci)
249 {
250 if ((ci->values_num != 1)
251 || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
252 {
253 WARNING ("threshold values: The `Persist' option needs exactly one "
254 "boolean argument.");
255 return (-1);
256 }
258 if (ci->values[0].value.boolean)
259 th->flags |= UT_FLAG_PERSIST;
260 else
261 th->flags &= ~UT_FLAG_PERSIST;
263 return (0);
264 } /* int ut_config_type_persist */
266 static int ut_config_type_percentage(threshold_t *th, oconfig_item_t *ci)
267 {
268 if ((ci->values_num != 1)
269 || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
270 {
271 WARNING ("threshold values: The `Percentage' option needs exactly one "
272 "boolean argument.");
273 return (-1);
274 }
276 if (ci->values[0].value.boolean)
277 th->flags |= UT_FLAG_PERCENTAGE;
278 else
279 th->flags &= ~UT_FLAG_PERCENTAGE;
281 return (0);
282 } /* int ut_config_type_percentage */
284 static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
285 {
286 int i;
287 threshold_t th;
288 int status = 0;
290 if ((ci->values_num != 1)
291 || (ci->values[0].type != OCONFIG_TYPE_STRING))
292 {
293 WARNING ("threshold values: The `Type' block needs exactly one string "
294 "argument.");
295 return (-1);
296 }
298 if (ci->children_num < 1)
299 {
300 WARNING ("threshold values: The `Type' block needs at least one option.");
301 return (-1);
302 }
304 memcpy (&th, th_orig, sizeof (th));
305 sstrncpy (th.type, ci->values[0].value.string, sizeof (th.type));
307 th.warning_min = NAN;
308 th.warning_max = NAN;
309 th.failure_min = NAN;
310 th.failure_max = NAN;
312 for (i = 0; i < ci->children_num; i++)
313 {
314 oconfig_item_t *option = ci->children + i;
315 status = 0;
317 if (strcasecmp ("Instance", option->key) == 0)
318 status = ut_config_type_instance (&th, option);
319 else if (strcasecmp ("DataSource", option->key) == 0)
320 status = ut_config_type_datasource (&th, option);
321 else if ((strcasecmp ("WarningMax", option->key) == 0)
322 || (strcasecmp ("FailureMax", option->key) == 0))
323 status = ut_config_type_max (&th, option);
324 else if ((strcasecmp ("WarningMin", option->key) == 0)
325 || (strcasecmp ("FailureMin", option->key) == 0))
326 status = ut_config_type_min (&th, option);
327 else if (strcasecmp ("Invert", option->key) == 0)
328 status = ut_config_type_invert (&th, option);
329 else if (strcasecmp ("Persist", option->key) == 0)
330 status = ut_config_type_persist (&th, option);
331 else if (strcasecmp ("Percentage", option->key) == 0)
332 status = ut_config_type_percentage (&th, option);
333 else
334 {
335 WARNING ("threshold values: Option `%s' not allowed inside a `Type' "
336 "block.", option->key);
337 status = -1;
338 }
340 if (status != 0)
341 break;
342 }
344 if (status == 0)
345 {
346 status = ut_threshold_add (&th);
347 }
349 return (status);
350 } /* int ut_config_type */
352 static int ut_config_plugin_instance (threshold_t *th, oconfig_item_t *ci)
353 {
354 if ((ci->values_num != 1)
355 || (ci->values[0].type != OCONFIG_TYPE_STRING))
356 {
357 WARNING ("threshold values: The `Instance' option needs exactly one "
358 "string argument.");
359 return (-1);
360 }
362 sstrncpy (th->plugin_instance, ci->values[0].value.string,
363 sizeof (th->plugin_instance));
365 return (0);
366 } /* int ut_config_plugin_instance */
368 static int ut_config_plugin (const threshold_t *th_orig, oconfig_item_t *ci)
369 {
370 int i;
371 threshold_t th;
372 int status = 0;
374 if ((ci->values_num != 1)
375 || (ci->values[0].type != OCONFIG_TYPE_STRING))
376 {
377 WARNING ("threshold values: The `Plugin' block needs exactly one string "
378 "argument.");
379 return (-1);
380 }
382 if (ci->children_num < 1)
383 {
384 WARNING ("threshold values: The `Plugin' block needs at least one nested "
385 "block.");
386 return (-1);
387 }
389 memcpy (&th, th_orig, sizeof (th));
390 sstrncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
392 for (i = 0; i < ci->children_num; i++)
393 {
394 oconfig_item_t *option = ci->children + i;
395 status = 0;
397 if (strcasecmp ("Type", option->key) == 0)
398 status = ut_config_type (&th, option);
399 else if (strcasecmp ("Instance", option->key) == 0)
400 status = ut_config_plugin_instance (&th, option);
401 else
402 {
403 WARNING ("threshold values: Option `%s' not allowed inside a `Plugin' "
404 "block.", option->key);
405 status = -1;
406 }
408 if (status != 0)
409 break;
410 }
412 return (status);
413 } /* int ut_config_plugin */
415 static int ut_config_host (const threshold_t *th_orig, oconfig_item_t *ci)
416 {
417 int i;
418 threshold_t th;
419 int status = 0;
421 if ((ci->values_num != 1)
422 || (ci->values[0].type != OCONFIG_TYPE_STRING))
423 {
424 WARNING ("threshold values: The `Host' block needs exactly one string "
425 "argument.");
426 return (-1);
427 }
429 if (ci->children_num < 1)
430 {
431 WARNING ("threshold values: The `Host' block needs at least one nested "
432 "block.");
433 return (-1);
434 }
436 memcpy (&th, th_orig, sizeof (th));
437 sstrncpy (th.host, ci->values[0].value.string, sizeof (th.host));
439 for (i = 0; i < ci->children_num; i++)
440 {
441 oconfig_item_t *option = ci->children + i;
442 status = 0;
444 if (strcasecmp ("Type", option->key) == 0)
445 status = ut_config_type (&th, option);
446 else if (strcasecmp ("Plugin", option->key) == 0)
447 status = ut_config_plugin (&th, option);
448 else
449 {
450 WARNING ("threshold values: Option `%s' not allowed inside a `Host' "
451 "block.", option->key);
452 status = -1;
453 }
455 if (status != 0)
456 break;
457 }
459 return (status);
460 } /* int ut_config_host */
462 int ut_config (const oconfig_item_t *ci)
463 {
464 int i;
465 int status = 0;
467 threshold_t th;
469 if (ci->values_num != 0)
470 {
471 ERROR ("threshold values: The `Threshold' block may not have any "
472 "arguments.");
473 return (-1);
474 }
476 if (threshold_tree == NULL)
477 {
478 threshold_tree = c_avl_create ((void *) strcmp);
479 if (threshold_tree == NULL)
480 {
481 ERROR ("ut_config: c_avl_create failed.");
482 return (-1);
483 }
484 }
486 memset (&th, '\0', sizeof (th));
487 th.warning_min = NAN;
488 th.warning_max = NAN;
489 th.failure_min = NAN;
490 th.failure_max = NAN;
492 for (i = 0; i < ci->children_num; i++)
493 {
494 oconfig_item_t *option = ci->children + i;
495 status = 0;
497 if (strcasecmp ("Type", option->key) == 0)
498 status = ut_config_type (&th, option);
499 else if (strcasecmp ("Plugin", option->key) == 0)
500 status = ut_config_plugin (&th, option);
501 else if (strcasecmp ("Host", option->key) == 0)
502 status = ut_config_host (&th, option);
503 else
504 {
505 WARNING ("threshold values: Option `%s' not allowed here.", option->key);
506 status = -1;
507 }
509 if (status != 0)
510 break;
511 }
513 return (status);
514 } /* int um_config */
515 /*
516 * End of the functions used to configure threshold values.
517 */
518 /* }}} */
520 static threshold_t *threshold_search (const value_list_t *vl)
521 {
522 threshold_t *th;
524 if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
525 vl->type, vl->type_instance)) != NULL)
526 return (th);
527 else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
528 vl->type, NULL)) != NULL)
529 return (th);
530 else if ((th = threshold_get (vl->host, vl->plugin, NULL,
531 vl->type, vl->type_instance)) != NULL)
532 return (th);
533 else if ((th = threshold_get (vl->host, vl->plugin, NULL,
534 vl->type, NULL)) != NULL)
535 return (th);
536 else if ((th = threshold_get (vl->host, "", NULL,
537 vl->type, vl->type_instance)) != NULL)
538 return (th);
539 else if ((th = threshold_get (vl->host, "", NULL,
540 vl->type, NULL)) != NULL)
541 return (th);
542 else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
543 vl->type, vl->type_instance)) != NULL)
544 return (th);
545 else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
546 vl->type, NULL)) != NULL)
547 return (th);
548 else if ((th = threshold_get ("", vl->plugin, NULL,
549 vl->type, vl->type_instance)) != NULL)
550 return (th);
551 else if ((th = threshold_get ("", vl->plugin, NULL,
552 vl->type, NULL)) != NULL)
553 return (th);
554 else if ((th = threshold_get ("", "", NULL,
555 vl->type, vl->type_instance)) != NULL)
556 return (th);
557 else if ((th = threshold_get ("", "", NULL,
558 vl->type, NULL)) != NULL)
559 return (th);
561 return (NULL);
562 } /* threshold_t *threshold_search */
564 /*
565 * int ut_report_state
566 *
567 * Checks if the `state' differs from the old state and creates a notification
568 * if appropriate.
569 * Does not fail.
570 */
571 static int ut_report_state (const data_set_t *ds,
572 const value_list_t *vl,
573 const threshold_t *th,
574 const gauge_t *values,
575 int ds_index,
576 int state)
577 { /* {{{ */
578 int state_old;
579 notification_t n;
581 char *buf;
582 size_t bufsize;
584 int status;
586 state_old = uc_get_state (ds, vl);
588 /* If the state didn't change, only report if `persistent' is specified and
589 * the state is not `okay'. */
590 if (state == state_old)
591 {
592 if ((th->flags & UT_FLAG_PERSIST) == 0)
593 return (0);
594 else if (state == STATE_OKAY)
595 return (0);
596 }
598 if (state != state_old)
599 uc_set_state (ds, vl, state);
601 NOTIFICATION_INIT_VL (&n, vl, ds);
603 buf = n.message;
604 bufsize = sizeof (n.message);
606 if (state == STATE_OKAY)
607 n.severity = NOTIF_OKAY;
608 else if (state == STATE_WARNING)
609 n.severity = NOTIF_WARNING;
610 else
611 n.severity = NOTIF_FAILURE;
613 n.time = vl->time;
615 status = ssnprintf (buf, bufsize, "Host %s, plugin %s",
616 vl->host, vl->plugin);
617 buf += status;
618 bufsize -= status;
620 if (vl->plugin_instance[0] != '\0')
621 {
622 status = ssnprintf (buf, bufsize, " (instance %s)",
623 vl->plugin_instance);
624 buf += status;
625 bufsize -= status;
626 }
628 status = ssnprintf (buf, bufsize, " type %s", vl->type);
629 buf += status;
630 bufsize -= status;
632 if (vl->type_instance[0] != '\0')
633 {
634 status = ssnprintf (buf, bufsize, " (instance %s)",
635 vl->type_instance);
636 buf += status;
637 bufsize -= status;
638 }
640 plugin_notification_meta_add_string (&n, "DataSource",
641 ds->ds[ds_index].name);
642 plugin_notification_meta_add_double (&n, "CurrentValue", values[ds_index]);
643 plugin_notification_meta_add_double (&n, "WarningMin", th->warning_min);
644 plugin_notification_meta_add_double (&n, "WarningMax", th->warning_max);
645 plugin_notification_meta_add_double (&n, "FailureMin", th->failure_min);
646 plugin_notification_meta_add_double (&n, "FailureMax", th->failure_max);
648 /* Send an okay notification */
649 if (state == STATE_OKAY)
650 {
651 status = ssnprintf (buf, bufsize, ": All data sources are within range again.");
652 buf += status;
653 bufsize -= status;
654 }
655 else
656 {
657 double min;
658 double max;
660 min = (state == STATE_ERROR) ? th->failure_min : th->warning_min;
661 max = (state == STATE_ERROR) ? th->failure_max : th->warning_max;
663 if (th->flags & UT_FLAG_INVERT)
664 {
665 if (!isnan (min) && !isnan (max))
666 {
667 status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
668 "%f. That is within the %s region of %f%s and %f%s.",
669 ds->ds[ds_index].name, values[ds_index],
670 (state == STATE_ERROR) ? "failure" : "warning",
671 min, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "",
672 max, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
673 }
674 else
675 {
676 status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
677 "%f. That is %s the %s threshold of %f%s.",
678 ds->ds[ds_index].name, values[ds_index],
679 isnan (min) ? "below" : "above",
680 (state == STATE_ERROR) ? "failure" : "warning",
681 isnan (min) ? max : min,
682 ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
683 }
684 }
685 else /* is not inverted */
686 {
687 status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
688 "%f. That is %s the %s threshold of %f%s.",
689 ds->ds[ds_index].name, values[ds_index],
690 (values[ds_index] < min) ? "below" : "above",
691 (state == STATE_ERROR) ? "failure" : "warning",
692 (values[ds_index] < min) ? min : max,
693 ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
694 }
695 buf += status;
696 bufsize -= status;
697 }
699 plugin_dispatch_notification (&n);
701 plugin_notification_meta_free (n.meta);
702 return (0);
703 } /* }}} int ut_report_state */
705 /*
706 * int ut_check_one_data_source
707 *
708 * Checks one data source against the given threshold configuration. If the
709 * `DataSource' option is set in the threshold, and the name does NOT match,
710 * `okay' is returned. If the threshold does match, its failure and warning
711 * min and max values are checked and `failure' or `warning' is returned if
712 * appropriate.
713 * Does not fail.
714 */
715 static int ut_check_one_data_source (const data_set_t *ds,
716 const value_list_t __attribute__((unused)) *vl,
717 const threshold_t *th,
718 const gauge_t *values,
719 int ds_index)
720 { /* {{{ */
721 const char *ds_name;
722 int is_warning = 0;
723 int is_failure = 0;
725 /* check if this threshold applies to this data source */
726 if (ds != NULL)
727 {
728 ds_name = ds->ds[ds_index].name;
729 if ((th->data_source[0] != 0)
730 && (strcmp (ds_name, th->data_source) != 0))
731 return (STATE_OKAY);
732 }
734 if ((th->flags & UT_FLAG_INVERT) != 0)
735 {
736 is_warning--;
737 is_failure--;
738 }
740 if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
741 || (!isnan (th->failure_max) && (th->failure_max < values[ds_index])))
742 is_failure++;
743 if (is_failure != 0)
744 return (STATE_ERROR);
746 if ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
747 || (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
748 is_warning++;
749 if (is_warning != 0)
750 return (STATE_WARNING);
752 return (STATE_OKAY);
753 } /* }}} int ut_check_one_data_source */
755 /*
756 * int ut_check_one_threshold
757 *
758 * Checks all data sources of a value list against the given threshold, using
759 * the ut_check_one_data_source function above. Returns the worst status,
760 * which is `okay' if nothing has failed.
761 * Returns less than zero if the data set doesn't have any data sources.
762 */
763 static int ut_check_one_threshold (const data_set_t *ds,
764 const value_list_t *vl,
765 const threshold_t *th,
766 const gauge_t *values,
767 int *ret_ds_index)
768 { /* {{{ */
769 int ret = -1;
770 int ds_index = -1;
771 int i;
773 if ((th->flags & UT_FLAG_PERCENTAGE) == UT_FLAG_PERCENTAGE)
774 {
776 gauge_t sum=0.0;
777 gauge_t percentage;
779 for (i = 0; i < ds->ds_num; i++)
780 if (!isnan (values[i]))
781 sum += values[i];
783 if (sum == 0.0)
784 {
785 WARNING ("Values sum for percentage sums up to zero");
786 return(STATE_WARNING);
787 }
789 percentage = 100.0 * values[0] / sum;
791 if (ret_ds_index != NULL)
792 *ret_ds_index = 0;
794 return ut_check_one_data_source (NULL, vl, th, &percentage, 0);
795 }
797 for (i = 0; i < ds->ds_num; i++)
798 {
799 int status;
801 status = ut_check_one_data_source (ds, vl, th, values, i);
802 if (ret < status)
803 {
804 ret = status;
805 ds_index = i;
806 }
807 } /* for (ds->ds_num) */
809 if (ret_ds_index != NULL)
810 *ret_ds_index = ds_index;
812 return (ret);
813 } /* }}} int ut_check_one_threshold */
815 /*
816 * int ut_check_threshold (PUBLIC)
817 *
818 * Gets a list of matching thresholds and searches for the worst status by one
819 * of the thresholds. Then reports that status using the ut_report_state
820 * function above.
821 * Returns zero on success and if no threshold has been configured. Returns
822 * less than zero on failure.
823 */
824 int ut_check_threshold (const data_set_t *ds, const value_list_t *vl)
825 { /* {{{ */
826 threshold_t *th;
827 gauge_t *values;
828 int status;
830 int worst_state = -1;
831 threshold_t *worst_th = NULL;
832 int worst_ds_index = -1;
834 if (threshold_tree == NULL)
835 return (0);
837 /* Is this lock really necessary? So far, thresholds are only inserted at
838 * startup. -octo */
839 pthread_mutex_lock (&threshold_lock);
840 th = threshold_search (vl);
841 pthread_mutex_unlock (&threshold_lock);
842 if (th == NULL)
843 return (0);
845 DEBUG ("ut_check_threshold: Found matching threshold(s)");
847 values = uc_get_rate (ds, vl);
848 if (values == NULL)
849 return (0);
851 while (th != NULL)
852 {
853 int ds_index = -1;
855 status = ut_check_one_threshold (ds, vl, th, values, &ds_index);
856 if (status < 0)
857 {
858 ERROR ("ut_check_threshold: ut_check_one_threshold failed.");
859 sfree (values);
860 return (-1);
861 }
863 if (worst_state < status)
864 {
865 worst_state = status;
866 worst_th = th;
867 worst_ds_index = ds_index;
868 }
870 th = th->next;
871 } /* while (th) */
873 status = ut_report_state (ds, vl, worst_th, values,
874 worst_ds_index, worst_state);
875 if (status != 0)
876 {
877 ERROR ("ut_check_threshold: ut_report_state failed.");
878 sfree (values);
879 return (-1);
880 }
882 sfree (values);
884 return (0);
885 } /* }}} int ut_check_threshold */
887 /*
888 * int ut_check_interesting (PUBLIC)
889 *
890 * Given an identification returns
891 * 0: No threshold is defined.
892 * 1: A threshold has been found. The flag `persist' is off.
893 * 2: A threshold has been found. The flag `persist' is on.
894 * (That is, it is expected that many notifications are sent until the
895 * problem disappears.)
896 */
897 int ut_check_interesting (const char *name)
898 { /* {{{ */
899 char *name_copy = NULL;
900 char *host = NULL;
901 char *plugin = NULL;
902 char *plugin_instance = NULL;
903 char *type = NULL;
904 char *type_instance = NULL;
905 int status;
906 data_set_t ds;
907 value_list_t vl;
908 threshold_t *th;
910 /* If there is no tree nothing is interesting. */
911 if (threshold_tree == NULL)
912 return (0);
914 name_copy = strdup (name);
915 if (name_copy == NULL)
916 {
917 ERROR ("ut_check_interesting: strdup failed.");
918 return (-1);
919 }
921 status = parse_identifier (name_copy, &host,
922 &plugin, &plugin_instance, &type, &type_instance);
923 if (status != 0)
924 {
925 ERROR ("ut_check_interesting: parse_identifier failed.");
926 sfree (name_copy);
927 return (-1);
928 }
930 memset (&ds, '\0', sizeof (ds));
931 memset (&vl, '\0', sizeof (vl));
933 sstrncpy (vl.host, host, sizeof (vl.host));
934 sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
935 if (plugin_instance != NULL)
936 sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
937 sstrncpy (ds.type, type, sizeof (ds.type));
938 sstrncpy (vl.type, type, sizeof (vl.type));
939 if (type_instance != NULL)
940 sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
942 sfree (name_copy);
943 host = plugin = plugin_instance = type = type_instance = NULL;
945 th = threshold_search (&vl);
946 if (th == NULL)
947 return (0);
948 if ((th->flags & UT_FLAG_PERSIST) == 0)
949 return (1);
950 return (2);
951 } /* }}} int ut_check_interesting */
953 /* vim: set sw=2 ts=8 sts=2 tw=78 et fdm=marker : */