static int statsd_read(void) /* {{{ */ { c_avl_iterator_t *iter; char *name; statsd_metric_t *metric; char **to_be_deleted = NULL; size_t to_be_deleted_num = 0; pthread_mutex_lock(&metrics_lock); if (metrics_tree == NULL) { pthread_mutex_unlock(&metrics_lock); return 0; } iter = c_avl_get_iterator(metrics_tree); while (c_avl_iterator_next(iter, (void *)&name, (void *)&metric) == 0) { if ((metric->updates_num == 0) && ((conf_delete_counters && (metric->type == STATSD_COUNTER)) || (conf_delete_timers && (metric->type == STATSD_TIMER)) || (conf_delete_gauges && (metric->type == STATSD_GAUGE)) || (conf_delete_sets && (metric->type == STATSD_SET)))) { DEBUG("statsd plugin: Deleting metric \"%s\".", name); strarray_add(&to_be_deleted, &to_be_deleted_num, name); continue; } /* Names have a prefix, e.g. "c:", which determines the (statsd) type. * Remove this here. */ statsd_metric_submit_unsafe(name + 2, metric); /* Reset the metric. */ metric->updates_num = 0; if (metric->type == STATSD_SET) statsd_metric_clear_set_unsafe(metric); } c_avl_iterator_destroy(iter); for (size_t i = 0; i < to_be_deleted_num; i++) { int status; status = c_avl_remove(metrics_tree, to_be_deleted[i], (void *)&name, (void *)&metric); if (status != 0) { ERROR("stats plugin: c_avl_remove (\"%s\") failed with status %i.", to_be_deleted[i], status); continue; } sfree(name); statsd_metric_free(metric); } pthread_mutex_unlock(&metrics_lock); strarray_free(to_be_deleted, to_be_deleted_num); return 0; } /* }}} int statsd_read */
void uc_iterator_destroy (uc_iter_t *iter) { if (iter == NULL) return; c_avl_iterator_destroy (iter->iter); pthread_mutex_unlock (&cache_lock); free (iter); } /* void uc_iterator_destroy */
void instances_of_types_tree_print(void) { c_avl_iterator_t *iter; char *k; instances_list_t *v; int n=0; INFO(OUTPUT_PREFIX_STRING "INSTANCES"); pthread_mutex_lock (&instances_of_types_mutex); iter = c_avl_get_iterator (instances_of_types_tree); while (c_avl_iterator_next (iter, (void *) &k, (void *) &v) == 0) { int i; INFO(OUTPUT_PREFIX_STRING "INSTANCES of %s", k); for(i=0; v->instance[i]; i++) { INFO(OUTPUT_PREFIX_STRING "INSTANCES : %s", v->instance[i]); } n++; } /* while (c_avl_iterator_next) */ c_avl_iterator_destroy (iter); pthread_mutex_unlock (&instances_of_types_mutex); INFO(OUTPUT_PREFIX_STRING "INSTANCES nb=%d",n); }
static int basic_aggregator_read_all_aggregators (void) { c_avl_iterator_t *iter; char *k; aggregator_definition_t *agg; int status; struct stat buf; short update_config = 1; /* Check if we should reread the configuration file */ errno=0; if(-1 == stat(configuration_filename, &buf)) { ERROR (OUTPUT_PREFIX_STRING "Cannot stat configuration file '%s' (errno=%d)", configuration_filename,errno); return(-1); } if(buf.st_mtime > configuration_filename_date) { configuration_filename_date = buf.st_mtime; } else { update_config = 0; } /* Reread the configuration file if needed */ if(1 == update_config) { status = basic_aggregator_read_config_file_and_update_aggregator_definitions(configuration_filename); if(status != 0) return -1; } /* Aggregate for all the aggregators */ iter = c_avl_get_iterator (aggregator); while (c_avl_iterator_next (iter, (void *) &k, (void *) &agg) == 0) { basic_aggregator_read(agg); } /* while (c_avl_iterator_next) */ c_avl_iterator_destroy (iter); return(0); }
static int basic_aggregator_submit_resultvalue ( const aggregator_definition_t *agg, c_avl_tree_t *ds_data ) { value_t *values; value_list_t vl = VALUE_LIST_INIT; const data_set_t *ds; char *identifier; char *hostname; char *plugin; char *plugin_instance; char *type; char *type_instance; int status; int i; int submit_ok; aggregator_operation_e operation; c_avl_iterator_t *iter; char *key_instance; c_avl_tree_t *ds_tree; identifier = sstrdup (agg->resultvalue); status = parse_identifier (identifier, &hostname, &plugin, &plugin_instance, &type, &type_instance); if (status != 0) { ERROR (OUTPUT_PREFIX_STRING "Cannot parse value `%s'.", agg->resultvalue); sfree (identifier); return (-1); } if((NULL == type) || (type[0] == '\0')) { ERROR (OUTPUT_PREFIX_STRING "parse_identifier() : type == NULL or is empty (identifier='%s')", identifier); sfree (identifier); return (-1); } ds = plugin_get_ds (type); if (ds == NULL) { ERROR (OUTPUT_PREFIX_STRING "plugin_get_ds (%s) == NULL", type); sfree (identifier); return (-1); } if(NULL == (values = malloc(ds->ds_num* sizeof(*values)))) { ERROR (OUTPUT_PREFIX_STRING "Could not allocate memory"); sfree (identifier); return (-1); } iter = c_avl_get_iterator (ds_data); while (c_avl_iterator_next (iter, (void *) &key_instance, (void *) &ds_tree) == 0) { for (operation=0; operation < nb_enum_in_aggregator_operation_e; operation++) { if(0 == agg->operation[operation]) continue; memset(values, '\0', ds->ds_num*sizeof(*values)); submit_ok = 1; for(i=0; i<ds->ds_num; i++) { value_and_nb_t *v; if(0 == c_avl_get(ds_tree, ds->ds[i].name,(void*)&v)) { switch(operation) { case operation_SUM : values[i].gauge = v->val; break; case operation_AVG : values[i].gauge = v->val/v->nb; break; default : assert (11 == 12); /* this should never happen */ } } else { submit_ok = 0; } } if(submit_ok) { int l = 0; int pos = 0; vl.values = values; vl.values_len = ds->ds_num; if(plugin_instance) { l = strlen(plugin_instance); } if(l) { sstrncpy (vl.plugin_instance, plugin_instance, l+1); pos += l; sstrncpy (vl.plugin_instance + pos, "_", DATA_MAX_NAME_LEN - pos); pos += 1; } switch(operation) { case operation_SUM : sstrncpy (vl.plugin_instance + pos, "sum", DATA_MAX_NAME_LEN - pos); break; case operation_AVG : sstrncpy (vl.plugin_instance + pos, "avg", DATA_MAX_NAME_LEN - pos); break; default : assert (11 == 12); /* this should never happen */ } sstrncpy (vl.host, hostname, sizeof (vl.host)); sstrncpy (vl.plugin, plugin, sizeof (vl.plugin)); sstrncpy (vl.type, type, sizeof (vl.type)); if(key_instance[0]) sstrncpy (vl.type_instance, key_instance, sizeof (vl.type_instance)); #ifdef DEBUG_THIS INFO(OUTPUT_PREFIX_STRING "DEBUG : dispatch '%s/%s-%s/%s%s%s'", vl.host, vl.plugin, vl.plugin_instance, vl.type, (vl.type_instance && vl.type_instance[0])?"-":"", vl.type_instance?vl.type_instance:"(null)"); #endif #ifdef DEBUG_THIS do { int i; if(strcmp(vl.host, "aggregator_2")) break; for(i=0; i<vl.values_len; i++) { INFO(OUTPUT_PREFIX_STRING "DEBUG : dispatch '%s/%s-%s/%s%s%s DS '%s'=%12e", vl.host, vl.plugin, vl.plugin_instance, vl.type, (vl.type_instance && vl.type_instance[0])?"-":"", vl.type_instance?vl.type_instance:"(null)", ds->ds[i].name, values[i].gauge ); } } while(0); #endif plugin_dispatch_values (&vl); } } } /* while (c_avl_iterator_next) */ c_avl_iterator_destroy (iter); sfree (identifier); return(0); } /* void basic_aggregator_submit_resultvalue */
int uc_get_names (char ***ret_names, time_t **ret_times, size_t *ret_number) { c_avl_iterator_t *iter; char *key; cache_entry_t *value; char **names = NULL; time_t *times = NULL; size_t number = 0; int status = 0; if ((ret_names == NULL) || (ret_number == NULL)) return (-1); pthread_mutex_lock (&cache_lock); iter = c_avl_get_iterator (cache_tree); while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0) { char **temp; /* remove missing values when list values */ if (value->state == STATE_MISSING) continue; if (ret_times != NULL) { time_t *tmp_times; tmp_times = (time_t *) realloc (times, sizeof (time_t) * (number + 1)); if (tmp_times == NULL) { status = -1; break; } times = tmp_times; times[number] = value->last_time; } temp = (char **) realloc (names, sizeof (char *) * (number + 1)); if (temp == NULL) { status = -1; break; } names = temp; names[number] = strdup (key); if (names[number] == NULL) { status = -1; break; } number++; } /* while (c_avl_iterator_next) */ c_avl_iterator_destroy (iter); pthread_mutex_unlock (&cache_lock); if (status != 0) { size_t i; for (i = 0; i < number; i++) { sfree (names[i]); } sfree (names); return (-1); } *ret_names = names; if (ret_times != NULL) *ret_times = times; *ret_number = number; return (0); } /* int uc_get_names */
int uc_check_timeout (void) { time_t now; cache_entry_t *ce; char **keys = NULL; int keys_len = 0; char *key; c_avl_iterator_t *iter; int i; pthread_mutex_lock (&cache_lock); now = time (NULL); /* Build a list of entries to be flushed */ iter = c_avl_get_iterator (cache_tree); while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0) { /* If entry has not been updated, add to `keys' array */ /* FIXME: Remove macro once "ce->interval" is of type cdtime_t. */ if ((now - ce->last_update) >= TIME_T_TO_CDTIME_T (timeout_g * ce->interval)) { char **tmp; tmp = (char **) realloc ((void *) keys, (keys_len + 1) * sizeof (char *)); if (tmp == NULL) { ERROR ("uc_check_timeout: realloc failed."); c_avl_iterator_destroy (iter); sfree (keys); pthread_mutex_unlock (&cache_lock); return (-1); } keys = tmp; keys[keys_len] = strdup (key); if (keys[keys_len] == NULL) { ERROR ("uc_check_timeout: strdup failed."); continue; } keys_len++; } } /* while (c_avl_iterator_next) */ ce = NULL; for (i = 0; i < keys_len; i++) { int status; status = ut_check_interesting (keys[i]); if (status < 0) { ERROR ("uc_check_timeout: ut_check_interesting failed."); sfree (keys[i]); continue; } else if (status == 0) /* ``service'' is uninteresting */ { DEBUG ("uc_check_timeout: %s is missing but ``uninteresting''", keys[i]); ce = NULL; status = c_avl_remove (cache_tree, keys[i], (void *) &key, (void *) &ce); if (status != 0) { ERROR ("uc_check_timeout: c_avl_remove (%s) failed.", keys[i]); } sfree (keys[i]); sfree (key); if (ce != NULL) cache_free (ce); continue; } /* If we get here, the value is ``interesting''. Query the record from the * cache and update the state field. */ if (c_avl_get (cache_tree, keys[i], (void *) &ce) != 0) { ERROR ("uc_check_timeout: cannot get data for %s from cache", keys[i]); /* Do not free `keys[i]' so a notification is sent further down. */ continue; } assert (ce != NULL); if (status == 2) /* persist */ { DEBUG ("uc_check_timeout: %s is missing, sending notification.", keys[i]); ce->state = STATE_MISSING; /* Do not free `keys[i]' so a notification is sent further down. */ } else if (status == 1) /* do not persist */ { if (ce->state == STATE_MISSING) { DEBUG ("uc_check_timeout: %s is missing but " "notification has already been sent.", keys[i]); /* Set `keys[i]' to NULL to no notification is sent. */ sfree (keys[i]); } else /* (ce->state != STATE_MISSING) */ { DEBUG ("uc_check_timeout: %s is missing, sending one notification.", keys[i]); ce->state = STATE_MISSING; /* Do not free `keys[i]' so a notification is sent further down. */ } } else { WARNING ("uc_check_timeout: ut_check_interesting (%s) returned " "invalid status %i.", keys[i], status); sfree (keys[i]); } /* Make really sure the next iteration doesn't work with this pointer. * There have been too many bugs in the past.. :/ -- octo */ ce = NULL; } /* for (keys[i]) */ c_avl_iterator_destroy (iter); pthread_mutex_unlock (&cache_lock); for (i = 0; i < keys_len; i++) { if (keys[i] == NULL) continue; uc_send_notification (keys[i]); sfree (keys[i]); } sfree (keys); return (0); } /* int uc_check_timeout */
int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number) { c_avl_iterator_t *iter; char *key; cache_entry_t *value; char **names = NULL; cdtime_t *times = NULL; size_t number = 0; size_t size_arrays = 0; int status = 0; if ((ret_names == NULL) || (ret_number == NULL)) return (-1); pthread_mutex_lock (&cache_lock); size_arrays = (size_t) c_avl_size (cache_tree); if (size_arrays < 1) { /* Handle the "no values" case here, to avoid the error message when * calloc() returns NULL. */ pthread_mutex_unlock (&cache_lock); return (0); } names = calloc (size_arrays, sizeof (*names)); times = calloc (size_arrays, sizeof (*times)); if ((names == NULL) || (times == NULL)) { ERROR ("uc_get_names: calloc failed."); sfree (names); sfree (times); pthread_mutex_unlock (&cache_lock); return (ENOMEM); } iter = c_avl_get_iterator (cache_tree); while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0) { /* remove missing values when list values */ if (value->state == STATE_MISSING) continue; /* c_avl_size does not return a number smaller than the number of elements * returned by c_avl_iterator_next. */ assert (number < size_arrays); if (ret_times != NULL) times[number] = value->last_time; names[number] = strdup (key); if (names[number] == NULL) { status = -1; break; } number++; } /* while (c_avl_iterator_next) */ c_avl_iterator_destroy (iter); pthread_mutex_unlock (&cache_lock); if (status != 0) { size_t i; for (i = 0; i < number; i++) { sfree (names[i]); } sfree (names); sfree (times); return (-1); } *ret_names = names; if (ret_times != NULL) *ret_times = times; else sfree (times); *ret_number = number; return (0); } /* int uc_get_names */
int uc_check_timeout (void) { cdtime_t now; cache_entry_t *ce; char **keys = NULL; cdtime_t *keys_time = NULL; cdtime_t *keys_interval = NULL; int keys_len = 0; char *key; c_avl_iterator_t *iter; int status; int i; pthread_mutex_lock (&cache_lock); now = cdtime (); /* Build a list of entries to be flushed */ iter = c_avl_get_iterator (cache_tree); while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0) { char **tmp; cdtime_t *tmp_time; /* If the entry is fresh enough, continue. */ if ((now - ce->last_update) < (ce->interval * timeout_g)) continue; /* If entry has not been updated, add to `keys' array */ tmp = realloc ((void *) keys, (keys_len + 1) * sizeof (char *)); if (tmp == NULL) { ERROR ("uc_check_timeout: realloc failed."); continue; } keys = tmp; tmp_time = realloc (keys_time, (keys_len + 1) * sizeof (*keys_time)); if (tmp_time == NULL) { ERROR ("uc_check_timeout: realloc failed."); continue; } keys_time = tmp_time; tmp_time = realloc (keys_interval, (keys_len + 1) * sizeof (*keys_interval)); if (tmp_time == NULL) { ERROR ("uc_check_timeout: realloc failed."); continue; } keys_interval = tmp_time; keys[keys_len] = strdup (key); if (keys[keys_len] == NULL) { ERROR ("uc_check_timeout: strdup failed."); continue; } keys_time[keys_len] = ce->last_time; keys_interval[keys_len] = ce->interval; keys_len++; } /* while (c_avl_iterator_next) */ c_avl_iterator_destroy (iter); pthread_mutex_unlock (&cache_lock); if (keys_len == 0) { /* realloc() may have been called for these. */ sfree (keys); sfree (keys_time); sfree (keys_interval); return (0); } /* Call the "missing" callback for each value. Do this before removing the * value from the cache, so that callbacks can still access the data stored, * including plugin specific meta data, rates, history, …. This must be done * without holding the lock, otherwise we will run into a deadlock if a * plugin calls the cache interface. */ for (i = 0; i < keys_len; i++) { value_list_t vl = VALUE_LIST_INIT; vl.values = NULL; vl.values_len = 0; vl.meta = NULL; status = parse_identifier_vl (keys[i], &vl); if (status != 0) { ERROR ("uc_check_timeout: parse_identifier_vl (\"%s\") failed.", keys[i]); continue; } vl.time = keys_time[i]; vl.interval = keys_interval[i]; plugin_dispatch_missing (&vl); } /* for (i = 0; i < keys_len; i++) */ /* Now actually remove all the values from the cache. We don't re-evaluate * the timestamp again, so in theory it is possible we remove a value after * it is updated here. */ pthread_mutex_lock (&cache_lock); for (i = 0; i < keys_len; i++) { key = NULL; ce = NULL; status = c_avl_remove (cache_tree, keys[i], (void *) &key, (void *) &ce); if (status != 0) { ERROR ("uc_check_timeout: c_avl_remove (\"%s\") failed.", keys[i]); sfree (keys[i]); continue; } sfree (keys[i]); sfree (key); cache_free (ce); } /* for (i = 0; i < keys_len; i++) */ pthread_mutex_unlock (&cache_lock); sfree (keys); sfree (keys_time); sfree (keys_interval); return (0); } /* int uc_check_timeout */