X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fcsv.c;h=be59ede03ef27a12373a3a07b1ea73d2f12f4e5b;hp=e008ecfe0f6fdeafe10caa20b9d7ca2eaf44c2f6;hb=ec51ddee94fa2ba1e01fe0e336ccc9c190a198ff;hpb=c7d859191d8fbfc129dea8cfaf9e13e78fd6642c diff --git a/src/csv.c b/src/csv.c index e008ecfe..be59ede0 100644 --- a/src/csv.c +++ b/src/csv.c @@ -23,348 +23,275 @@ #include "collectd.h" -#include "plugin.h" #include "common.h" +#include "plugin.h" #include "utils_cache.h" /* * Private variables */ -static const char *config_keys[] = -{ - "DataDir", - "StoreRates" -}; -static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); - -static char *datadir = NULL; -static int store_rates = 0; -static int use_stdio = 0; - -static int value_list_to_string (char *buffer, int buffer_len, - const data_set_t *ds, const value_list_t *vl) -{ - int offset; - int status; - gauge_t *rates = NULL; - - assert (0 == strcmp (ds->type, vl->type)); - - memset (buffer, '\0', buffer_len); - - status = ssnprintf (buffer, buffer_len, "%.3f", - CDTIME_T_TO_DOUBLE (vl->time)); - if ((status < 1) || (status >= buffer_len)) - return (-1); - offset = status; - - for (size_t i = 0; i < ds->ds_num; i++) - { - if ((ds->ds[i].type != DS_TYPE_COUNTER) - && (ds->ds[i].type != DS_TYPE_GAUGE) - && (ds->ds[i].type != DS_TYPE_DERIVE) - && (ds->ds[i].type != DS_TYPE_ABSOLUTE)) - { - sfree (rates); - return (-1); - } - - if (ds->ds[i].type == DS_TYPE_GAUGE) - { - status = ssnprintf (buffer + offset, buffer_len - offset, - ",%lf", vl->values[i].gauge); - } - else if (store_rates != 0) - { - if (rates == NULL) - rates = uc_get_rate (ds, vl); - if (rates == NULL) - { - WARNING ("csv plugin: " - "uc_get_rate failed."); - return (-1); - } - status = ssnprintf (buffer + offset, - buffer_len - offset, - ",%lf", rates[i]); - } - else if (ds->ds[i].type == DS_TYPE_COUNTER) - { - status = ssnprintf (buffer + offset, - buffer_len - offset, - ",%llu", - vl->values[i].counter); - } - else if (ds->ds[i].type == DS_TYPE_DERIVE) - { - status = ssnprintf (buffer + offset, - buffer_len - offset, - ",%"PRIi64, - vl->values[i].derive); - } - else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) - { - status = ssnprintf (buffer + offset, - buffer_len - offset, - ",%"PRIu64, - vl->values[i].absolute); - } - - if ((status < 1) || (status >= (buffer_len - offset))) - { - sfree (rates); - return (-1); - } - - offset += status; - } /* for ds->ds_num */ - - sfree (rates); - return (0); +static const char *config_keys[] = {"DataDir", "StoreRates"}; +static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); + +static char *datadir; +static int store_rates; +static int use_stdio; + +static int value_list_to_string(char *buffer, int buffer_len, + const data_set_t *ds, const value_list_t *vl) { + int offset; + int status; + gauge_t *rates = NULL; + + assert(0 == strcmp(ds->type, vl->type)); + + memset(buffer, '\0', buffer_len); + + status = snprintf(buffer, buffer_len, "%.3f", CDTIME_T_TO_DOUBLE(vl->time)); + if ((status < 1) || (status >= buffer_len)) + return -1; + offset = status; + + for (size_t i = 0; i < ds->ds_num; i++) { + if ((ds->ds[i].type != DS_TYPE_COUNTER) && + (ds->ds[i].type != DS_TYPE_GAUGE) && + (ds->ds[i].type != DS_TYPE_DERIVE) && + (ds->ds[i].type != DS_TYPE_ABSOLUTE)) { + sfree(rates); + return -1; + } + + if (ds->ds[i].type == DS_TYPE_GAUGE) { + status = snprintf(buffer + offset, buffer_len - offset, ",%lf", + vl->values[i].gauge); + } else if (store_rates != 0) { + if (rates == NULL) + rates = uc_get_rate(ds, vl); + if (rates == NULL) { + WARNING("csv plugin: " + "uc_get_rate failed."); + return -1; + } + status = snprintf(buffer + offset, buffer_len - offset, ",%lf", rates[i]); + } else if (ds->ds[i].type == DS_TYPE_COUNTER) { + status = snprintf(buffer + offset, buffer_len - offset, ",%" PRIu64, + (uint64_t)vl->values[i].counter); + } else if (ds->ds[i].type == DS_TYPE_DERIVE) { + status = snprintf(buffer + offset, buffer_len - offset, ",%" PRIi64, + vl->values[i].derive); + } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) { + status = snprintf(buffer + offset, buffer_len - offset, ",%" PRIu64, + vl->values[i].absolute); + } + + if ((status < 1) || (status >= (buffer_len - offset))) { + sfree(rates); + return -1; + } + + offset += status; + } /* for ds->ds_num */ + + sfree(rates); + return 0; } /* int value_list_to_string */ -static int value_list_to_filename (char *buffer, size_t buffer_size, - value_list_t const *vl) -{ - int status; - - char *ptr = buffer; - size_t ptr_size = buffer_size; - time_t now; - struct tm struct_tm; - - if (datadir != NULL) - { - size_t len = strlen (datadir) + 1; - - if (len >= ptr_size) - return (ENOBUFS); - - memcpy (ptr, datadir, len); - ptr[len-1] = '/'; - ptr_size -= len; - ptr += len; - } - - status = FORMAT_VL (ptr, ptr_size, vl); - if (status != 0) - return (status); - - /* Skip all the time formatting stuff when printing to STDOUT or - * STDERR. */ - if (use_stdio) - return (0); - - ptr_size -= strlen (ptr); - ptr += strlen (ptr); - - /* "-2013-07-12" => 11 bytes */ - if (ptr_size < 12) - { - ERROR ("csv plugin: Buffer too small."); - return (ENOMEM); - } - - /* TODO: Find a way to minimize the calls to `localtime_r', - * since they are pretty expensive.. */ - now = time (NULL); - if (localtime_r (&now, &struct_tm) == NULL) - { - ERROR ("csv plugin: localtime_r failed"); - return (-1); - } - - status = strftime (ptr, ptr_size, "-%Y-%m-%d", &struct_tm); - if (status == 0) /* yep, it returns zero on error. */ - { - ERROR ("csv plugin: strftime failed"); - return (-1); - } - - return (0); +static int value_list_to_filename(char *buffer, size_t buffer_size, + value_list_t const *vl) { + int status; + + char *ptr = buffer; + size_t ptr_size = buffer_size; + time_t now; + struct tm struct_tm; + + if (datadir != NULL) { + size_t len = strlen(datadir) + 1; + + if (len >= ptr_size) + return ENOBUFS; + + memcpy(ptr, datadir, len); + ptr[len - 1] = '/'; + ptr_size -= len; + ptr += len; + } + + status = FORMAT_VL(ptr, ptr_size, vl); + if (status != 0) + return status; + + /* Skip all the time formatting stuff when printing to STDOUT or + * STDERR. */ + if (use_stdio) + return 0; + + ptr_size -= strlen(ptr); + ptr += strlen(ptr); + + /* "-2013-07-12" => 11 bytes */ + if (ptr_size < 12) { + ERROR("csv plugin: Buffer too small."); + return ENOMEM; + } + + /* TODO: Find a way to minimize the calls to `localtime_r', + * since they are pretty expensive.. */ + now = time(NULL); + if (localtime_r(&now, &struct_tm) == NULL) { + ERROR("csv plugin: localtime_r failed"); + return -1; + } + + status = strftime(ptr, ptr_size, "-%Y-%m-%d", &struct_tm); + if (status == 0) /* yep, it returns zero on error. */ + { + ERROR("csv plugin: strftime failed"); + return -1; + } + + return 0; } /* int value_list_to_filename */ -static int csv_create_file (const char *filename, const data_set_t *ds) -{ - FILE *csv; +static int csv_create_file(const char *filename, const data_set_t *ds) { + FILE *csv; - if (check_create_dir (filename)) - return (-1); + if (check_create_dir(filename)) + return -1; - csv = fopen (filename, "w"); - if (csv == NULL) - { - char errbuf[1024]; - ERROR ("csv plugin: fopen (%s) failed: %s", - filename, - sstrerror (errno, errbuf, sizeof (errbuf))); - return (-1); - } + csv = fopen(filename, "w"); + if (csv == NULL) { + ERROR("csv plugin: fopen (%s) failed: %s", filename, STRERRNO); + return -1; + } - fprintf (csv, "epoch"); - for (size_t i = 0; i < ds->ds_num; i++) - fprintf (csv, ",%s", ds->ds[i].name); + fprintf(csv, "epoch"); + for (size_t i = 0; i < ds->ds_num; i++) + fprintf(csv, ",%s", ds->ds[i].name); - fprintf (csv, "\n"); - fclose (csv); + fprintf(csv, "\n"); + fclose(csv); - return 0; + return 0; } /* int csv_create_file */ -static int csv_config (const char *key, const char *value) -{ - if (strcasecmp ("DataDir", key) == 0) - { - if (datadir != NULL) - { - free (datadir); - datadir = NULL; - } - if (strcasecmp ("stdout", value) == 0) - { - use_stdio = 1; - return (0); - } - else if (strcasecmp ("stderr", value) == 0) - { - use_stdio = 2; - return (0); - } - datadir = strdup (value); - if (datadir != NULL) - { - int len = strlen (datadir); - while ((len > 0) && (datadir[len - 1] == '/')) - { - len--; - datadir[len] = '\0'; - } - if (len <= 0) - { - free (datadir); - datadir = NULL; - } - } - } - else if (strcasecmp ("StoreRates", key) == 0) - { - if (IS_TRUE (value)) - store_rates = 1; - else - store_rates = 0; - } - else - { - return (-1); - } - return (0); +static int csv_config(const char *key, const char *value) { + if (strcasecmp("DataDir", key) == 0) { + if (datadir != NULL) { + free(datadir); + datadir = NULL; + } + if (strcasecmp("stdout", value) == 0) { + use_stdio = 1; + return 0; + } else if (strcasecmp("stderr", value) == 0) { + use_stdio = 2; + return 0; + } + datadir = strdup(value); + if (datadir != NULL) { + int len = strlen(datadir); + while ((len > 0) && (datadir[len - 1] == '/')) { + len--; + datadir[len] = '\0'; + } + if (len <= 0) { + free(datadir); + datadir = NULL; + } + } + } else if (strcasecmp("StoreRates", key) == 0) { + if (IS_TRUE(value)) + store_rates = 1; + else + store_rates = 0; + } else { + return -1; + } + return 0; } /* int csv_config */ -static int csv_write (const data_set_t *ds, const value_list_t *vl, - user_data_t __attribute__((unused)) *user_data) -{ - struct stat statbuf; - char filename[512]; - char values[4096]; - FILE *csv; - int csv_fd; - struct flock fl = { 0 }; - int status; - - if (0 != strcmp (ds->type, vl->type)) { - ERROR ("csv plugin: DS type does not match value list type"); - return -1; - } - - status = value_list_to_filename (filename, sizeof (filename), vl); - if (status != 0) - return (-1); - - DEBUG ("csv plugin: csv_write: filename = %s;", filename); - - if (value_list_to_string (values, sizeof (values), ds, vl) != 0) - return (-1); - - if (use_stdio) - { - escape_string (filename, sizeof (filename)); - - /* Replace commas by colons for PUTVAL compatible output. */ - for (size_t i = 0; i < sizeof (values); i++) - { - if (values[i] == 0) - break; - else if (values[i] == ',') - values[i] = ':'; - } - - fprintf (use_stdio == 1 ? stdout : stderr, - "PUTVAL %s interval=%.3f %s\n", - filename, - CDTIME_T_TO_DOUBLE (vl->interval), - values); - return (0); - } - - if (stat (filename, &statbuf) == -1) - { - if (errno == ENOENT) - { - if (csv_create_file (filename, ds)) - return (-1); - } - else - { - char errbuf[1024]; - ERROR ("stat(%s) failed: %s", filename, - sstrerror (errno, errbuf, - sizeof (errbuf))); - return (-1); - } - } - else if (!S_ISREG (statbuf.st_mode)) - { - ERROR ("stat(%s): Not a regular file!", - filename); - return (-1); - } - - csv = fopen (filename, "a"); - if (csv == NULL) - { - char errbuf[1024]; - ERROR ("csv plugin: fopen (%s) failed: %s", filename, - sstrerror (errno, errbuf, sizeof (errbuf))); - return (-1); - } - csv_fd = fileno (csv); - - fl.l_pid = getpid (); - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - - status = fcntl (csv_fd, F_SETLK, &fl); - if (status != 0) - { - char errbuf[1024]; - ERROR ("csv plugin: flock (%s) failed: %s", filename, - sstrerror (errno, errbuf, sizeof (errbuf))); - fclose (csv); - return (-1); - } - - fprintf (csv, "%s\n", values); - - /* The lock is implicitely released. I we don't release it explicitely - * because the `FILE *' may need to flush a cache first */ - fclose (csv); - - return (0); +static int csv_write(const data_set_t *ds, const value_list_t *vl, + user_data_t __attribute__((unused)) * user_data) { + struct stat statbuf; + char filename[512]; + char values[4096]; + FILE *csv; + int csv_fd; + struct flock fl = {0}; + int status; + + if (0 != strcmp(ds->type, vl->type)) { + ERROR("csv plugin: DS type does not match value list type"); + return -1; + } + + status = value_list_to_filename(filename, sizeof(filename), vl); + if (status != 0) + return -1; + + DEBUG("csv plugin: csv_write: filename = %s;", filename); + + if (value_list_to_string(values, sizeof(values), ds, vl) != 0) + return -1; + + if (use_stdio) { + escape_string(filename, sizeof(filename)); + + /* Replace commas by colons for PUTVAL compatible output. */ + for (size_t i = 0; i < sizeof(values); i++) { + if (values[i] == 0) + break; + else if (values[i] == ',') + values[i] = ':'; + } + + fprintf(use_stdio == 1 ? stdout : stderr, "PUTVAL %s interval=%.3f %s\n", + filename, CDTIME_T_TO_DOUBLE(vl->interval), values); + return 0; + } + + if (stat(filename, &statbuf) == -1) { + if (errno == ENOENT) { + if (csv_create_file(filename, ds)) + return -1; + } else { + ERROR("stat(%s) failed: %s", filename, STRERRNO); + return -1; + } + } else if (!S_ISREG(statbuf.st_mode)) { + ERROR("stat(%s): Not a regular file!", filename); + return -1; + } + + csv = fopen(filename, "a"); + if (csv == NULL) { + ERROR("csv plugin: fopen (%s) failed: %s", filename, STRERRNO); + return -1; + } + csv_fd = fileno(csv); + + fl.l_pid = getpid(); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + + status = fcntl(csv_fd, F_SETLK, &fl); + if (status != 0) { + ERROR("csv plugin: flock (%s) failed: %s", filename, STRERRNO); + fclose(csv); + return -1; + } + + fprintf(csv, "%s\n", values); + + /* The lock is implicitely released. I we don't release it explicitely + * because the `FILE *' may need to flush a cache first */ + fclose(csv); + + return 0; } /* int csv_write */ -void module_register (void) -{ - plugin_register_config ("csv", csv_config, - config_keys, config_keys_num); - plugin_register_write ("csv", csv_write, /* user_data = */ NULL); +void module_register(void) { + plugin_register_config("csv", csv_config, config_keys, config_keys_num); + plugin_register_write("csv", csv_write, /* user_data = */ NULL); } /* void module_register */