src/utils_threshold.c: Change the percentage code so it works with the DataSource...
[collectd.git] / src / utils_threshold.c
index 380601a..fa8c8f9 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
 {
@@ -114,7 +115,7 @@ static int ut_threshold_add (const threshold_t *th)
     return (-1);
   }
   memcpy (th_copy, th, sizeof (threshold_t));
-  th_copy = NULL;
+  th_ptr = NULL;
 
   DEBUG ("ut_threshold_add: Adding entry `%s'", name);
 
@@ -184,9 +185,8 @@ static int ut_config_type_instance (threshold_t *th, oconfig_item_t *ci)
     return (-1);
   }
 
-  strncpy (th->type_instance, ci->values[0].value.string,
+  sstrncpy (th->type_instance, ci->values[0].value.string,
       sizeof (th->type_instance));
-  th->type_instance[sizeof (th->type_instance) - 1] = '\0';
 
   return (0);
 } /* int ut_config_type_instance */
@@ -263,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;
@@ -284,8 +302,7 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
   }
 
   memcpy (&th, th_orig, sizeof (th));
-  strncpy (th.type, ci->values[0].value.string, sizeof (th.type));
-  th.type[sizeof (th.type) - 1] = '\0';
+  sstrncpy (th.type, ci->values[0].value.string, sizeof (th.type));
 
   th.warning_min = NAN;
   th.warning_max = NAN;
@@ -299,7 +316,7 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
 
     if (strcasecmp ("Instance", option->key) == 0)
       status = ut_config_type_instance (&th, option);
-    if (strcasecmp ("DataSource", option->key) == 0)
+    else if (strcasecmp ("DataSource", option->key) == 0)
       status = ut_config_type_datasource (&th, option);
     else if ((strcasecmp ("WarningMax", option->key) == 0)
        || (strcasecmp ("FailureMax", option->key) == 0))
@@ -311,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' "
@@ -340,9 +359,8 @@ static int ut_config_plugin_instance (threshold_t *th, oconfig_item_t *ci)
     return (-1);
   }
 
-  strncpy (th->plugin_instance, ci->values[0].value.string,
+  sstrncpy (th->plugin_instance, ci->values[0].value.string,
       sizeof (th->plugin_instance));
-  th->plugin_instance[sizeof (th->plugin_instance) - 1] = '\0';
 
   return (0);
 } /* int ut_config_plugin_instance */
@@ -369,8 +387,7 @@ static int ut_config_plugin (const threshold_t *th_orig, oconfig_item_t *ci)
   }
 
   memcpy (&th, th_orig, sizeof (th));
-  strncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
-  th.plugin[sizeof (th.plugin) - 1] = '\0';
+  sstrncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
 
   for (i = 0; i < ci->children_num; i++)
   {
@@ -417,8 +434,7 @@ static int ut_config_host (const threshold_t *th_orig, oconfig_item_t *ci)
   }
 
   memcpy (&th, th_orig, sizeof (th));
