X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Ftail_csv.c;h=79ea46654659ced9fab69bd8ae97e6111dc9c842;hb=ae6058aeb62cd1acdf94306404ed47b10115b89f;hp=cab26416cbffa97183e4f2c15bf2a14ff309e97e;hpb=88ed4433eaa37f5859420cc41487ec5ee080d477;p=collectd.git diff --git a/src/tail_csv.c b/src/tail_csv.c index cab26416..79ea4665 100644 --- a/src/tail_csv.c +++ b/src/tail_csv.c @@ -22,6 +22,7 @@ **/ #include "collectd.h" + #include "plugin.h" /* plugin_register_*, plugin_dispatch_values */ #include "common.h" /* auxiliary functions */ #include "utils_tail.h" @@ -33,22 +34,23 @@ #include struct metric_definition_s { - char *name; - char *type; - char *instance; - int data_source_type; - int index; + char *name; + char *type; + char *instance; + int data_source_type; + ssize_t value_from; struct metric_definition_s *next; }; typedef struct metric_definition_s metric_definition_t; struct instance_definition_s { - char *name; - char *path; - cu_tail_t *tail; + char *instance; + char *path; + cu_tail_t *tail; metric_definition_t **metric_list; - size_t metric_list_len; - cdtime_t interval; + size_t metric_list_len; + cdtime_t interval; + ssize_t time_from; struct instance_definition_s *next; }; typedef struct instance_definition_s instance_definition_t; @@ -69,7 +71,8 @@ static int tcsv_submit (instance_definition_t *id, sstrncpy(vl.host, hostname_g, sizeof (vl.host)); sstrncpy(vl.plugin, "tail_csv", sizeof(vl.plugin)); - sstrncpy(vl.plugin_instance, id->name, sizeof(vl.plugin_instance)); + if (id->instance != NULL) + sstrncpy(vl.plugin_instance, id->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, md->type, sizeof(vl.type)); if (md->instance != NULL) sstrncpy(vl.type_instance, md->instance, sizeof(vl.type_instance)); @@ -77,16 +80,13 @@ static int tcsv_submit (instance_definition_t *id, vl.time = t; vl.interval = id->interval; - DEBUG("tail_csv plugin: -> plugin_dispatch_values (&vl);"); - plugin_dispatch_values(&vl); - - return (0); + return (plugin_dispatch_values(&vl)); } static cdtime_t parse_time (char const *tbuf) { double t; - char *endptr = 0; + char *endptr = NULL; errno = 0; t = strtod (tbuf, &endptr); @@ -101,21 +101,42 @@ static int tcsv_read_metric (instance_definition_t *id, char **fields, size_t fields_num) { value_t v; - cdtime_t t; + cdtime_t t = 0; int status; - if (md->index >= fields_num) + if (md->data_source_type == -1) return (EINVAL); - t = parse_time (fields[0]); + assert (md->value_from >= 0); + if (((size_t) md->value_from) >= fields_num) + return (EINVAL); - status = parse_value (fields[md->index], &v, md->data_source_type); + status = parse_value (fields[md->value_from], &v, md->data_source_type); if (status != 0) return (status); + if (id->time_from >= 0) { + if (((size_t) id->time_from) >= fields_num) + return (EINVAL); + t = parse_time (fields[id->time_from]); + } + return (tcsv_submit (id, md, v, t)); } +static _Bool tcsv_check_index (ssize_t index, size_t fields_num, char const *name) +{ + if (index < 0) + return 1; + else if (((size_t) index) < fields_num) + return 1; + + ERROR ("tail_csv plugin: Metric \"%s\": Request for index %zd when " + "only %zu fields are available.", + name, index, fields_num); + return (0); +} + static int tcsv_read_buffer (instance_definition_t *id, char *buffer, size_t buffer_size) { @@ -177,12 +198,9 @@ static int tcsv_read_buffer (instance_definition_t *id, for (i = 0; i < id->metric_list_len; ++i){ metric_definition_t *md = id->metric_list[i]; - if (((size_t) md->index) >= metrics_num) { - ERROR ("tail_csv plugin: Metric \"%s\": Request for index %i when " - "only %zu fields are available.", - md->name, md->index, metrics_num); + if (!tcsv_check_index (md->value_from, metrics_num, md->name) + || !tcsv_check_index (id->time_from, metrics_num, md->name)) continue; - } tcsv_read_metric (id, md, metrics, metrics_num); } @@ -194,9 +212,7 @@ static int tcsv_read_buffer (instance_definition_t *id, static int tcsv_read (user_data_t *ud) { instance_definition_t *id; - id = ud->data; - DEBUG("tail_csv plugin: tcsv_read (instance = %s)", id->name); if (id->tail == NULL) { @@ -218,8 +234,8 @@ static int tcsv_read (user_data_t *ud) { status = cu_tail_readline (id->tail, buffer, (int) sizeof (buffer)); if (status != 0) { - ERROR ("tail_csv plugin: Instance \"%s\": cu_tail_readline failed " - "with status %i.", id->name, status); + ERROR ("tail_csv plugin: File \"%s\": cu_tail_readline failed " + "with status %i.", id->path, status); return (-1); } @@ -235,49 +251,53 @@ static int tcsv_read (user_data_t *ud) { static void tcsv_metric_definition_destroy(void *arg){ metric_definition_t *md; + metric_definition_t *next; md = arg; if (md == NULL) return; - if (md->name != NULL) - DEBUG("tail_csv plugin: Destroying metric definition `%s'.", md->name); + next = md->next; + md->next = NULL; sfree(md->name); sfree(md->type); sfree(md->instance); sfree(md); + + tcsv_metric_definition_destroy (next); } -static int tcsv_config_add_metric_index(metric_definition_t *md, oconfig_item_t *ci){ +static int tcsv_config_get_index(oconfig_item_t *ci, ssize_t *ret_index) { if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)){ - WARNING("tail_csv plugin: `Index' needs exactly one integer argument."); + WARNING("tail_csv plugin: The \"%s\" config option needs exactly one " + "integer argument.", ci->key); return (-1); } - md->index = (int)ci->values[0].value.number; - if (md->index <= 0){ - WARNING("tail_csv plugin: `Index' must be higher than 0."); + if (ci->values[0].value.number < 0) { + WARNING("tail_csv plugin: The \"%s\" config option must be positive " + "(or zero).", ci->key); return (-1); } + *ret_index = (ssize_t) ci->values[0].value.number; return (0); } /* Parse metric */ static int tcsv_config_add_metric(oconfig_item_t *ci){ metric_definition_t *md; - const data_set_t *ds; - int status = 0; - int i; + int status; - md = (metric_definition_t *)malloc(sizeof(*md)); + md = calloc(1, sizeof(*md)); if (md == NULL) return (-1); - memset(md, 0, sizeof(*md)); md->name = NULL; md->type = NULL; md->instance = NULL; + md->data_source_type = -1; + md->value_from = -1; md->next = NULL; status = cf_util_get_string (ci, &md->name); @@ -286,16 +306,15 @@ static int tcsv_config_add_metric(oconfig_item_t *ci){ return (-1); } - for (i = 0; i < ci->children_num; ++i){ + for (int i = 0; i < ci->children_num; ++i){ oconfig_item_t *option = ci->children + i; - status = 0; if (strcasecmp("Type", option->key) == 0) status = cf_util_get_string(option, &md->type); else if (strcasecmp("Instance", option->key) == 0) status = cf_util_get_string(option, &md->instance); - else if (strcasecmp("Index", option->key) == 0) - status = tcsv_config_add_metric_index(md, option); + else if (strcasecmp("ValueFrom", option->key) == 0) + status = tcsv_config_get_index (option, &md->value_from); else { WARNING("tail_csv plugin: Option `%s' not allowed here.", option->key); status = -1; @@ -311,40 +330,18 @@ static int tcsv_config_add_metric(oconfig_item_t *ci){ } /* Verify all necessary options have been set. */ - if (md->type == NULL){ + if (md->type == NULL) { WARNING("tail_csv plugin: Option `Type' must be set."); status = -1; - } else if (md->index == 0){ - WARNING("tail_csv plugin: Option `Index' must be set."); + } else if (md->value_from < 0) { + WARNING("tail_csv plugin: Option `ValueFrom' must be set."); status = -1; } - - if (status != 0){ - tcsv_metric_definition_destroy(md); - return (-1); - } - - /* Retrieve the data source type from the types db. */ - ds = plugin_get_ds(md->type); - if (ds == NULL){ - ERROR ("tail_csv plugin: Failed to look up type \"%s\". " - "It may not be defined in the types.db file. " - "Please read the types.db(5) manual page for more details.", - md->type); + if (status != 0) { tcsv_metric_definition_destroy(md); - return (-1); - } else if (ds->ds_num != 1) { - ERROR ("tail_csv plugin: The type \"%s\" has %i data sources. " - "Only types with a single data soure are supported.", - ds->type, ds->ds_num); - return (-1); - } else { - md->data_source_type = ds->ds->type; + return (status); } - DEBUG("tail_csv plugin: md = { name = %s, type = %s, data_source_type = %d, index = %d }", - md->name, md->type, md->data_source_type, md->index); - if (metric_head == NULL) metric_head = md; else { @@ -365,98 +362,97 @@ static void tcsv_instance_definition_destroy(void *arg){ if (id == NULL) return; - if (id->name != NULL) - DEBUG("tail_csv plugin: Destroying instance definition `%s'.", id->name); - - cu_tail_destroy (id->tail); + if (id->tail != NULL) + cu_tail_destroy (id->tail); id->tail = NULL; - sfree(id->name); + sfree(id->instance); sfree(id->path); sfree(id->metric_list); sfree(id); } -static int tcsv_config_add_instance_collect(instance_definition_t *id, oconfig_item_t *ci){ +static int tcsv_config_add_instance_collect(instance_definition_t *id, oconfig_item_t *ci) { metric_definition_t *metric; - int i; + metric_definition_t **metric_list; + size_t metric_list_size; - if (ci->values_num < 1){ + if (ci->values_num < 1) { WARNING("tail_csv plugin: The `Collect' config option needs at least one argument."); return (-1); } - /* Verify string arguments */ - for (i = 0; i < ci->values_num; ++i) - if (ci->values[i].type != OCONFIG_TYPE_STRING){ + metric_list_size = id->metric_list_len + (size_t) ci->values_num; + metric_list = realloc (id->metric_list, sizeof (*id->metric_list) * metric_list_size); + if (metric_list == NULL) + return (-1); + id->metric_list = metric_list; + + for (int i = 0; i < ci->values_num; i++) { + char *metric_name; + + if (ci->values[i].type != OCONFIG_TYPE_STRING) { WARNING("tail_csv plugin: All arguments to `Collect' must be strings."); - return (-1); + continue; } + metric_name = ci->values[i].value.string; - id->metric_list = (metric_definition_t **)malloc(sizeof(metric_definition_t *) * ci->values_num); - if (id->metric_list == NULL) - return (-1); - - for (i = 0; i < ci->values_num; ++i){ for (metric = metric_head; metric != NULL; metric = metric->next) - if (strcasecmp(ci->values[i].value.string, metric->name) == 0) + if (strcasecmp(metric_name, metric->name) == 0) break; - if (metric == NULL){ - WARNING("tail_csv plugin: `Collect' argument not found `%s'.", ci->values[i].value.string); - return (-1); + if (metric == NULL) { + WARNING ("tail_csv plugin: `Collect' argument not found `%s'.", metric_name); + continue; } - DEBUG("tail_csv plugin: id { name=%s md->name=%s }", id->name, metric->name); - - id->metric_list[i] = metric; + id->metric_list[id->metric_list_len] = metric; id->metric_list_len++; } return (0); } -/* Parse instance */ -static int tcsv_config_add_instance(oconfig_item_t *ci){ - +/* block */ +static int tcsv_config_add_file(oconfig_item_t *ci) +{ instance_definition_t* id; int status = 0; - int i; /* Registration variables */ char cb_name[DATA_MAX_NAME_LEN]; - user_data_t cb_data; - struct timespec cb_interval; - - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)){ - WARNING("tail_csv plugin: The `Instance' config option needs exactly one string argument."); - return (-1); - } + user_data_t cb_data = { 0 }; - id = (instance_definition_t *)malloc(sizeof(*id)); + id = calloc(1, sizeof(*id)); if (id == NULL) return (-1); - memset(id, 0, sizeof(*id)); + id->instance = NULL; + id->path = NULL; + id->metric_list = NULL; + id->time_from = -1; + id->next = NULL; - id->name = strdup(ci->values[0].value.string); - if (id->name == NULL){ - free(id); - return (-1); + status = cf_util_get_string (ci, &id->path); + if (status != 0) { + sfree (id); + return (status); } /* Use default interval. */ id->interval = plugin_get_interval(); - for (i = 0; i < ci->children_num; ++i){ + for (int i = 0; i < ci->children_num; ++i){ oconfig_item_t *option = ci->children + i; status = 0; - if (strcasecmp("Path", option->key) == 0) - status = cf_util_get_string(option, &id->path); + if (strcasecmp("Instance", option->key) == 0) + status = cf_util_get_string(option, &id->instance); else if (strcasecmp("Collect", option->key) == 0) status = tcsv_config_add_instance_collect(id, option); else if (strcasecmp("Interval", option->key) == 0) cf_util_get_cdtime(option, &id->interval); + else if (strcasecmp("TimeFrom", option->key) == 0) + status = tcsv_config_get_index (option, &id->time_from); else { WARNING("tail_csv plugin: Option `%s' not allowed here.", option->key); status = -1; @@ -485,14 +481,10 @@ static int tcsv_config_add_instance(oconfig_item_t *ci){ return (-1); } - DEBUG("tail_csv plugin: id = { name = %s, path = %s }", id->name, id->path); - - ssnprintf (cb_name, sizeof (cb_name), "tail_csv/%s", id->name); - memset(&cb_data, 0, sizeof(cb_data)); + ssnprintf (cb_name, sizeof (cb_name), "tail_csv/%s", id->path); cb_data.data = id; cb_data.free_func = tcsv_instance_definition_destroy; - CDTIME_T_TO_TIMESPEC(id->interval, &cb_interval); - status = plugin_register_complex_read(NULL, cb_name, tcsv_read, &cb_interval, &cb_data); + status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval, &cb_data); if (status != 0){ ERROR("tail_csv plugin: Registering complex read function failed."); @@ -505,13 +497,12 @@ static int tcsv_config_add_instance(oconfig_item_t *ci){ /* Parse blocks */ static int tcsv_config(oconfig_item_t *ci){ - int i; - for (i = 0; i < ci->children_num; ++i){ + for (int i = 0; i < ci->children_num; ++i){ oconfig_item_t *child = ci->children + i; if (strcasecmp("Metric", child->key) == 0) tcsv_config_add_metric(child); - else if (strcasecmp("Instance", child->key) == 0) - tcsv_config_add_instance(child); + else if (strcasecmp("File", child->key) == 0) + tcsv_config_add_file(child); else WARNING("tail_csv plugin: Ignore unknown config option `%s'.", child->key); } @@ -519,24 +510,51 @@ static int tcsv_config(oconfig_item_t *ci){ return (0); } /* int tcsv_config */ -static int tcsv_shutdown(void){ - metric_definition_t *metric_this; - metric_definition_t *metric_next; +static int tcsv_init(void) { /* {{{ */ + static _Bool have_init = 0; + metric_definition_t *md; - metric_this = metric_head; - metric_head = NULL; + if (have_init) + return (0); + + for (md = metric_head; md != NULL; md = md->next) { + data_set_t const *ds; + + /* Retrieve the data source type from the types db. */ + ds = plugin_get_ds(md->type); + if (ds == NULL) + { + ERROR ("tail_csv plugin: Failed to look up type \"%s\" for " + "metric \"%s\". It may not be defined in the types.db " + "file. Please read the types.db(5) manual page for more " + "details.", + md->type, md->name); + continue; + } + else if (ds->ds_num != 1) + { + ERROR ("tail_csv plugin: The type \"%s\" has %zu data sources. " + "Only types with a single data soure are supported.", + ds->type, ds->ds_num); + continue; + } - while (metric_this != NULL){ - metric_next = metric_this->next; - tcsv_metric_definition_destroy(metric_this); - metric_this = metric_next; + md->data_source_type = ds->ds->type; } return (0); +} /* }}} int tcsv_init */ + +static int tcsv_shutdown (void) { + tcsv_metric_definition_destroy (metric_head); + metric_head = NULL; + + return (0); } void module_register(void){ plugin_register_complex_config("tail_csv", tcsv_config); + plugin_register_init("tail_csv", tcsv_init); plugin_register_shutdown("tail_csv", tcsv_shutdown); }