From: Florian Forster Date: Wed, 6 Dec 2006 20:24:56 +0000 (+0100) Subject: rrdtool plugin: First implementation of an rrdtool write plugin. X-Git-Tag: collectd-4.0.0~252 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=9f0557d03a0be5a857b5d4e52540d07eb2cc2890;p=collectd.git rrdtool plugin: First implementation of an rrdtool write plugin. Many functions have been moved from `common.c' to a new file `rrdtool.c'. The new plugin compiles, but has not yet been testet. --- diff --git a/src/Makefile.am b/src/Makefile.am index 638deb7d..0d1bbc67 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/common.c b/src/common.c index 5487b326..6da5e33c 100644 --- a/src/common.c +++ b/src/common.c @@ -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) diff --git a/src/common.h b/src/common.h index 2be2ff50..8f32b227 100644 --- a/src/common.h +++ b/src/common.h @@ -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); diff --git a/src/plugin.h b/src/plugin.h index 93bf0294..611fa572 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -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 index 00000000..7bf407ab --- /dev/null +++ b/src/rrdtool.c @@ -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 + **/ + +#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 +#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); +}