rrdtool plugin: First implementation of an rrdtool write plugin.
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Wed, 6 Dec 2006 20:24:56 +0000 (21:24 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Wed, 6 Dec 2006 20:24:56 +0000 (21:24 +0100)
Many functions have been moved from `common.c' to a new file `rrdtool.c'. The
new plugin compiles, but has not yet been testet.

src/Makefile.am
src/common.c
src/common.h
src/plugin.h
src/rrdtool.c [new file with mode: 0644]

index 638deb7..0d1bbc6 100644 (file)
@@ -31,9 +31,6 @@ endif
 
 # Link to these libraries..
 collectd_LDFLAGS = -export-dynamic
-if BUILD_WITH_RRDTOOL
-collectd_LDFLAGS += -lm -lrrd
-endif
 if BUILD_WITH_LIBRT
 collectd_LDFLAGS += -lrt
 endif
@@ -306,6 +303,14 @@ collectd_LDADD += "-dlopen" processes.la
 collectd_DEPENDENCIES += processes.la
 endif
 
+if BUILD_WITH_RRDTOOL
+pkglib_LTLIBRARIES += rrdtool.la
+rrdtool_la_SOURCES = rrdtool.c
+rrdtool_la_LDFLAGS = -module -avoid-version -lrrd
+collectd_LDADD += "-dlopen" rrdtool.la
+collectd_DEPENDENCIES += rrdtool.la
+endif
+
 if BUILD_MODULE_SENSORS
 pkglib_LTLIBRARIES += sensors.la
 sensors_la_SOURCES = sensors.c
index 5487b32..6da5e33 100644 (file)
@@ -35,48 +35,6 @@ extern int operating_mode;
 extern kstat_ctl_t *kc;
 #endif
 
-#ifdef HAVE_LIBRRD
-#if 0
-static char *rra_def[] =
-{
-               "RRA:AVERAGE:0.0:1:1500",
-               "RRA:AVERAGE:0.2:6:1500",
-               "RRA:AVERAGE:0.1:180:1680",
-               "RRA:AVERAGE:0.1:2160:1520",
-               "RRA:MIN:0.0:1:1500",
-               "RRA:MIN:0.2:6:1500",
-               "RRA:MIN:0.1:180:1680",
-               "RRA:MIN:0.1:2160:1520",
-               "RRA:MAX:0.0:1:1500",
-               "RRA:MAX:0.2:6:1500",
-               "RRA:MAX:0.1:180:1680",
-               "RRA:MAX:0.1:2160:1520",
-               NULL
-};
-static int rra_num = 12;
-#endif
-
-static int rra_timespans[] =
-{
-       3600,
-       86400,
-       604800,
-       2678400,
-       31622400,
-       0
-};
-static int rra_timespans_num = 5;
-
-static char *rra_types[] =
-{
-       "AVERAGE",
-       "MIN",
-       "MAX",
-       NULL
-};
-static int rra_types_num = 3;
-#endif /* HAVE_LIBRRD */
-
 void sstrncpy (char *d, const char *s, int len)
 {
        strncpy (d, s, len);
@@ -320,7 +278,7 @@ int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct times
        return (0);
 }
 
-static int check_create_dir (const char *file_orig)
+int check_create_dir (const char *file_orig)
 {
        struct stat statbuf;
 
@@ -424,89 +382,6 @@ static int check_create_dir (const char *file_orig)
        return (0);
 }
 
-/* * * * *
- * Magic *
- * * * * */
-#if HAVE_LIBRRD
-static int rra_get (char ***ret)
-{
-       static char **rra_def = NULL;
-       static int rra_num = 0;
-
-       int rra_max = rra_timespans_num * rra_types_num;
-
-       int step;
-       int rows;
-       int span;
-
-       int cdp_num;
-       int cdp_len;
-       int i, j;
-
-       char buffer[64];
-
-       if ((rra_num != 0) && (rra_def != NULL))
-       {
-               *ret = rra_def;
-               return (rra_num);
-       }
-
-       if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
-               return (-1);
-       memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
-
-       step = atoi (COLLECTD_STEP);
-       rows = atoi (COLLECTD_ROWS);
-
-       if ((step <= 0) || (rows <= 0))
-       {
-               *ret = NULL;
-               return (-1);
-       }
-
-       cdp_len = 0;
-       for (i = 0; i < rra_timespans_num; i++)
-       {
-               span = rra_timespans[i];
-
-               if ((span / step) < rows)
-                       continue;
-
-               if (cdp_len == 0)
-                       cdp_len = 1;
-               else
-                       cdp_len = (int) floor (((double) span) / ((double) (rows * step)));
-
-               cdp_num = (int) ceil (((double) span) / ((double) (cdp_len * step)));
-
-               for (j = 0; j < rra_types_num; j++)
-               {
-                       if (rra_num >= rra_max)
-                               break;
-
-                       if (snprintf (buffer, sizeof(buffer), "RRA:%s:%3.1f:%u:%u",
-                                               rra_types[j], COLLECTD_XFF,
-                                               cdp_len, cdp_num) >= sizeof (buffer))
-                       {
-                               syslog (LOG_ERR, "rra_get: Buffer would have been truncated.");
-                               continue;
-                       }
-
-                       rra_def[rra_num++] = sstrdup (buffer);
-               }
-       }
-
-#if COLLECT_DEBUG
-       DBG ("rra_num = %i", rra_num);
-       for (i = 0; i < rra_num; i++)
-               DBG ("  %s", rra_def[i]);
-#endif
-
-       *ret = rra_def;
-       return (rra_num);
-}
-#endif /* HAVE_LIBRRD */
-
 static int log_create_file (char *filename, char **ds_def, int ds_num)
 {
        FILE *log;
@@ -560,7 +435,7 @@ static int log_create_file (char *filename, char **ds_def, int ds_num)
        return 0;
 }
 
-static int log_update_file (char *host, char *file, char *values,
+int log_update_file (char *host, char *file, char *values,
                char **ds_def, int ds_num)
 {
        char *tmp;
@@ -640,121 +515,6 @@ static int log_update_file (char *host, char *file, char *values,
        return (0);
 } /* int log_update_file */
 
-#if HAVE_LIBRRD
-static int rrd_create_file (char *filename, char **ds_def, int ds_num)
-{
-       char **argv;
-       int argc;
-       char **rra_def;
-       int rra_num;
-       int i, j;
-       int status = 0;
-
-       if (check_create_dir (filename))
-               return (-1);
-
-       if ((rra_num = rra_get (&rra_def)) < 1)
-       {
-               syslog (LOG_ERR, "rra_create failed: Could not calculate RRAs");
-               return (-1);
-       }
-
-       argc = ds_num + rra_num + 4;
-
-       if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
-       {
-               syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
-               return (-1);
-       }
-
-       argv[0] = "create";
-       argv[1] = filename;
-       argv[2] = "-s";
-       argv[3] = COLLECTD_STEP;
-
-       j = 4;
-       for (i = 0; i < ds_num; i++)
-               argv[j++] = ds_def[i];
-       for (i = 0; i < rra_num; i++)
-               argv[j++] = rra_def[i];
-       argv[j] = NULL;
-
-       optind = 0; /* bug in librrd? */
-       rrd_clear_error ();
-       if (rrd_create (argc, argv) == -1)
-       {
-               syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
-               status = -1;
-       }
-
-       free (argv);
-
-       return (status);
-}
-#endif /* HAVE_LIBRRD */
-
-int rrd_update_file (char *host, char *file, char *values,
-               char **ds_def, int ds_num)
-{
-#if HAVE_LIBRRD
-       struct stat statbuf;
-       char full_file[1024];
-       char *argv[4] = { "update", full_file, values, NULL };
-#endif /* HAVE_LIBRRD */
-
-       /* I'd rather have a function `common_update_file' to make this
-        * decission, but for that we'd need to touch all plugins.. */
-       if (operating_mode == MODE_LOG)
-               return (log_update_file (host, file, values,
-                                       ds_def, ds_num));
-
-#if HAVE_LIBRRD
-       /* host == NULL => local mode */
-       if (host != NULL)
-       {
-               if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
-                       return (-1);
-       }
-       else
-       {
-               if (snprintf (full_file, 1024, "%s", file) >= 1024)
-                       return (-1);
-       }
-
-       if (stat (full_file, &statbuf) == -1)
-       {
-               if (errno == ENOENT)
-               {
-                       if (rrd_create_file (full_file, ds_def, ds_num))
-                               return (-1);
-               }
-               else
-               {
-                       syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
-                       return (-1);
-               }
-       }
-       else if (!S_ISREG (statbuf.st_mode))
-       {
-               syslog (LOG_ERR, "stat %s: Not a regular file!", full_file);
-               return (-1);
-       }
-
-       optind = 0; /* bug in librrd? */
-       rrd_clear_error ();
-       if (rrd_update (3, argv) == -1)
-       {
-               syslog (LOG_WARNING, "rrd_update failed: %s: %s", full_file, rrd_get_error ());
-               return (-1);
-       }
-       return (0);
-/* #endif HAVE_LIBRRD */
-
-#else
-       syslog (LOG_ERR, "`rrd_update_file' was called, but collectd isn't linked against librrd!");
-       return (-1);
-#endif
-}
 
 #ifdef HAVE_LIBKSTAT
 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
index 2be2ff5..8f32b22 100644 (file)
@@ -145,8 +145,7 @@ int escape_slashes (char *buf, int buf_len);
 /* FIXME: `timeval_sub_timespec' needs a description */
 int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret);
 
-int rrd_update_file (char *host, char *file, char *values,
-               char **ds_def, int ds_num);
+int check_create_dir (const char *file_orig);
 
 #ifdef HAVE_LIBKSTAT
 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name);
index 93bf029..611fa57 100644 (file)
@@ -45,6 +45,7 @@ struct value_list_s
 {
        value_t *values;
        int      values_len;
+       char     host[DATA_MAX_NAME_LEN];
        char     plugin[DATA_MAX_NAME_LEN];
        char     plugin_instance[DATA_MAX_NAME_LEN];
        char     type_instance[DATA_MAX_NAME_LEN];
diff --git a/src/rrdtool.c b/src/rrdtool.c
new file mode 100644 (file)
index 0000000..7bf407a
--- /dev/null
@@ -0,0 +1,406 @@
+/**
+ * collectd - src/rrdtool.c
+ * Copyright (C) 2006  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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+
+/*
+ * This weird macro cascade forces the glibc to define `NAN'. I don't know
+ * another way to solve this, so more intelligent solutions are welcome. -octo
+ */
+#ifndef __USE_ISOC99
+# define DISABLE__USE_ISOC99 1
+# define __USE_ISOC99 1
+#endif
+#include <math.h>
+#ifdef DISABLE__USE_ISOC99
+# undef DISABLE__USE_ISOC99
+# undef __USE_ISOC99
+#endif
+
+static int rra_timespans[] =
+{
+       3600,
+       86400,
+       604800,
+       2678400,
+       31622400,
+       0
+};
+static int rra_timespans_num = 5;
+
+static char *rra_types[] =
+{
+       "AVERAGE",
+       "MIN",
+       "MAX",
+       NULL
+};
+static int rra_types_num = 3;
+
+/* * * * * * * * * *
+ * WARNING:  Magic *
+ * * * * * * * * * */
+static int rra_get (char ***ret)
+{
+       static char **rra_def = NULL;
+       static int rra_num = 0;
+
+       int rra_max = rra_timespans_num * rra_types_num;
+
+       int step;
+       int rows;
+       int span;
+
+       int cdp_num;
+       int cdp_len;
+       int i, j;
+
+       char buffer[64];
+
+       if ((rra_num != 0) && (rra_def != NULL))
+       {
+               *ret = rra_def;
+               return (rra_num);
+       }
+
+       if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
+               return (-1);
+       memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
+
+       step = atoi (COLLECTD_STEP);
+       rows = atoi (COLLECTD_ROWS);
+
+       if ((step <= 0) || (rows <= 0))
+       {
+               *ret = NULL;
+               return (-1);
+       }
+
+       cdp_len = 0;
+       for (i = 0; i < rra_timespans_num; i++)
+       {
+               span = rra_timespans[i];
+
+               if ((span / step) < rows)
+                       continue;
+
+               if (cdp_len == 0)
+                       cdp_len = 1;
+               else
+                       cdp_len = (int) floor (((double) span) / ((double) (rows * step)));
+
+               cdp_num = (int) ceil (((double) span) / ((double) (cdp_len * step)));
+
+               for (j = 0; j < rra_types_num; j++)
+               {
+                       if (rra_num >= rra_max)
+                               break;
+
+                       if (snprintf (buffer, sizeof(buffer), "RRA:%s:%3.1f:%u:%u",
+                                               rra_types[j], COLLECTD_XFF,
+                                               cdp_len, cdp_num) >= sizeof (buffer))
+                       {
+                               syslog (LOG_ERR, "rra_get: Buffer would have been truncated.");
+                               continue;
+                       }
+
+                       rra_def[rra_num++] = sstrdup (buffer);
+               }
+       }
+
+#if COLLECT_DEBUG
+       DBG ("rra_num = %i", rra_num);
+       for (i = 0; i < rra_num; i++)
+               DBG ("  %s", rra_def[i]);
+#endif
+
+       *ret = rra_def;
+       return (rra_num);
+}
+
+static void ds_free (int ds_num, char **ds_def)
+{
+       int i;
+
+       for (i = 0; i < ds_num; i++)
+               if (ds_def[i] != NULL)
+                       free (ds_def[i]);
+       free (ds_def);
+}
+
+static int ds_get (char ***ret, const data_set_t *ds)
+{
+       char **ds_def;
+       int ds_num;
+
+       char min[32];
+       char max[32];
+       char buffer[128];
+
+       ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
+       if (ds_def == NULL)
+       {
+               syslog (LOG_ERR, "rrdtool plugin: malloc failed: %s",
+                               strerror (errno));
+               return (-1);
+       }
+       memset (ds_def, '\0', ds->ds_num * sizeof (char *));
+
+       for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
+       {
+               data_source_t *d = ds->ds + ds_num;
+               char *type;
+               int status;
+
+               ds_def[ds_num] = NULL;
+
+               if (d->type == DS_TYPE_COUNTER)
+                       type = "COUNTER";
+               else if (d->type == DS_TYPE_GAUGE)
+                       type = "GAUGE";
+               else
+               {
+                       syslog (LOG_ERR, "rrdtool plugin: Unknown DS type: %i",
+                                       d->type);
+                       break;
+               }
+
+               if (d->min == NAN)
+               {
+                       strcpy (min, "U");
+               }
+               else
+               {
+                       snprintf (buffer, sizeof (min), "%lf", d->min);
+                       min[sizeof (min) - 1] = '\0';
+               }
+
+               if (d->max == NAN)
+               {
+                       strcpy (max, "U");
+               }
+               else
+               {
+                       snprintf (buffer, sizeof (max), "%lf", d->max);
+                       max[sizeof (max) - 1] = '\0';
+               }
+
+               status = snprintf (buffer, sizeof (buffer),
+                               "DS:%s:%s:%s:%s:%s",
+                               d->name, type, COLLECTD_HEARTBEAT,
+                               min, max);
+               if ((status < 1) || (status >= sizeof (buffer)))
+                       break;
+
+               ds_def[ds_num] = sstrdup (buffer);
+               ds_num++;
+       } /* for ds_num = 0 .. ds->ds_num */
+
+       if (ds_num != ds->ds_num)
+       {
+               ds_free (ds_num, ds_def);
+               return (-1);
+       }
+
+       *ret = ds_def;
+       return (ds_num);
+}
+
+static int rrd_create_file (char *filename, const data_set_t *ds)
+{
+       char **argv;
+       int argc;
+       char **rra_def;
+       int rra_num;
+       char **ds_def;
+       int ds_num;
+       int i, j;
+       int status = 0;
+
+       if (check_create_dir (filename))
+               return (-1);
+
+       if ((rra_num = rra_get (&rra_def)) < 1)
+       {
+               syslog (LOG_ERR, "rrd_create_file failed: Could not calculate RRAs");
+               return (-1);
+       }
+
+       if ((ds_num = ds_get (&ds_def, ds)) < 1)
+       {
+               syslog (LOG_ERR, "rrd_create_file failed: Could not calculate DSes");
+               return (-1);
+       }
+
+       argc = ds_num + rra_num + 4;
+
+       if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
+       {
+               syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
+               return (-1);
+       }
+
+       argv[0] = "create";
+       argv[1] = filename;
+       argv[2] = "-s";
+       argv[3] = COLLECTD_STEP;
+
+       j = 4;
+       for (i = 0; i < ds_num; i++)
+               argv[j++] = ds_def[i];
+       for (i = 0; i < rra_num; i++)
+               argv[j++] = rra_def[i];
+       argv[j] = NULL;
+
+       optind = 0; /* bug in librrd? */
+       rrd_clear_error ();
+       if (rrd_create (argc, argv) == -1)
+       {
+               syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
+               status = -1;
+       }
+
+       free (argv);
+       ds_free (ds_num, ds_def);
+
+       return (status);
+}
+
+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;
+       int i;
+
+       memset (buffer, '\0', sizeof (buffer_len));
+       buffer[0] = 'N';
+       offset = 1;
+
+       for (i = 0; i < ds->ds_num; i++)
+       {
+               if ((ds->ds[i].type != DS_TYPE_COUNTER)
+                               && (ds->ds[i].type != DS_TYPE_GAUGE))
+                       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,
+                                       ":%lf", vl->values[i].gauge);
+
+               if ((status < 1) || (status >= (buffer_len - offset)))
+                       return (-1);
+
+               offset += status;
+       } /* for ds->ds_num */
+
+       return (0);
+} /* int value_list_to_string */
+
+static int value_list_to_filename (char *buffer, int buffer_len,
+               const data_set_t *ds, const value_list_t *vl)
+{
+       int offset = 0;
+       int status;
+
+       status = snprintf (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,
+                               "%s-%s/", vl->plugin, vl->plugin_instance);
+       else
+               status = snprintf (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.rrd", ds->type, vl->type_instance);
+       else
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s.rrd", ds->type);
+       if ((status < 1) || (status >= buffer_len - offset))
+               return (-1);
+       offset += status;
+
+       return (0);
+} /* int value_list_to_filename */
+
+static int rrd_write (const data_set_t *ds, const value_list_t *vl)
+{
+       struct stat statbuf;
+       char        filename[512];
+       char        values[512];
+       char       *argv[4] = { "update", filename, values, NULL };
+
+       if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+               return (-1);
+
+       if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
+               return (-1);
+
+       if (stat (filename, &statbuf) == -1)
+       {
+               if (errno == ENOENT)
+               {
+                       if (rrd_create_file (filename, ds))
+                               return (-1);
+               }
+               else
+               {
+                       syslog (LOG_ERR, "stat(%s) failed: %s",
+                                       filename, strerror (errno));
+                       return (-1);
+               }
+       }
+       else if (!S_ISREG (statbuf.st_mode))
+       {
+               syslog (LOG_ERR, "stat(%s): Not a regular file!",
+                               filename);
+               return (-1);
+       }
+
+       optind = 0; /* bug in librrd? */
+       rrd_clear_error ();
+       if (rrd_update (3, argv) == -1)
+       {
+               syslog (LOG_WARNING, "rrd_update failed: %s: %s",
+                               filename, rrd_get_error ());
+               return (-1);
+       }
+       return (0);
+} /* int rrd_update_file */
+
+void module_register (void)
+{
+       plugin_register_write ("rrdtool", rrd_write);
+}