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);