-  strncpy (th.host, ci->values[0].value.string, sizeof (th.host));
-  th.host[sizeof (th.host) - 1] = '\0';
+  sstrncpy (th.host, ci->values[0].value.string, sizeof (th.host));
 
   for (i = 0; i < ci->children_num; i++)
   {
@@ -472,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;
@@ -501,179 +517,138 @@ int ut_config (const oconfig_item_t *ci)
  */
 /* }}} */
 
-static threshold_t *threshold_search (const data_set_t *ds,
-    const value_list_t *vl)
+static threshold_t *threshold_search (const value_list_t *vl)
 {
   threshold_t *th;
 
   if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, vl->plugin, NULL,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, vl->plugin, NULL,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, "", NULL,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, "", NULL,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get ("", vl->plugin, NULL,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get ("", vl->plugin, NULL,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get ("", "", NULL,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get ("", "", NULL,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
 
   return (NULL);
 } /* threshold_t *threshold_search */
 
-/* TODO: Split this into two functions, one that iterates over all threshold
- * definitions and one that checks if (a) the threshold matches (the data
- * source matches) and (b) if the threshold is satisfied or not. Break at the
- * first matching threshold. */
-int ut_check_threshold (const data_set_t *ds, const value_list_t *vl)
-{
+/*
+ * int ut_report_state
+ *
+ * Checks if the `state' differs from the old state and creates a notification
+ * if appropriate.
+ * Does not fail.
+ */
+static int ut_report_state (const data_set_t *ds,
+    const value_list_t *vl,
+    const threshold_t *th,
+    const gauge_t *values,
+    int ds_index,
+    int state)
+{ /* {{{ */
+  int state_old;
   notification_t n;
-  threshold_t *th;
-  gauge_t *values;
-  int i;
-
-  int state_orig;
-  int state_new = STATE_OKAY;
-  int ds_index = 0;
 
   char *buf;
   size_t bufsize;
-  int status;
-
-  if (threshold_tree == NULL)
-    return (0);
-
-  /* Is this lock really necessary? So far, thresholds are only inserted at
-   * startup. -octo */
-  pthread_mutex_lock (&threshold_lock);
-  th = threshold_search (ds, vl);
-  pthread_mutex_unlock (&threshold_lock);
-  if (th == NULL)
-    return (0);
 
-  DEBUG ("ut_check_threshold: Found matching threshold");
-
-  values = uc_get_rate (ds, vl);
-  if (values == NULL)
-    return (0);
+  int status;
 
-  state_orig = uc_get_state (ds, vl);
+  state_old = uc_get_state (ds, vl);
 
-  for (i = 0; i < ds->ds_num; i++)
+  /* If the state didn't change, only report if `persistent' is specified and
+   * the state is not `okay'. */
+  if (state == state_old)
   {
-    int is_inverted = 0;
-    int is_warning = 0;
-    int is_failure = 0;
-
-    if ((th->flags & UT_FLAG_INVERT) != 0)
-    {
-      is_inverted = 1;
-      is_warning--;
-      is_failure--;
-    }
-    if ((!isnan (th->failure_min) && (th->failure_min > values[i]))
-       || (!isnan (th->failure_max) && (th->failure_max < values[i])))
-      is_failure++;
-    if ((!isnan (th->warning_min) && (th->warning_min > values[i]))
-       || (!isnan (th->warning_max) && (th->warning_max < values[i])))
-      is_warning++;
-
-    if ((is_failure != 0) && (state_new != STATE_ERROR))
-    {
-      state_new = STATE_ERROR;
-      ds_index = i;
-    }
-    else if ((is_warning != 0)
-       && (state_new != STATE_ERROR)
-       && (state_new != STATE_WARNING))
-    {
-      state_new = STATE_WARNING;
-      ds_index = i;
-    }
+    if ((th->flags & UT_FLAG_PERSIST) == 0)
+      return (0);
+    else if (state == STATE_OKAY)
+      return (0);
   }
 
-  if (state_new != state_orig)
-    uc_set_state (ds, vl, state_new);
-
-  /* Return here if we're not going to send a notification */
-  if ((state_new == state_orig)
-      && ((state_new == STATE_OKAY)
-       || ((th->flags & UT_FLAG_PERSIST) == 0)))
-  {
-    sfree (values);
-    return (0);
-  }
+  if (state != state_old)
+    uc_set_state (ds, vl, state);
 
   NOTIFICATION_INIT_VL (&n, vl, ds);
-  {
-    /* Copy the associative members */
-    if (state_new == STATE_OKAY)
-      n.severity = NOTIF_OKAY;
-    else if (state_new == STATE_WARNING)
-      n.severity = NOTIF_WARNING;
-    else
-      n.severity = NOTIF_FAILURE;
 
-    n.time = vl->time;
+  buf = n.message;
+  bufsize = sizeof (n.message);
 
-    buf = n.message;
-    bufsize = sizeof (n.message);
+  if (state == STATE_OKAY)
+    n.severity = NOTIF_OKAY;
+  else if (state == STATE_WARNING)
+    n.severity = NOTIF_WARNING;
+  else
+    n.severity = NOTIF_FAILURE;
+
+  n.time = vl->time;
+
+  status = ssnprintf (buf, bufsize, "Host %s, plugin %s",
+      vl->host, vl->plugin);
+  buf += status;
+  bufsize -= status;
 
-    status = snprintf (buf, bufsize, "Host %s, plugin %s",
-       vl->host, vl->plugin);
+  if (vl->plugin_instance[0] != '\0')
+  {
+    status = ssnprintf (buf, bufsize, " (instance %s)",
+       vl->plugin_instance);
     buf += status;
     bufsize -= status;
+  }
 
-    if (vl->plugin_instance[0] != '\0')
-    {
-      status = snprintf (buf, bufsize, " (instance %s)",
-         vl->plugin_instance);
-      buf += status;
-      bufsize -= status;
-    }
+  status = ssnprintf (buf, bufsize, " type %s", vl->type);
+  buf += status;
+  bufsize -= status;
 
-    status = snprintf (buf, bufsize, " type %s", ds->type);
+  if (vl->type_instance[0] != '\0')
+  {
+    status = ssnprintf (buf, bufsize, " (instance %s)",
+       vl->type_instance);
     buf += status;
     bufsize -= status;
-
-    if (vl->type_instance[0] != '\0')
-    {
-      status = snprintf (buf, bufsize, " (instance %s)",
-         vl->type_instance);
-      buf += status;
-      bufsize -= status;
-    }
   }
 
-  /* Send a okay notification */
-  if (state_new == STATE_OKAY)
+  plugin_notification_meta_add_string (&n, "DataSource",
+      ds->ds[ds_index].name);
+  plugin_notification_meta_add_double (&n, "CurrentValue", values[ds_index]);
+  plugin_notification_meta_add_double (&n, "WarningMin", th->warning_min);
+  plugin_notification_meta_add_double (&n, "WarningMax", th->warning_max);
+  plugin_notification_meta_add_double (&n, "FailureMin", th->failure_min);
+  plugin_notification_meta_add_double (&n, "FailureMax", th->failure_max);
+
+  /* Send an okay notification */
+  if (state == STATE_OKAY)
   {
-    status = snprintf (buf, bufsize, ": All data sources are within range again.");
+    status = ssnprintf (buf, bufsize, ": All data sources are within range again.");
     buf += status;
     bufsize -= status;
   }
@@ -682,37 +657,40 @@ int ut_check_threshold (const data_set_t *ds, const value_list_t *vl)
     double min;
     double max;
 
-    min = (state_new == STATE_ERROR) ? th->failure_min : th->warning_min;
-    max = (state_new == STATE_ERROR) ? th->failure_max : th->warning_max;
+    min = (state == STATE_ERROR) ? th->failure_min : th->warning_min;
+    max = (state == STATE_ERROR) ? th->failure_max : th->warning_max;
 
     if (th->flags & UT_FLAG_INVERT)
     {
       if (!isnan (min) && !isnan (max))
       {
-       status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
-           "%f. That is within the %s region of %f and %f.",
-           ds->ds[ds_index].name, values[ds_index],
-           (state_new == STATE_ERROR) ? "failure" : "warning",
-           min, min);
+        status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
+            "%f. That is within the %s region of %f%s and %f%s.",
+            ds->ds[ds_index].name, values[ds_index],
+            (state == STATE_ERROR) ? "failure" : "warning",
+            min, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "",
+            max, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
       }
       else
       {
-       status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
-           "%f. That is %s the %s threshold of %f.",
+       status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
+           "%f. That is %s the %s threshold of %f%s.",
            ds->ds[ds_index].name, values[ds_index],
            isnan (min) ? "below" : "above",
-           (state_new == STATE_ERROR) ? "failure" : "warning",
-           isnan (min) ? max : min);
+           (state == STATE_ERROR) ? "failure" : "warning",
+           isnan (min) ? max : min,
+           ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
       }
     }
     else /* is not inverted */
     {
-      status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
-         "%f. That is %s the %s threshold of %f.",
+      status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
+         "%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_new == STATE_ERROR) ? "failure" : "warning",
-         (values[ds_index] < min) ? min : max);
+         (state == STATE_ERROR) ? "failure" : "warning",
+         (values[ds_index] < min) ? min : max,
+         ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
     }
     buf += status;
     bufsize -= status;
@@ -720,13 +698,217 @@ int ut_check_threshold (const data_set_t *ds, const value_list_t *vl)
 
   plugin_dispatch_notification (&n);
 
+  plugin_notification_meta_free (n.meta);
+  return (0);
+} /* }}} int ut_report_state */
+
+/*
+ * int ut_check_one_data_source
+ *
+ * Checks one data source against the given threshold configuration. If the
+ * `DataSource' option is set in the threshold, and the name does NOT match,
+ * `okay' is returned. If the threshold does match, its failure and warning
+ * min and max values are checked and `failure' or `warning' is returned if
+ * appropriate.
+ * Does not fail.
+ */
+static int ut_check_one_data_source (const data_set_t *ds,
+    const value_list_t __attribute__((unused)) *vl,
+    const threshold_t *th,
+    const gauge_t *values,
+    int ds_index)
+{ /* {{{ */
+  const char *ds_name;
+  int is_warning = 0;
+  int is_failure = 0;
+
+  /* check if this threshold applies to this data source */
+  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)
+  {
+    is_warning--;
+    is_failure--;
+  }
+
+  if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
+      || (!isnan (th->failure_max) && (th->failure_max < values[ds_index])))
+    is_failure++;
+  if (is_failure != 0)
+    return (STATE_ERROR);
+
+  if ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
+      || (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
+    is_warning++;
+  if (is_warning != 0)
+    return (STATE_WARNING);
+
+  return (STATE_OKAY);
+} /* }}} int ut_check_one_data_source */
+
+/*
+ * int ut_check_one_threshold
+ *
+ * Checks all data sources of a value list against the given threshold, using
+ * the ut_check_one_data_source function above. Returns the worst status,
+ * which is `okay' if nothing has failed.
+ * Returns less than zero if the data set doesn't have any data sources.
+ */
+static int ut_check_one_threshold (const data_set_t *ds,
+    const value_list_t *vl,
+    const threshold_t *th,
+    const gauge_t *values,
+    int *ret_ds_index)
+{ /* {{{ */
+  int ret = -1;
+  int ds_index = -1;
+  int i;
+  gauge_t values_copy[ds->ds_num];
+
+  memcpy (values_copy, values, sizeof (values_copy));
+
+  if ((th->flags & UT_FLAG_PERCENTAGE) != 0)
+  {
+    int num = 0;
+    gauge_t sum=0.0;
+
+    if (ds->ds_num == 1)
+    {
+      WARNING ("ut_check_one_threshold: The %s type has only one data "
+          "source, but you have configured to check this as a percentage. "
+          "That doesn't make much sense, because the percentage will always "
+          "be 100%%!", ds->type);
+    }
+
+    /* Prepare `sum' and `num'. */
+    for (i = 0; i < ds->ds_num; i++)
+      if (!isnan (values[i]))
+      {
+        num++;
+       sum += values[i];
+      }
+
+    if ((num == 0) /* All data sources are undefined. */
+        || (sum == 0.0)) /* Sum is zero, cannot calculate percentage. */
+    {
+      for (i = 0; i < ds->ds_num; i++)
+        values_copy[i] = NAN;
+    }
+    else /* We can actually calculate the percentage. */
+    {
+      for (i = 0; i < ds->ds_num; i++)
+        values_copy[i] = 100.0 * values[i] / sum;
+    }
+  } /* if (UT_FLAG_PERCENTAGE) */
+
+  for (i = 0; i < ds->ds_num; i++)
+  {
+    int status;
+
+    status = ut_check_one_data_source (ds, vl, th, values_copy, i);
+    if (ret < status)
+    {
+      ret = status;
+      ds_index = i;
+    }
+  } /* for (ds->ds_num) */
+
+  if (ret_ds_index != NULL)
+    *ret_ds_index = ds_index;
+
+  return (ret);
+} /* }}} int ut_check_one_threshold */
+
+/*
+ * int ut_check_threshold (PUBLIC)
+ *
+ * Gets a list of matching thresholds and searches for the worst status by one
+ * of the thresholds. Then reports that status using the ut_report_state
+ * function above. 
+ * Returns zero on success and if no threshold has been configured. Returns
+ * less than zero on failure.
+ */
+int ut_check_threshold (const data_set_t *ds, const value_list_t *vl)
+{ /* {{{ */
+  threshold_t *th;
+  gauge_t *values;
+  int status;
+
+  int worst_state = -1;
+  threshold_t *worst_th = NULL;
+  int worst_ds_index = -1;
+
+  if (threshold_tree == NULL)
+    return (0);
+
+  /* Is this lock really necessary? So far, thresholds are only inserted at
+   * startup. -octo */
+  pthread_mutex_lock (&threshold_lock);
+  th = threshold_search (vl);
+  pthread_mutex_unlock (&threshold_lock);
+  if (th == NULL)
+    return (0);
+
+  DEBUG ("ut_check_threshold: Found matching threshold(s)");
+
+  values = uc_get_rate (ds, vl);
+  if (values == NULL)
+    return (0);
+
+  while (th != NULL)
+  {
+    int ds_index = -1;
+
+    status = ut_check_one_threshold (ds, vl, th, values, &ds_index);
+    if (status < 0)
+    {
+      ERROR ("ut_check_threshold: ut_check_one_threshold failed.");
+      sfree (values);
+      return (-1);
+    }
+
+    if (worst_state < status)
+    {
+      worst_state = status;
+      worst_th = th;
+      worst_ds_index = ds_index;
+    }
+
+    th = th->next;
+  } /* while (th) */
+
+  status = ut_report_state (ds, vl, worst_th, values,
+      worst_ds_index, worst_state);
+  if (status != 0)
+  {
+    ERROR ("ut_check_threshold: ut_report_state failed.");
+    sfree (values);
+    return (-1);
+  }
+
   sfree (values);
 
   return (0);
-} /* int ut_check_threshold */
+} /* }}} int ut_check_threshold */
 
+/*
+ * int ut_check_interesting (PUBLIC)
+ *
+ * Given an identification returns
+ * 0: No threshold is defined.
+ * 1: A threshold has been found. The flag `persist' is off.
+ * 2: A threshold has been found. The flag `persist' is on.
+ *    (That is, it is expected that many notifications are sent until the
+ *    problem disappears.)
+ */
 int ut_check_interesting (const char *name)
-{
+{ /* {{{ */
   char *name_copy = NULL;
   char *host = NULL;
   char *plugin = NULL;
@@ -754,38 +936,31 @@ int ut_check_interesting (const char *name)
   if (status != 0)
   {
     ERROR ("ut_check_interesting: parse_identifier failed.");
+    sfree (name_copy);
     return (-1);
   }
 
   memset (&ds, '\0', sizeof (ds));
   memset (&vl, '\0', sizeof (vl));
 
-  strncpy (vl.host, host, sizeof (vl.host));
-  vl.host[sizeof (vl.host) - 1] = '\0';
-  strncpy (vl.plugin, plugin, sizeof (vl.plugin));
-  vl.plugin[sizeof (vl.plugin) - 1] = '\0';
+  sstrncpy (vl.host, host, sizeof (vl.host));
+  sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
   if (plugin_instance != NULL)
-  {
-    strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
-    vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
-  }
-  strncpy (ds.type, type, sizeof (ds.type));
-  ds.type[sizeof (ds.type) - 1] = '\0';
+    sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+  sstrncpy (ds.type, type, sizeof (ds.type));
+  sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_instance != NULL)
-  {
-    strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
-    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-  }
+    sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
   sfree (name_copy);
   host = plugin = plugin_instance = type = type_instance = NULL;
 
-  th = threshold_search (&ds, &vl);
+  th = threshold_search (&vl);
   if (th == NULL)
     return (0);
   if ((th->flags & UT_FLAG_PERSIST) == 0)
     return (1);
   return (2);
-} /* int ut_check_interesting */
+} /* }}} int ut_check_interesting */
 
-/* vim: set sw=2 ts=8 sts=2 tw=78 fdm=marker : */
+/* vim: set sw=2 ts=8 sts=2 tw=78 et fdm=marker : */