csv plugin: Make the output to STDOUT compatible to the exec plugin.
[collectd.git] / src / csv.c
index dd33ca5..352557a 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
@@ -1,6 +1,6 @@
 /**
  * collectd - src/csv.c
- * Copyright (C) 2007  Florian octo Forster
+ * Copyright (C) 2007-2009  Florian octo Forster
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
 #include "collectd.h"
 #include "plugin.h"
 #include "common.h"
-#include "utils_debug.h"
+#include "utils_cache.h"
+#include "utils_parse_option.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)
@@ -30,10 +45,13 @@ static int value_list_to_string (char *buffer, int buffer_len,
        int offset;
        int status;
        int i;
+       gauge_t *rates = NULL;
+
+       assert (0 == strcmp (ds->type, vl->type));
 
-       memset (buffer, '\0', sizeof (buffer_len));
+       memset (buffer, '\0', buffer_len);
 
-       status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+       status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
        if ((status < 1) || (status >= buffer_len))
                return (-1);
        offset = status;
@@ -45,18 +63,45 @@ static int value_list_to_string (char *buffer, int buffer_len,
                        return (-1);
 
                if (ds->ds[i].type == DS_TYPE_COUNTER)
-                       status = snprintf (buffer + offset, buffer_len - offset,
-                                       ",%llu", vl->values[i].counter);
-               else
-                       status = snprintf (buffer + offset, buffer_len - offset,
+               {
+                       if (store_rates == 0)
+                       {
+                               status = ssnprintf (buffer + offset,
+                                               buffer_len - offset,
+                                               ",%llu",
+                                               vl->values[i].counter);
+                       }
+                       else /* if (store_rates == 1) */
+                       {
+                               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_GAUGE) */
+               {
+                       status = ssnprintf (buffer + offset, buffer_len - offset,
                                        ",%lf", vl->values[i].gauge);
+               }
 
                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 */
 
@@ -66,46 +111,59 @@ static int value_list_to_filename (char *buffer, int buffer_len,
        int offset = 0;
        int status;
 
-       status = snprintf (buffer + offset, buffer_len - offset,
+       assert (0 == strcmp (ds->type, vl->type));
+
+       if (datadir != NULL)
+       {
+               status = ssnprintf (buffer + offset, buffer_len - offset,
+                               "%s/", datadir);
+               if ((status < 1) || (status >= buffer_len - offset))
+                       return (-1);
+               offset += status;
+       }
+
+       status = ssnprintf (buffer + offset, buffer_len - offset,
                        "%s/", vl->host);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
 
        if (strlen (vl->plugin_instance) > 0)
-               status = snprintf (buffer + offset, buffer_len - offset,
+               status = ssnprintf (buffer + offset, buffer_len - offset,
                                "%s-%s/", vl->plugin, vl->plugin_instance);
        else
-               status = snprintf (buffer + offset, buffer_len - offset,
+               status = ssnprintf (buffer + offset, buffer_len - offset,
                                "%s/", vl->plugin);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
 
        if (strlen (vl->type_instance) > 0)
-               status = snprintf (buffer + offset, buffer_len - offset,
-                               "%s-%s", ds->type, vl->type_instance);
+               status = ssnprintf (buffer + offset, buffer_len - offset,
+                               "%s-%s", vl->type, vl->type_instance);
        else
-               status = snprintf (buffer + offset, buffer_len - offset,
-                               "%s", ds->type);
+               status = ssnprintf (buffer + offset, buffer_len - offset,
+                               "%s", vl->type);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
 
+       if (!use_stdio)
        {
                time_t now;
-               struct tm *tm;
+               struct tm stm;
 
-               /* TODO: Find a way to minimize the calls to `localtime', since
-                * they are pretty expensive.. */
+               /* TODO: Find a way to minimize the calls to `localtime_r',
+                * since they are pretty expensive.. */
                now = time (NULL);
-               tm = localtime (&now);
+               if (localtime_r (&now, &stm) == NULL)
+               {
+                       ERROR ("csv plugin: localtime_r failed");
+                       return (1);
+               }
 
                strftime (buffer + offset, buffer_len - offset,
-                               "-%Y-%m-%d", tm);
-
-               /* `localtime(3)' returns a pointer to static data,
-                * therefore the pointer may not be free'd. */
+                               "-%Y-%m-%d", &stm);
        }
 
        return (0);
@@ -122,8 +180,10 @@ static int csv_create_file (const char *filename, const data_set_t *ds)
        csv = fopen (filename, "w");
        if (csv == NULL)
        {
-               syslog (LOG_ERR, "csv plugin: fopen (%s) failed: %s",
-                               filename, strerror(errno));
+               char errbuf[1024];
+               ERROR ("csv plugin: fopen (%s) failed: %s",
+                               filename,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
 
@@ -137,6 +197,58 @@ static int csv_create_file (const char *filename, const data_set_t *ds)
        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);
+               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 ((strcasecmp ("True", value) == 0)
+                               || (strcasecmp ("Yes", value) == 0)
+                               || (strcasecmp ("On", value) == 0))
+               {
+                       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)
 {
        struct stat  statbuf;
@@ -147,12 +259,40 @@ static int csv_write (const data_set_t *ds, const value_list_t *vl)
        struct flock fl;
        int          status;
 
+       if (0 != strcmp (ds->type, vl->type)) {
+               ERROR ("csv plugin: DS type does not match value list type");
+               return -1;
+       }
+
        if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 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)
+       {
+               size_t i;
+
+               escape_string (filename, sizeof (filename));
+
+               /* Replace commas by colons for PUTVAL compatible output. */
+               for (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=%i %s\n",
+                        filename, interval_g, values);
+               return (0);
+       }
+
        if (stat (filename, &statbuf) == -1)
        {
                if (errno == ENOENT)
@@ -162,14 +302,16 @@ static int csv_write (const data_set_t *ds, const value_list_t *vl)
                }
                else
                {
-                       syslog (LOG_ERR, "stat(%s) failed: %s",
-                                       filename, strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("stat(%s) failed: %s", filename,
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (-1);
                }
        }
        else if (!S_ISREG (statbuf.st_mode))
        {
-               syslog (LOG_ERR, "stat(%s): Not a regular file!",
+               ERROR ("stat(%s): Not a regular file!",
                                filename);
                return (-1);
        }
@@ -177,8 +319,9 @@ static int csv_write (const data_set_t *ds, const value_list_t *vl)
        csv = fopen (filename, "a");
        if (csv == NULL)
        {
-               syslog (LOG_ERR, "csv plugin: fopen (%s) failed: %s",
-                               filename, strerror (errno));
+               char errbuf[1024];
+               ERROR ("csv plugin: fopen (%s) failed: %s", filename,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
        csv_fd = fileno (csv);
@@ -193,8 +336,9 @@ static int csv_write (const data_set_t *ds, const value_list_t *vl)
        status = fcntl (csv_fd, F_SETLK, &fl);
        if (status != 0)
        {
-               syslog (LOG_ERR, "csv plugin: flock (%s) failed: %s",
-                               filename, strerror (errno));
+               char errbuf[1024];
+               ERROR ("csv plugin: flock (%s) failed: %s", filename,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                fclose (csv);
                return (-1);
        }
@@ -210,5 +354,7 @@ static int csv_write (const data_set_t *ds, const value_list_t *vl)
 
 void module_register (void)
 {
+       plugin_register_config ("csv", csv_config,
+                       config_keys, config_keys_num);
        plugin_register_write ("csv", csv_write);
-}
+} /* void module_register */