X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Frrdtool.c;h=ea96290555670542dfdcd116f90006dc85cf1c50;hb=034a237b11bf1a8809751f103b01ff1c3859ec2b;hp=91be7b616754b730fef9dd57f5676ddb4b443dfc;hpb=6360474f4aa35dd1a587b6148ff88a23e6155132;p=collectd.git diff --git a/src/rrdtool.c b/src/rrdtool.c index 91be7b61..ea962905 100644 --- a/src/rrdtool.c +++ b/src/rrdtool.c @@ -1,6 +1,6 @@ /** * collectd - src/rrdtool.c - * Copyright (C) 2006 Florian octo Forster + * Copyright (C) 2006,2007 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 @@ -23,20 +23,9 @@ #include "plugin.h" #include "common.h" #include "utils_avltree.h" -#include "utils_debug.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 +#if HAVE_PTHREAD_H +# include #endif /* @@ -47,6 +36,7 @@ struct rrd_cache_s int values_num; char **values; time_t first_value; + time_t last_value; }; typedef struct rrd_cache_s rrd_cache_t; @@ -59,35 +49,45 @@ static int rra_timespans[] = 86400, 604800, 2678400, - 31622400, - 0 + 31622400 }; -static int rra_timespans_num = 5; +static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans); + +static int *rra_timespans_custom = NULL; +static int rra_timespans_custom_num = 0; static char *rra_types[] = { "AVERAGE", "MIN", - "MAX", - NULL + "MAX" }; -static int rra_types_num = 3; +static int rra_types_num = STATIC_ARRAY_SIZE (rra_types); static const char *config_keys[] = { "CacheTimeout", "CacheFlush", "DataDir", - NULL + "StepSize", + "HeartBeat", + "RRARows", + "RRATimespan", + "XFF" }; -static int config_keys_num = 3; +static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); -static char *datadir = NULL; +static char *datadir = NULL; +static int stepsize = 0; +static int heartbeat = 0; +static int rrarows = 1200; +static double xff = 0.1; static int cache_timeout = 0; static int cache_flush_timeout = 0; static time_t cache_flush_last; static avl_tree_t *cache = NULL; +static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; /* * * * * * * * * * * WARNING: Magic * @@ -97,10 +97,11 @@ 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 *rts; + int rts_num; + + int rra_max; - int step; - int rows; int span; int cdp_num; @@ -115,44 +116,57 @@ static int rra_get (char ***ret) return (rra_num); } + /* Use the configured timespans or fall back to the built-in defaults */ + if (rra_timespans_custom_num != 0) + { + rts = rra_timespans_custom; + rts_num = rra_timespans_custom_num; + } + else + { + rts = rra_timespans; + rts_num = rra_timespans_num; + } + + rra_max = rts_num * rra_types_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)) + if ((stepsize <= 0) || (rrarows <= 0)) { *ret = NULL; return (-1); } cdp_len = 0; - for (i = 0; i < rra_timespans_num; i++) + for (i = 0; i < rts_num; i++) { - span = rra_timespans[i]; + span = rts[i]; - if ((span / step) < rows) + if ((span / stepsize) < rrarows) continue; if (cdp_len == 0) cdp_len = 1; else - cdp_len = (int) floor (((double) span) / ((double) (rows * step))); + cdp_len = (int) floor (((double) span) + / ((double) (rrarows * stepsize))); - cdp_num = (int) ceil (((double) span) / ((double) (cdp_len * step))); + cdp_num = (int) ceil (((double) span) + / ((double) (cdp_len * stepsize))); 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, + if (snprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u", + rra_types[j], xff, cdp_len, cdp_num) >= sizeof (buffer)) { - syslog (LOG_ERR, "rra_get: Buffer would have been truncated."); + ERROR ("rra_get: Buffer would have been truncated."); continue; } @@ -161,9 +175,9 @@ static int rra_get (char ***ret) } #if COLLECT_DEBUG - DBG ("rra_num = %i", rra_num); + DEBUG ("rra_num = %i", rra_num); for (i = 0; i < rra_num; i++) - DBG (" %s", rra_def[i]); + DEBUG (" %s", rra_def[i]); #endif *ret = rra_def; @@ -189,13 +203,14 @@ static int ds_get (char ***ret, const data_set_t *ds) char max[32]; char buffer[128]; - DBG ("ds->ds_num = %i", ds->ds_num); + DEBUG ("ds->ds_num = %i", ds->ds_num); ds_def = (char **) malloc (ds->ds_num * sizeof (char *)); if (ds_def == NULL) { - syslog (LOG_ERR, "rrdtool plugin: malloc failed: %s", - strerror (errno)); + char errbuf[1024]; + ERROR ("rrdtool plugin: malloc failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } memset (ds_def, '\0', ds->ds_num * sizeof (char *)); @@ -214,12 +229,12 @@ static int ds_get (char ***ret, const data_set_t *ds) type = "GAUGE"; else { - syslog (LOG_ERR, "rrdtool plugin: Unknown DS type: %i", + ERROR ("rrdtool plugin: Unknown DS type: %i", d->type); break; } - if (d->min == NAN) + if (isnan (d->min)) { strcpy (min, "U"); } @@ -229,7 +244,7 @@ static int ds_get (char ***ret, const data_set_t *ds) min[sizeof (min) - 1] = '\0'; } - if (d->max == NAN) + if (isnan (d->max)) { strcpy (max, "U"); } @@ -240,8 +255,8 @@ static int ds_get (char ***ret, const data_set_t *ds) } status = snprintf (buffer, sizeof (buffer), - "DS:%s:%s:%s:%s:%s", - d->name, type, COLLECTD_HEARTBEAT, + "DS:%s:%s:%i:%s:%s", + d->name, type, heartbeat, min, max); if ((status < 1) || (status >= sizeof (buffer))) break; @@ -252,9 +267,9 @@ static int ds_get (char ***ret, const data_set_t *ds) #if COLLECT_DEBUG { int i; - DBG ("ds_num = %i", ds_num); + DEBUG ("ds_num = %i", ds_num); for (i = 0; i < ds_num; i++) - DBG (" %s", ds_def[i]); + DEBUG (" %s", ds_def[i]); } #endif @@ -277,6 +292,7 @@ static int rrd_create_file (char *filename, const data_set_t *ds) char **ds_def; int ds_num; int i, j; + char stepsize_str[16]; int status = 0; if (check_create_dir (filename)) @@ -284,13 +300,13 @@ static int rrd_create_file (char *filename, const data_set_t *ds) if ((rra_num = rra_get (&rra_def)) < 1) { - syslog (LOG_ERR, "rrd_create_file failed: Could not calculate RRAs"); + ERROR ("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"); + ERROR ("rrd_create_file failed: Could not calculate DSes"); return (-1); } @@ -298,14 +314,24 @@ static int rrd_create_file (char *filename, const data_set_t *ds) if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL) { - syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno)); + char errbuf[1024]; + ERROR ("rrd_create failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + return (-1); + } + + status = snprintf (stepsize_str, sizeof (stepsize_str), + "%i", stepsize); + if ((status < 1) || (status >= sizeof (stepsize_str))) + { + ERROR ("rrdtool plugin: snprintf failed."); return (-1); } argv[0] = "create"; argv[1] = filename; argv[2] = "-s"; - argv[3] = COLLECTD_STEP; + argv[3] = stepsize_str; j = 4; for (i = 0; i < ds_num; i++) @@ -318,7 +344,7 @@ static int rrd_create_file (char *filename, const data_set_t *ds) rrd_clear_error (); if (rrd_create (argc, argv) == -1) { - syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ()); + ERROR ("rrd_create failed: %s: %s", filename, rrd_get_error ()); status = -1; } @@ -409,7 +435,7 @@ static int value_list_to_filename (char *buffer, int buffer_len, } /* int value_list_to_filename */ static rrd_cache_t *rrd_cache_insert (const char *filename, - const char *value) + const char *value, time_t value_time) { rrd_cache_t *rc = NULL; int new_rc = 0; @@ -425,15 +451,25 @@ static rrd_cache_t *rrd_cache_insert (const char *filename, rc->values_num = 0; rc->values = NULL; rc->first_value = 0; + rc->last_value = 0; new_rc = 1; } + if (rc->last_value >= value_time) + { + WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)", + (unsigned int) rc->last_value, + (unsigned int) value_time); + return (NULL); + } + rc->values = (char **) realloc ((void *) rc->values, (rc->values_num + 1) * sizeof (char *)); if (rc->values == NULL) { - syslog (LOG_ERR, "rrdtool plugin: realloc failed: %s", - strerror (errno)); + char errbuf[1024]; + ERROR ("rrdtool plugin: realloc failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); if (cache != NULL) { void *cache_key = NULL; @@ -449,7 +485,8 @@ static rrd_cache_t *rrd_cache_insert (const char *filename, rc->values_num++; if (rc->values_num == 1) - rc->first_value = time (NULL); + rc->first_value = value_time; + rc->last_value = value_time; /* Insert if this is the first value */ if ((cache != NULL) && (new_rc == 1)) @@ -458,8 +495,9 @@ static rrd_cache_t *rrd_cache_insert (const char *filename, if (cache_key == NULL) { - syslog (LOG_ERR, "rrdtool plugin: strdup failed: %s", - strerror (errno)); + char errbuf[1024]; + ERROR ("rrdtool plugin: strdup failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); sfree (rc->values[0]); sfree (rc->values); sfree (rc); @@ -469,7 +507,8 @@ static rrd_cache_t *rrd_cache_insert (const char *filename, avl_insert (cache, cache_key, rc); } - DBG ("rrd_cache_insert (%s, %s) = %p", filename, value, (void *) rc); + DEBUG ("rrd_cache_insert (%s, %s, %u) = %p", filename, value, + (unsigned int) value_time, (void *) rc); return (rc); } /* rrd_cache_t *rrd_cache_insert */ @@ -484,6 +523,9 @@ static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc) int i; + if (rc->values_num < 1) + return (0); + argc = rc->values_num + 2; argv = (char **) malloc ((argc + 1) * sizeof (char *)); if (argv == NULL) @@ -501,15 +543,20 @@ static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc) memcpy (argv + 2, rc->values, rc->values_num * sizeof (char *)); argv[argc] = NULL; - DBG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv); + DEBUG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv); optind = 0; /* bug in librrd? */ rrd_clear_error (); status = rrd_update (argc, argv); + if (status != 0) + { + WARNING ("rrd_update failed: %s: %s", + filename, rrd_get_error ()); + status = -1; + } free (argv); free (fn); - /* Free the value list of `rc' */ for (i = 0; i < rc->values_num; i++) free (rc->values[i]); @@ -517,14 +564,7 @@ static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc) rc->values = NULL; rc->values_num = 0; - if (status != 0) - { - syslog (LOG_WARNING, "rrd_update failed: %s: %s", - filename, rrd_get_error ()); - return (-1); - } - - return (0); + return (status); } /* int rrd_write_cache_entry */ static void rrd_cache_flush (int timeout) @@ -542,7 +582,7 @@ static void rrd_cache_flush (int timeout) if (cache == NULL) return; - DBG ("Flushing cache, timeout = %i", timeout); + DEBUG ("Flushing cache, timeout = %i", timeout); now = time (NULL); @@ -550,17 +590,18 @@ static void rrd_cache_flush (int timeout) iter = avl_get_iterator (cache); while (avl_iterator_next (iter, (void *) &key, (void *) &rc) == 0) { - DBG ("key = %s; age = %i;", key, now - rc->first_value); + DEBUG ("key = %s; age = %i;", key, now - rc->first_value); if ((now - rc->first_value) >= timeout) { keys = (char **) realloc ((void *) keys, (keys_num + 1) * sizeof (char *)); if (keys == NULL) { - DBG ("realloc failed: %s", strerror (errno)); - syslog (LOG_ERR, "rrdtool plugin: " + char errbuf[1024]; + ERROR ("rrdtool plugin: " "realloc failed: %s", - strerror (errno)); + sstrerror (errno, errbuf, + sizeof (errbuf))); avl_iterator_destroy (iter); return; } @@ -574,7 +615,7 @@ static void rrd_cache_flush (int timeout) { if (avl_remove (cache, keys[i], (void *) &key, (void *) &rc) != 0) { - DBG ("avl_remove (%s) failed.", keys[i]); + DEBUG ("avl_remove (%s) failed.", keys[i]); continue; } @@ -586,7 +627,7 @@ static void rrd_cache_flush (int timeout) } /* for (i = 0..keys_num) */ free (keys); - DBG ("Flushed %i value(s)", keys_num); + DEBUG ("Flushed %i value(s)", keys_num); cache_flush_last = now; } /* void rrd_cache_flush */ @@ -614,33 +655,40 @@ static int rrd_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); } - rc = rrd_cache_insert (filename, values); + pthread_mutex_lock (&cache_lock); + rc = rrd_cache_insert (filename, values, vl->time); if (rc == NULL) + { + pthread_mutex_unlock (&cache_lock); return (-1); + } if (cache == NULL) { rrd_write_cache_entry (filename, rc); /* rc's value-list is free's by `rrd_write_cache_entry' */ sfree (rc); + pthread_mutex_unlock (&cache_lock); return (0); } now = time (NULL); - DBG ("age (%s) = %i", filename, now - rc->first_value); + DEBUG ("age (%s) = %i", filename, now - rc->first_value); /* `rc' is not free'd here, because we'll likely reuse it. If not, then * the next flush will remove this entry. */ @@ -650,14 +698,15 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl) if ((now - cache_flush_last) >= cache_flush_timeout) rrd_cache_flush (cache_flush_timeout); + pthread_mutex_unlock (&cache_lock); return (0); } /* int rrd_write */ -static int rrd_config (const char *key, const char *val) +static int rrd_config (const char *key, const char *value) { if (strcasecmp ("CacheTimeout", key) == 0) { - int tmp = atoi (val); + int tmp = atoi (value); if (tmp < 0) { fprintf (stderr, "rrdtool: `CacheTimeout' must " @@ -668,7 +717,7 @@ static int rrd_config (const char *key, const char *val) } else if (strcasecmp ("CacheFlush", key) == 0) { - int tmp = atoi (val); + int tmp = atoi (value); if (tmp < 0) { fprintf (stderr, "rrdtool: `CacheFlush' must " @@ -681,7 +730,7 @@ static int rrd_config (const char *key, const char *val) { if (datadir != NULL) free (datadir); - datadir = strdup (val); + datadir = strdup (value); if (datadir != NULL) { int len = strlen (datadir); @@ -697,6 +746,82 @@ static int rrd_config (const char *key, const char *val) } } } + else if (strcasecmp ("StepSize", key) == 0) + { + int tmp = atoi (value); + if (tmp <= 0) + { + fprintf (stderr, "rrdtool: `StepSize' must " + "be greater than 0.\n"); + return (1); + } + stepsize = tmp; + } + else if (strcasecmp ("HeartBeat", key) == 0) + { + int tmp = atoi (value); + if (tmp <= 0) + { + fprintf (stderr, "rrdtool: `HeartBeat' must " + "be greater than 0.\n"); + return (1); + } + heartbeat = tmp; + } + else if (strcasecmp ("RRARows", key) == 0) + { + int tmp = atoi (value); + if (tmp <= 0) + { + fprintf (stderr, "rrdtool: `RRARows' must " + "be greater than 0.\n"); + return (1); + } + rrarows = tmp; + } + else if (strcasecmp ("RRATimespan", key) == 0) + { + char *saveptr = NULL; + char *dummy; + char *ptr; + char *value_copy; + int *tmp_alloc; + + value_copy = strdup (value); + if (value_copy == NULL) + return (1); + + dummy = value_copy; + while ((ptr = strtok_r (dummy, ", \t", &saveptr)) != NULL) + { + dummy = NULL; + + tmp_alloc = realloc (rra_timespans_custom, + sizeof (int) * (rra_timespans_custom_num + 1)); + if (tmp_alloc == NULL) + { + fprintf (stderr, "rrdtool: realloc failed.\n"); + free (value_copy); + return (1); + } + rra_timespans_custom = tmp_alloc; + rra_timespans_custom[rra_timespans_custom_num] = atoi (ptr); + if (rra_timespans_custom[rra_timespans_custom_num] != 0) + rra_timespans_custom_num++; + } /* while (strtok_r) */ + free (value_copy); + } + else if (strcasecmp ("XFF", key) == 0) + { + double tmp = atof (value); + if ((tmp < 0.0) || (tmp >= 1.0)) + { + fprintf (stderr, "rrdtool: `XFF' must " + "be in the range 0 to 1 (exclusive)."); + return (1); + } + xff = tmp; + } else { return (-1); @@ -706,16 +831,33 @@ static int rrd_config (const char *key, const char *val) static int rrd_shutdown (void) { + pthread_mutex_lock (&cache_lock); rrd_cache_flush (-1); if (cache != NULL) avl_destroy (cache); cache = NULL; + pthread_mutex_unlock (&cache_lock); return (0); } /* int rrd_shutdown */ static int rrd_init (void) { + if (stepsize <= 0) + stepsize = interval_g; + if (heartbeat <= 0) + heartbeat = 2 * interval_g; + + if (heartbeat < interval_g) + WARNING ("rrdtool plugin: Your `heartbeat' is " + "smaller than your `interval'. This will " + "likely cause problems."); + else if (stepsize < interval_g) + WARNING ("rrdtool plugin: Your `stepsize' is " + "smaller than your `interval'. This will " + "create needlessly big RRD-files."); + + pthread_mutex_lock (&cache_lock); if (cache_timeout < 2) { cache_timeout = 0; @@ -730,6 +872,13 @@ static int rrd_init (void) cache_flush_last = time (NULL); plugin_register_shutdown ("rrdtool", rrd_shutdown); } + pthread_mutex_unlock (&cache_lock); + + DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;" + " heartbeat = %i; rrarows = %i; xff = %lf;", + (datadir == NULL) ? "(null)" : datadir, + stepsize, heartbeat, rrarows, xff); + return (0); } /* int rrd_init */