X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Faggregation.c;h=db33c177c039fa1676d9fcdc690b47d428f9a82b;hb=9de042657fa536305c5d98ef114dd9750ed4d656;hp=49224345f1b65d661c813f163e1e723908f363f1;hpb=cc53b5c986c740c238eaa72b93fd4628d7aa723f;p=collectd.git diff --git a/src/aggregation.c b/src/aggregation.c index 49224345..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,6 +405,43 @@ 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; @@ -406,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; @@ -425,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) @@ -444,7 +505,17 @@ static int agg_config_aggregation (oconfig_item_t *ci) /* {{{ */ /* Sanity checking */ is_valid = 1; - if (strchr (agg->ident.type, '/') != NULL) /* {{{ */ + 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 " @@ -458,7 +529,9 @@ static int agg_config_aggregation (oconfig_item_t *ci) /* {{{ */ && !LU_IS_ALL (agg->ident.type_instance)) { ERROR ("aggregation plugin: An aggregation must contain at least one " - "\"/all/\" wildcard. Otherwise, nothing will be aggregated. " + "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, @@ -492,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 */ @@ -499,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, @@ -507,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); } @@ -523,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 */ @@ -537,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; @@ -548,6 +643,7 @@ static int agg_read (void) /* {{{ */ else success++; } + pthread_mutex_unlock (&agg_instance_list_lock); return ((success > 0) ? 0 : -1);