X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Faggregation.c;h=db33c177c039fa1676d9fcdc690b47d428f9a82b;hb=9de042657fa536305c5d98ef114dd9750ed4d656;hp=42722021adca5f9fd0ce29c60f0d68040e41d38a;hpb=aefb1ea8faaf373428e1862b6de13b26a630da06;p=collectd.git
diff --git a/src/aggregation.c b/src/aggregation.c
index 42722021..db33c177 100644
--- a/src/aggregation.c
+++ b/src/aggregation.c
@@ -192,13 +192,21 @@ static int agg_instance_update (agg_instance_t *inst, /* {{{ */
gauge_t *rate;
if (ds->ds_num != 1)
- return (-1);
+ {
+ ERROR ("aggregation plugin: The \"%s\" type (data set) has more than one "
+ "data source. This is currently not supported by this plugin. "
+ "Sorry.", ds->type);
+ return (EINVAL);
+ }
rate = uc_get_rate (ds, vl);
if (rate == NULL)
{
- ERROR ("aggregation plugin: uc_get_rate() failed.");
- return (-1);
+ char ident[6 * DATA_MAX_NAME_LEN];
+ FORMAT_VL (ident, sizeof (ident), vl);
+ ERROR ("aggregation plugin: Unable to read the current rate of \"%s\".",
+ ident);
+ return (ENOENT);
}
if (isnan (rate[0]))
@@ -241,6 +249,12 @@ static int agg_instance_read_func (agg_instance_t *inst, /* {{{ */
status = rate_to_value (&v, rate, state, inst->ds_type, t);
if (status != 0)
{
+ /* If this is the first iteration and rate_to_value() was asked to return a
+ * COUNTER or a DERIVE, it will return EAGAIN. Catch this and handle
+ * gracefully. */
+ if (status == EAGAIN)
+ return (0);
+
WARNING ("aggregation plugin: rate_to_value failed with status %i.",
status);
return (-1);
@@ -376,11 +390,11 @@ static void agg_lookup_free_obj_callback (void *user_obj) /* {{{ */
/*
*
*
- * Host "/any/"
* Plugin "cpu"
- * PluginInstance "/all/"
* Type "cpu"
- * TypeInstance "/any/"
+ *
+ * GroupBy Host
+ * GroupBy TypeInstance
*
* CalculateNum true
* CalculateSum true
@@ -391,9 +405,47 @@ static void agg_lookup_free_obj_callback (void *user_obj) /* {{{ */
*
*
*/
+static int agg_config_handle_group_by (oconfig_item_t const *ci, /* {{{ */
+ aggregation_t *agg)
+{
+ int i;
+
+ for (i = 0; i < ci->values_num; i++)
+ {
+ char const *value;
+
+ if (ci->values[i].type != OCONFIG_TYPE_STRING)
+ {
+ ERROR ("aggregation plugin: Argument %i of the \"GroupBy\" option "
+ "is not a string.", i + 1);
+ continue;
+ }
+
+ value = ci->values[i].value.string;
+
+ if (strcasecmp ("Host", value) == 0)
+ sstrncpy (agg->ident.host, LU_ANY, sizeof (agg->ident.host));
+ else if (strcasecmp ("Plugin", value) == 0)
+ sstrncpy (agg->ident.plugin, LU_ANY, sizeof (agg->ident.plugin));
+ else if (strcasecmp ("PluginInstance", value) == 0)
+ sstrncpy (agg->ident.plugin_instance, LU_ANY,
+ sizeof (agg->ident.plugin_instance));
+ else if (strcasecmp ("TypeInstance", value) == 0)
+ sstrncpy (agg->ident.type_instance, LU_ANY, sizeof (agg->ident.type_instance));
+ else if (strcasecmp ("Type", value) == 0)
+ ERROR ("aggregation plugin: Grouping by type is not supported.");
+ else
+ WARNING ("aggregation plugin: The \"%s\" argument to the \"GroupBy\" "
+ "option is invalid and will be ignored.", value);
+ } /* for (ci->values) */
+
+ return (0);
+} /* }}} int agg_config_handle_group_by */
+
static int agg_config_aggregation (oconfig_item_t *ci) /* {{{ */
{
aggregation_t *agg;
+ _Bool is_valid;
int status;
int i;
@@ -405,6 +457,14 @@ static int agg_config_aggregation (oconfig_item_t *ci) /* {{{ */
}
memset (agg, 0, sizeof (*agg));
+ sstrncpy (agg->ident.host, LU_ALL, sizeof (agg->ident.host));
+ sstrncpy (agg->ident.plugin, LU_ALL, sizeof (agg->ident.plugin));
+ sstrncpy (agg->ident.plugin_instance, LU_ALL,
+ sizeof (agg->ident.plugin_instance));
+ sstrncpy (agg->ident.type, LU_ALL, sizeof (agg->ident.type));
+ sstrncpy (agg->ident.type_instance, LU_ALL,
+ sizeof (agg->ident.type_instance));
+
for (i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
@@ -424,6 +484,8 @@ static int agg_config_aggregation (oconfig_item_t *ci) /* {{{ */
else if (strcasecmp ("TypeInstance", child->key) == 0)
cf_util_get_string_buffer (child, agg->ident.type_instance,
sizeof (agg->ident.type_instance));
+ else if (strcasecmp ("GroupBy", child->key) == 0)
+ agg_config_handle_group_by (child, agg);
else if (strcasecmp ("CalculateNum", child->key) == 0)
cf_util_get_boolean (child, &agg->calc_num);
else if (strcasecmp ("CalculateSum", child->key) == 0)
@@ -441,10 +503,59 @@ static int agg_config_aggregation (oconfig_item_t *ci) /* {{{ */
" blocks and will be ignored.", child->key);
}
- /* TODO(octo): Check identifier:
- * - At least one wildcard.
- * - Type is set.
- */
+ /* Sanity checking */
+ is_valid = 1;
+ if (LU_IS_ALL (agg->ident.type)) /* {{{ */
+ {
+ ERROR ("aggregation plugin: It appears you did not specify the required "
+ "\"Type\" option in this aggregation. "
+ "(Host \"%s\", Plugin \"%s\", PluginInstance \"%s\", "
+ "Type \"%s\", TypeInstance \"%s\")",
+ agg->ident.host, agg->ident.plugin, agg->ident.plugin_instance,
+ agg->ident.type, agg->ident.type_instance);
+ is_valid = 0;
+ }
+ else if (strchr (agg->ident.type, '/') != NULL)
+ {
+ ERROR ("aggregation plugin: The \"Type\" may not contain the '/' "
+ "character. Especially, it may not be a wildcard. The current "
+ "value is \"%s\".", agg->ident.type);
+ is_valid = 0;
+ } /* }}} */
+
+ if (!LU_IS_ALL (agg->ident.host) /* {{{ */
+ && !LU_IS_ALL (agg->ident.plugin)
+ && !LU_IS_ALL (agg->ident.plugin_instance)
+ && !LU_IS_ALL (agg->ident.type_instance))
+ {
+ ERROR ("aggregation plugin: An aggregation must contain at least one "
+ "wildcard. This is achieved by leaving at least one of the \"Host\", "
+ "\"Plugin\", \"PluginInstance\" and \"TypeInstance\" options blank "
+ "and not grouping by that field. "
+ "(Host \"%s\", Plugin \"%s\", PluginInstance \"%s\", "
+ "Type \"%s\", TypeInstance \"%s\")",
+ agg->ident.host, agg->ident.plugin, agg->ident.plugin_instance,
+ agg->ident.type, agg->ident.type_instance);
+ is_valid = 0;
+ } /* }}} */
+
+ if (!agg->calc_num && !agg->calc_sum && !agg->calc_average /* {{{ */
+ && !agg->calc_min && !agg->calc_max && !agg->calc_stddev)
+ {
+ ERROR ("aggregation plugin: No aggregation function has been specified. "
+ "Without this, I don't know what I should be calculating. "
+ "(Host \"%s\", Plugin \"%s\", PluginInstance \"%s\", "
+ "Type \"%s\", TypeInstance \"%s\")",
+ agg->ident.host, agg->ident.plugin, agg->ident.plugin_instance,
+ agg->ident.type, agg->ident.type_instance);
+ is_valid = 0;
+ } /* }}} */
+
+ if (!is_valid) /* {{{ */
+ {
+ sfree (agg);
+ return (-1);
+ } /* }}} */
status = lookup_add (lookup, &agg->ident, agg);
if (status != 0)
@@ -454,6 +565,11 @@ static int agg_config_aggregation (oconfig_item_t *ci) /* {{{ */
return (-1);
}
+ DEBUG ("aggregation plugin: Successfully added aggregation: "
+ "(Host \"%s\", Plugin \"%s\", PluginInstance \"%s\", "
+ "Type \"%s\", TypeInstance \"%s\")",
+ agg->ident.host, agg->ident.plugin, agg->ident.plugin_instance,
+ agg->ident.type, agg->ident.type_instance);
return (0);
} /* }}} int agg_config_aggregation */
@@ -461,6 +577,8 @@ static int agg_config (oconfig_item_t *ci) /* {{{ */
{
int i;
+ pthread_mutex_lock (&agg_instance_list_lock);
+
if (lookup == NULL)
{
lookup = lookup_create (agg_lookup_class_callback,
@@ -469,6 +587,7 @@ static int agg_config (oconfig_item_t *ci) /* {{{ */
agg_lookup_free_obj_callback);
if (lookup == NULL)
{
+ pthread_mutex_unlock (&agg_instance_list_lock);
ERROR ("aggregation plugin: lookup_create failed.");
return (-1);
}
@@ -485,6 +604,8 @@ static int agg_config (oconfig_item_t *ci) /* {{{ */
" blocks and will be ignored.", child->key);
}
+ pthread_mutex_unlock (&agg_instance_list_lock);
+
return (0);
} /* }}} int agg_config */
@@ -499,6 +620,18 @@ static int agg_read (void) /* {{{ */
pthread_mutex_lock (&agg_instance_list_lock);
+ /* agg_instance_list_head only holds data, after the "write" callback has
+ * been called with a matching value list at least once. So on startup,
+ * there's a race between the aggregations read() and write() callback. If
+ * the read() callback is called first, agg_instance_list_head is NULL and
+ * "success" may be zero. This is expected and should not result in an error.
+ * Therefore we need to handle this case separately. */
+ if (agg_instance_list_head == NULL)
+ {
+ pthread_mutex_unlock (&agg_instance_list_lock);
+ return (0);
+ }
+
for (this = agg_instance_list_head; this != NULL; this = this->next)
{
int status;
@@ -510,6 +643,7 @@ static int agg_read (void) /* {{{ */
else
success++;
}
+
pthread_mutex_unlock (&agg_instance_list_lock);
return ((success > 0) ? 0 : -1);