src/utils_threshold.c: Percentage support in thresholds
authorAndrés J. Díaz <ajdiaz@connectical.com>
Mon, 6 Jul 2009 15:53:03 +0000 (17:53 +0200)
committerFlorian Forster <octo@huhu.verplant.org>
Mon, 6 Jul 2009 15:53:03 +0000 (17:53 +0200)
Hi all!

I attach a patch to add percentage support in thresholds, like this example:

<Threshold>
  <Type df>
   WarningMax 90
   Percentage true
 </Type>
</Threshold>

The percentage option works like collectd-nagios, that is, calculate the
percentage of the value of the first DS over the total. For df plugin,
for example,
calculate the percentage of the "used" DS.

Bugs and suggestions are welcome :)

Enjoy!

Regards,
  Andres

src/utils_threshold.c

index 03a3f2d..083a018 100644 (file)
@@ -33,6 +33,7 @@
  * {{{ */
 #define UT_FLAG_INVERT  0x01
 #define UT_FLAG_PERSIST 0x02
+#define UT_FLAG_PERCENTAGE 0x04
 
 typedef struct threshold_s
 {
@@ -262,6 +263,24 @@ static int ut_config_type_persist (threshold_t *th, oconfig_item_t *ci)
   return (0);
 } /* int ut_config_type_persist */
 
+static int ut_config_type_percentage(threshold_t *th, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+  {
+    WARNING ("threshold values: The `Percentage' option needs exactly one "
+       "boolean argument.");
+    return (-1);
+  }
+
+  if (ci->values[0].value.boolean)
+    th->flags |= UT_FLAG_PERCENTAGE;
+  else
+    th->flags &= ~UT_FLAG_PERCENTAGE;
+
+  return (0);
+} /* int ut_config_type_percentage */
+
 static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
 {
   int i;
@@ -309,6 +328,8 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
       status = ut_config_type_invert (&th, option);
     else if (strcasecmp ("Persist", option->key) == 0)
       status = ut_config_type_persist (&th, option);
+    else if (strcasecmp ("Percentage", option->key) == 0)
+      status = ut_config_type_percentage (&th, option);
     else
     {
       WARNING ("threshold values: Option `%s' not allowed inside a `Type' "
@@ -467,7 +488,7 @@ int ut_config (const oconfig_item_t *ci)
   th.warning_max = NAN;
   th.failure_min = NAN;
   th.failure_max = NAN;
-    
+
   for (i = 0; i < ci->children_num; i++)
   {
     oconfig_item_t *option = ci->children + i;
@@ -644,29 +665,32 @@ static int ut_report_state (const data_set_t *ds,
       if (!isnan (min) && !isnan (max))
       {
        status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
-           "%f. That is within the %s region of %f and %f.",
+           "%f. That is within the %s region of %f and %f%s.",
            ds->ds[ds_index].name, values[ds_index],
            (state == STATE_ERROR) ? "failure" : "warning",
-           min, max);
+           min, max,
+           ((th->flags & UT_FLAG_PERCENTAGE) == UT_FLAG_PERCENTAGE) ? "%" : "" );
       }
       else
       {
        status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
-           "%f. That is %s the %s threshold of %f.",
+           "%f. That is %s the %s threshold of %f%s.",
            ds->ds[ds_index].name, values[ds_index],
            isnan (min) ? "below" : "above",
            (state == STATE_ERROR) ? "failure" : "warning",
-           isnan (min) ? max : min);
+           isnan (min) ? max : min,
+           ((th->flags & UT_FLAG_PERCENTAGE) == UT_FLAG_PERCENTAGE) ? "%" : "" );
       }
     }
     else /* is not inverted */
     {
       status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
-         "%f. That is %s the %s threshold of %f.",
+         "%f. That is %s the %s threshold of %f%s.",
          ds->ds[ds_index].name, values[ds_index],
          (values[ds_index] < min) ? "below" : "above",
          (state == STATE_ERROR) ? "failure" : "warning",
-         (values[ds_index] < min) ? min : max);
+         (values[ds_index] < min) ? min : max,
+         ((th->flags & UT_FLAG_PERCENTAGE) == UT_FLAG_PERCENTAGE) ? "%" : "" );
     }
     buf += status;
     bufsize -= status;
@@ -699,10 +723,13 @@ static int ut_check_one_data_source (const data_set_t *ds,
   int is_failure = 0;
 
   /* check if this threshold applies to this data source */
-  ds_name = ds->ds[ds_index].name;
-  if ((th->data_source[0] != 0)
-      && (strcmp (ds_name, th->data_source) != 0))
-    return (STATE_OKAY);
+  if (ds != NULL)
+  {
+    ds_name = ds->ds[ds_index].name;
+    if ((th->data_source[0] != 0)
+       && (strcmp (ds_name, th->data_source) != 0))
+      return (STATE_OKAY);
+  }
 
   if ((th->flags & UT_FLAG_INVERT) != 0)
   {
@@ -743,6 +770,30 @@ static int ut_check_one_threshold (const data_set_t *ds,
   int ds_index = -1;
   int i;
 
+  if ((th->flags & UT_FLAG_PERCENTAGE) == UT_FLAG_PERCENTAGE)
+  {
+
+    gauge_t sum=0.0;
+    gauge_t percentage;
+
+    for (i = 0; i < ds->ds_num; i++)
+      if (!isnan (values[i]))
+       sum += values[i];
+
+    if (sum == 0.0)
+    {
+      WARNING ("Values sum for percentage seems up to zero");
+      return(STATE_WARNING);
+    }
+
+    percentage = 100.0 * values[0] / sum;
+
+    if (ret_ds_index != NULL)
+       *ret_ds_index = 0;
+
+    return ut_check_one_data_source (NULL, vl, th, &percentage, 0);
+  }
+
   for (i = 0; i < ds->ds_num; i++)
   {
     int status;