Merge branch 'sh/collectd-4.5' into sh/collectd-4.6
authorSebastian Harl <sh@tokkee.org>
Sat, 7 Mar 2009 17:03:42 +0000 (18:03 +0100)
committerSebastian Harl <sh@tokkee.org>
Sat, 7 Mar 2009 17:03:42 +0000 (18:03 +0100)
Conflicts:
contrib/collection3/lib/Collectd/Graph/Common.pm
src/postgresql_default.conf

1  2 
README
src/postgresql_default.conf
src/rrdtool.c
src/snmp.c

diff --combined README
--- 1/README
--- 2/README
+++ b/README
@@@ -33,13 -33,6 +33,13 @@@ Feature
        Batterycharge, -current and voltage of ACPI and PMU based laptop
        batteries.
  
 +    - curl
 +      Parse statistics from websites using regular expressions.
 +
 +    - bind
 +      Name server and resolver statistics from the `statistics-channel'
 +      interface of BIND 9.5, 9,6 and later.
 +
      - cpu
        CPU utilization: Time spent in the system, user, nice, idle, and related
        states.
      - cpufreq
        CPU frequency (For laptops with speed step or a similar technology)
  
 +    - dbi
 +      Executes SQL statements on various databases and interprets the returned
 +      data.
 +
      - df
        Mountpoint usage (Basically the values `df(1)' delivers)
  
@@@ -87,9 -76,6 +87,9 @@@
        Iptables' counters: Number of bytes that were matched by a certain
        iptables rule.
  
 +    - ipmi
 +      IPMI (Intelligent Platform Management Interface) sensors information.
 +
      - ipvs
        IPVS connection statistics (number of connections, octets and packets
        for each service and destination).
        Read onewire sensors using the owcapu library of the owfs project.
        Please read in collectd.conf(5) why this plugin is experimental.
  
 +    - openvpn
 +      RX and TX of each client in openvpn-status.log (status-version 2).
 +      <http://openvpn.net/index.php/documentation/howto.html>
 +
 +    - oracle
 +      Query data from an Oracle database.
 +
      - perl
        The perl plugin implements a Perl-interpreter into collectd. You can
        write your own plugins in Perl and return arbitrary values using this
        PostgreSQL database statistics: active server connections, transaction
        numbers, block IO, table row manipulations.
  
 +    - powerdns
 +      PowerDNS name server statistics.
 +
      - processes
        Process counts: Number of running, sleeping, zombie, ... processes.
  
 +    - rrdcached
 +      RRDtool caching daemon (RRDcacheD) statistics.
 +
      - sensors
        System sensors, accessed using lm_sensors: Voltages, temperatures and
        fan rotation speeds.
      - tcpconns
        Number of TCP connections to specific local and remote ports.
  
 +    - teamspeak2
 +      TeamSpeak2 server statistics.
 +
 +    - thermal
 +      Linux ACPI thermal zone information.
 +
      - users
        Users currently logged in.
  
        you can easily do weird stuff with the plugins we didn't dare think of
        ;) See collectd-perl(5).
  
 +    - rrdcached
 +      Output to round-robin-database (RRD) files using the RRDtool caching
 +      daemon (RRDcacheD) - see rrdcached(1). That daemon provides a general
 +      implementation of the caching done by the `rrdtool' plugin.
 +
      - rrdtool
        Output to round-robin-database (RRD) files using librrd. See rrdtool(1).
        This is likely the most popular destination for such values. Since
        Notifications are propagated to plugins written in Perl as well.
        See collectd-perl(5).
  
 +  * Value processing can be controlled using the "filter chain" infrastructure
 +    and "matches" and "targets". The following plugins are available:
 +
 +    - match_regex
 +      Match values by their identifier based on regular expressions.
 +
 +    - match_timediff
 +      Match values with an invalid timestamp.
 +
 +    - match_value
 +      Select values by their data sources' values.
 +
 +    - target_notification
 +      Create and dispatch a notification.
 +
 +    - target_replace
 +      Replace parts of an identifier using regular expressions.
 +
 +    - target_set
 +      Set (overwrite) entire parts of an identifier.
 +
    * Miscellaneous plugins:
  
      - uuid
      since collectd is programmed multithreaded it benefits from hyperthreading
      and multicore processors and makes sure that the daemon isn't idle if only
      one plugins waits for an IO-operation to complete.
 -    
 +
    * Once set up, hardly any maintenance is necessary. Setup is kept as easy
      as possible and the default values should be okay for most users.
  
@@@ -398,104 -339,76 +398,104 @@@ Prerequisite
    * CoreFoundation.framework and IOKit.framework (optional)
      For compiling on Darwin in general and the `apple_sensors' plugin in
      particular.
 +    <http://developer.apple.com/corefoundation/>
 +
 +  * libclntsh (optional)
 +    Used by the `oracle' plugin.
  
    * libcurl (optional)
 -    If you want to use the `apache', `ascent', or `nginx' plugin.
 +    If you want to use the `apache', `ascent', `curl' or `nginx' plugin.
 +    <http://curl.haxx.se/>
 +
 +  * libdbi (optional)
 +    Used by the `dbi' plugin to connect to various databases.
 +    <http://libdbi.sourceforge.net/>
  
    * libesmtp (optional)
      For the `notify_email' plugin.
 +    <http://www.stafford.uklinux.net/libesmtp/>
  
    * libhal (optional)
      If present, the uuid plugin will check for UUID from HAL.
 +    <http://hal.freedesktop.org/>
  
 -  * libiptc (optional)
 +  * libiptc (optional, if not found a version shipped with this distribution
 +    can be used if the Linux kernel headers are available)
      For querying iptables counters.
 +    <http://netfilter.org/>
  
    * libmysqlclient (optional)
      Unsurprisingly used by the `mysql' plugin.
 +    <http://dev.mysql.com/>
  
    * libnetlink (optional)
      Used, obviously, for the `netlink' plugin.
 +    <http://www.linuxfoundation.org/en/Net:Iproute2>
  
    * libnetsnmp (optional)
      For the `snmp' plugin.
 +    <http://www.net-snmp.org/>
  
    * libnotify (optional)
      For the `notify_desktop' plugin.
 +    <http://www.galago-project.org/>
  
    * liboping (optional, if not found a version shipped with this distribution
      can be used)
      Used by the `ping' plugin to send and receive ICMP packets.
 +    <http://verplant.org/liboping/>
  
    * libowcapi (optional)
      Used by the `onewire' plugin to read values from onewire sensors (or the
      owserver(1) daemon).
 +    <http://www.owfs.org/>
  
    * libpcap (optional)
      Used to capture packets by the `dns' plugin.
 +    <http://www.tcpdump.org/>
  
    * libperl (optional)
      Obviously used by the `perl' plugin. The library has to be compiled with
      ithread support (introduced in Perl 5.6.0).
 +    <http://www.perl.org/>
  
    * libpq (optional)
      The PostgreSQL C client library used by the `postgresql' plugin.
 +    <http://www.postgresql.org/>
  
 -  * librrd (optional; headers and library; rrdtool 1.0 and 1.2 both work fine)
 -    If built without `librrd' the resulting binary will be `client only', i.e.
 -    will send its values via multicast and not create any RRD files itself.
 -    Alternatively you can chose to write CSV-files (Comma Separated Values)
 -    instead.
 +  * librrd (optional)
 +    Used by the `rrdtool' and `rrdcached' plugins. The latter requires RRDtool
 +    client support which was added after version 1.3 of RRDtool. Versions 1.0,
 +    1.2 and 1.3 are known to work with the `rrdtool' plugin.
 +    <http://oss.oetiker.ch/rrdtool/>
  
    * librt, libsocket, libkstat, libdevinfo (optional)
      Various standard Solaris libraries which provide system functions.
 +    <http://developers.sun.com/solaris/>
  
    * libsensors (optional)
      To read from `lm_sensors', see the `sensors' plugin.
 +    <http://www.lm-sensors.org/>
  
 -  * libstatgrab (optional) may be used to collect statistics on systems other
 -    than Linux and/or Solaris. Note that CPU- and disk-statistics, while being
 -    provided by this library, are not supported in collectd right now..
 -    <http://www.i-scream.org/libstatgrab/> 
 +  * libstatgrab (optional)
 +    Used by various plugins to collect statistics on systems other than Linux
 +    and/or Solaris.
 +    <http://www.i-scream.org/libstatgrab/>
  
    * libupsclient/nut (optional)
      For the `nut' plugin which queries nut's `upsd'.
 +    <http://networkupstools.org/>
  
    * libvirt (optional)
      Collect statistics from virtual machines.
 +    <http://libvirt.org/>
  
    * libxml2 (optional)
      Parse XML data. This is needed for the `ascent' and `libvirt' plugins.
 +    <http://xmlsoft.org/>
  
    * libxmms (optional)
 +    <http://www.xmms.org/>
  
  
  Configuring / Compiling / Installing
    `./configure && make && make install'.  For detailed, generic instructions
    see INSTALL. For a complete list of configure options and their description,
    run `./configure --help'.
 -  
 +
    By default, the configure script will check for all build dependencies and
    disable all plugins whose requirements cannot be fulfilled (any other plugin
    will be enabled). To enable a plugin, install missing dependencies (see
@@@ -541,12 -454,24 +541,24 @@@ Crosscompilin
    that the compiled binary actually behaves as it should, but since NANs
    are likely never passed to the libm you have a good chance to be lucky.
  
+   Likewise, collectd needs to know the layout of doubles in memory, in order
+   to craft uniform network packets over different architectures. For this, it
+   needs to know how to convert doubles into the memory layout used by x86. The
+   configure script tries to figure this out by compiling and running a few
+   small test programs. This is of course not possible when cross-compiling.
+   You can use the `--with-fp-layout' option to tell the configure script which
+   conversion method to assume. Valid arguments are:
+     * `nothing'    (12345678 -> 12345678)
+     * `endianflip' (12345678 -> 87654321)
+     * `intswap'    (12345678 -> 56781234)
  
  Contact
  -------
  
-   For questions, bugreports, development information and basically all other
-   concerns please send an email to collectd's mailinglist at
+   For questions, bug reports, development information and basically all other
+   concerns please send an email to collectd's mailing list at
    <collectd at verplant.org>.
  
    For live discussion and more personal contact visit us in IRC, we're in
@@@ -560,5 -485,6 +572,6 @@@ Autho
    Sebastian tokkee Harl <sh at tokkee.org>,
    and many contributors (see `AUTHORS').
  
-   Please send bugreports and patches to the mailinglist, see `Contact' above.
+   Please send bug reports and patches to the mailing list, see `Contact'
+   above.
  
  # Pre-defined queries of collectd's postgresql plugin.
 +#
 +# Do not edit this file. If you want to change any of the query definitions,
 +# overwrite them in collectd.conf instead.
 +#
 +# This file is distributed under the same terms as collectd itself.
  
  <Query backends>
 -      Query "SELECT count(*) \
 +      Statement "SELECT count(*) AS count \
                FROM pg_stat_activity \
                WHERE datname = $1;"
  
        Param database
  
 -      Column pg_numbackends
 +      <Result>
 +              Type "pg_numbackends"
 +              ValuesFrom "count"
 +      </Result>
  </Query>
  
  <Query transactions>
 -      Query "SELECT xact_commit, xact_rollback \
 +      Statement "SELECT xact_commit, xact_rollback \
                FROM pg_stat_database \
                WHERE datname = $1;"
  
        Param database
  
 -      Column pg_xact commit
 -      Column pg_xact rollback
 +      <Result>
 +              Type "pg_xact"
 +              InstancePrefix "commit"
 +              ValuesFrom "xact_commit"
 +      </Result>
 +      <Result>
 +              Type "pg_xact"
 +              InstancePrefix "rollback"
 +              ValuesFrom "xact_rollback"
 +      </Result>
  </Query>
  
  <Query queries>
 -      Query "SELECT sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del) \
 +      Statement "SELECT sum(n_tup_ins) AS ins, \
 +                      sum(n_tup_upd) AS upd, \
 +                      sum(n_tup_del) AS del \
                FROM pg_stat_user_tables;"
  
 -      Column pg_n_tup_c ins
 -      Column pg_n_tup_c upd
 -      Column pg_n_tup_c del
 -
 -      MaxPGVersion 80299
 +      <Result>
 +              Type "pg_n_tup_c"
 +              InstancePrefix "ins"
 +              ValuesFrom "ins"
 +      </Result>
 +      <Result>
 +              Type "pg_n_tup_c"
 +              InstancePrefix "upd"
 +              ValuesFrom "upd"
 +      </Result>
 +      <Result>
 +              Type "pg_n_tup_c"
 +              InstancePrefix "del"
 +              ValuesFrom "del"
 +      </Result>
 +
 +      MaxVersion 80299
  </Query>
  
  <Query queries>
 -      Query "SELECT sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del), \
 -                      sum(n_tup_hot_upd) \
 +      Statement "SELECT sum(n_tup_ins) AS ins, \
 +                      sum(n_tup_upd) AS upd, \
 +                      sum(n_tup_del) AS del, \
 +                      sum(n_tup_hot_upd) AS hot_upd \
                FROM pg_stat_user_tables;"
  
 -      Column pg_n_tup_c ins
 -      Column pg_n_tup_c upd
 -      Column pg_n_tup_c del
 -      Column pg_n_tup_c hot_upd
 -
 -      MinPGVersion 80300
 +      <Result>
 +              Type "pg_n_tup_c"
 +              InstancePrefix "ins"
 +              ValuesFrom "ins"
 +      </Result>
 +      <Result>
 +              Type "pg_n_tup_c"
 +              InstancePrefix "upd"
 +              ValuesFrom "upd"
 +      </Result>
 +      <Result>
 +              Type "pg_n_tup_c"
 +              InstancePrefix "del"
 +              ValuesFrom "del"
 +      </Result>
 +      <Result>
 +              Type "pg_n_tup_c"
 +              InstancePrefix "hot_upd"
 +              ValuesFrom "hot_upd"
 +      </Result>
 +
 +      MinVersion 80300
  </Query>
  
  <Query query_plans>
 -      Query "SELECT sum(seq_scan), sum(seq_tup_read), \
 -                      sum(idx_scan), sum(idx_tup_fetch) \
 +      Statement "SELECT sum(seq_scan) AS seq, \
 +                      sum(seq_tup_read) AS seq_tup_read, \
 +                      sum(idx_scan) AS idx, \
 +                      sum(idx_tup_fetch) AS idx_tup_fetch \
                FROM pg_stat_user_tables;"
  
 -      Column pg_scan seq
 -      Column pg_scan seq_tup_read
 -      Column pg_scan idx
 -      Column pg_scan idx_tup_fetch
 +      <Result>
 +              Type "pg_scan"
 +              InstancePrefix "seq"
 +              ValuesFrom "seq"
 +      </Result>
 +      <Result>
 +              Type "pg_scan"
 +              InstancePrefix "seq_tup_read"
 +              ValuesFrom "seq_tup_read"
 +      </Result>
 +      <Result>
 +              Type "pg_scan"
 +              InstancePrefix "idx"
 +              ValuesFrom "idx"
 +      </Result>
 +      <Result>
 +              Type "pg_scan"
 +              InstancePrefix "idx_tup_fetch"
 +              ValuesFrom "idx_tup_fetch"
 +      </Result>
  </Query>
  
  <Query table_states>
 -      Query "SELECT sum(n_live_tup), sum(n_dead_tup) \
 +      Statement "SELECT sum(n_live_tup) AS live, sum(n_dead_tup) AS dead \
                FROM pg_stat_user_tables;"
  
 -      Column pg_n_tup_g live
 -      Column pg_n_tup_g dead
 -
 -      MinPGVersion 80300
 +      <Result>
 +              Type "pg_n_tup_g"
 +              InstancePrefix "live"
 +              ValuesFrom "live"
 +      </Result>
 +      <Result>
 +              Type "pg_n_tup_g"
 +              InstancePrefix "dead"
 +              ValuesFrom "dead"
 +      </Result>
 +
 +      MinVersion 80300
  </Query>
  
  <Query disk_io>
-       Statement "SELECT sum(heap_blks_read) AS heap_read, \
-                       sum(heap_blks_hit) AS heap_hit, \
-                       sum(idx_blks_read) AS idx_read, \
-                       sum(idx_blks_hit) AS idx_hit, \
-                       sum(toast_blks_read) AS toast_read, \
-                       sum(toast_blks_hit) AS toast_hit, \
-                       sum(tidx_blks_read) AS tidx_read, \
-                       sum(tidx_blks_hit) AS tidx_hit \
 -      Query "SELECT coalesce(sum(heap_blks_read), 0), \
 -                      coalesce(sum(heap_blks_hit), 0), \
 -                      coalesce(sum(idx_blks_read), 0), \
 -                      coalesce(sum(idx_blks_hit), 0), \
 -                      coalesce(sum(toast_blks_read), 0), \
 -                      coalesce(sum(toast_blks_hit), 0), \
 -                      coalesce(sum(tidx_blks_read), 0), \
 -                      coalesce(sum(tidx_blks_hit), 0) \
++      Statement "SELECT coalesce(sum(heap_blks_read), 0) AS heap_read, \
++                      coalesce(sum(heap_blks_hit), 0) AS heap_hit, \
++                      coalesce(sum(idx_blks_read), 0) AS idx_read, \
++                      coalesce(sum(idx_blks_hit), 0) AS idx_hit, \
++                      coalesce(sum(toast_blks_read), 0) AS toast_read, \
++                      coalesce(sum(toast_blks_hit), 0) AS toast_hit, \
++                      coalesce(sum(tidx_blks_read), 0) AS tidx_read, \
++                      coalesce(sum(tidx_blks_hit), 0) AS tidx_hit \
                FROM pg_statio_user_tables;"
  
 -      Column pg_blks heap_read
 -      Column pg_blks heap_hit
 -      Column pg_blks idx_read
 -      Column pg_blks idx_hit
 -      Column pg_blks toast_read
 -      Column pg_blks toast_hit
 -      Column pg_blks tidx_read
 -      Column pg_blks tidx_hit
 +      <Result>
 +              Type "pg_blks"
 +              InstancePrefix "heap_read"
 +              ValuesFrom "heap_read"
 +      </Result>
 +      <Result>
 +              Type "pg_blks"
 +              InstancePrefix "heap_hit"
 +              ValuesFrom "heap_hit"
 +      </Result>
 +      <Result>
 +              Type "pg_blks"
 +              InstancePrefix "idx_read"
 +              ValuesFrom "idx_read"
 +      </Result>
 +      <Result>
 +              Type "pg_blks"
 +              InstancePrefix "idx_hit"
 +              ValuesFrom "idx_hit"
 +      </Result>
 +      <Result>
 +              Type "pg_blks"
 +              InstancePrefix "toast_read"
 +              ValuesFrom "toast_read"
 +      </Result>
 +      <Result>
 +              Type "pg_blks"
 +              InstancePrefix "toast_hit"
 +              ValuesFrom "toast_hit"
 +      </Result>
 +      <Result>
 +              Type "pg_blks"
 +              InstancePrefix "tidx_read"
 +              ValuesFrom "tidx_read"
 +      </Result>
 +      <Result>
 +              Type "pg_blks"
 +              InstancePrefix "tidx_hit"
 +              ValuesFrom "tidx_hit"
 +      </Result>
  </Query>
  
  <Query disk_usage>
 -      Query "SELECT pg_database_size($1);"
 +      Statement "SELECT pg_database_size($1) AS size;"
  
        Param database
  
 -      Column pg_db_size
 +      <Result>
 +              Type pg_db_size
 +              ValuesFrom "size"
 +      </Result>
  </Query>
  
  # vim: set ft=config :
diff --combined src/rrdtool.c
@@@ -23,7 -23,6 +23,7 @@@
  #include "plugin.h"
  #include "common.h"
  #include "utils_avltree.h"
 +#include "utils_rrdcreate.h"
  
  #include <rrd.h>
  
@@@ -66,6 -65,27 +66,6 @@@ typedef struct rrd_queue_s rrd_queue_t
  /*
   * Private variables
   */
 -static int rra_timespans[] =
 -{
 -      3600,
 -      86400,
 -      604800,
 -      2678400,
 -      31622400
 -};
 -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"
 -};
 -static int rra_types_num = STATIC_ARRAY_SIZE (rra_types);
 -
  static const char *config_keys[] =
  {
        "CacheTimeout",
@@@ -83,21 -103,12 +83,21 @@@ static int config_keys_num = STATIC_ARR
  /* If datadir is zero, the daemon's basedir is used. If stepsize or heartbeat
   * is zero a default, depending on the `interval' member of the value list is
   * being used. */
 -static char   *datadir   = NULL;
 -static int     stepsize  = 0;
 -static int     heartbeat = 0;
 -static int     rrarows   = 1200;
 -static double  xff       = 0.1;
 -static double  write_rate = 0.0;
 +static char *datadir   = NULL;
 +static double write_rate = 0.0;
 +static rrdcreate_config_t rrdcreate_config =
 +{
 +      /* stepsize = */ 0,
 +      /* heartbeat = */ 0,
 +      /* rrarows = */ 1200,
 +      /* xff = */ 0.1,
 +
 +      /* timespans = */ NULL,
 +      /* timespans_num = */ 0,
 +
 +      /* consolidation_functions = */ NULL,
 +      /* consolidation_functions_num = */ 0
 +};
  
  /* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
   * ALWAYS lock `cache_lock' first! */
@@@ -121,7 -132,233 +121,7 @@@ static pthread_mutex_t librrd_lock = PT
  
  static int do_shutdown = 0;
  
 -/* * * * * * * * * *
 - * WARNING:  Magic *
 - * * * * * * * * * */
 -
 -static void rra_free (int rra_num, char **rra_def)
 -{
 -      int i;
 -
 -      for (i = 0; i < rra_num; i++)
 -      {
 -              sfree (rra_def[i]);
 -      }
 -      sfree (rra_def);
 -} /* void rra_free */
 -
 -static int rra_get (char ***ret, const value_list_t *vl)
 -{
 -      char **rra_def;
 -      int rra_num;
 -
 -      int *rts;
 -      int  rts_num;
 -
 -      int rra_max;
 -
 -      int span;
 -
 -      int cdp_num;
 -      int cdp_len;
 -      int i, j;
 -
 -      char buffer[64];
 -
 -      /* The stepsize we use here: If it is user-set, use it. If not, use the
 -       * interval of the value-list. */
 -      int ss;
 -
 -      if (rrarows <= 0)
 -      {
 -              *ret = NULL;
 -              return (-1);
 -      }
 -
 -      ss = (stepsize > 0) ? stepsize : vl->interval;
 -      if (ss <= 0)
 -      {
 -              *ret = NULL;
 -              return (-1);
 -      }
 -
 -      /* 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 *));
 -      rra_num = 0;
 -
 -      cdp_len = 0;
 -      for (i = 0; i < rts_num; i++)
 -      {
 -              span = rts[i];
 -
 -              if ((span / ss) < rrarows)
 -                      span = ss * rrarows;
 -
 -              if (cdp_len == 0)
 -                      cdp_len = 1;
 -              else
 -                      cdp_len = (int) floor (((double) span)
 -                                      / ((double) (rrarows * ss)));
 -
 -              cdp_num = (int) ceil (((double) span)
 -                              / ((double) (cdp_len * ss)));
 -
 -              for (j = 0; j < rra_types_num; j++)
 -              {
 -                      if (rra_num >= rra_max)
 -                              break;
 -
 -                      if (ssnprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
 -                                              rra_types[j], xff,
 -                                              cdp_len, cdp_num) >= sizeof (buffer))
 -                      {
 -                              ERROR ("rra_get: Buffer would have been truncated.");
 -                              continue;
 -                      }
 -
 -                      rra_def[rra_num++] = sstrdup (buffer);
 -              }
 -      }
 -
 -#if COLLECT_DEBUG
 -      DEBUG ("rra_num = %i", rra_num);
 -      for (i = 0; i < rra_num; i++)
 -              DEBUG ("  %s", rra_def[i]);
 -#endif
 -
 -      *ret = rra_def;
 -      return (rra_num);
 -} /* int rra_get */
 -
 -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, const value_list_t *vl)
 -{
 -      char **ds_def;
 -      int ds_num;
 -
 -      char min[32];
 -      char max[32];
 -      char buffer[128];
 -
 -      DEBUG ("ds->ds_num = %i", ds->ds_num);
 -
 -      ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
 -      if (ds_def == NULL)
 -      {
 -              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 *));
 -
 -      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
 -              {
 -                      ERROR ("rrdtool plugin: Unknown DS type: %i",
 -                                      d->type);
 -                      break;
 -              }
 -
 -              if (isnan (d->min))
 -              {
 -                      sstrncpy (min, "U", sizeof (min));
 -              }
 -              else
 -                      ssnprintf (min, sizeof (min), "%lf", d->min);
 -
 -              if (isnan (d->max))
 -              {
 -                      sstrncpy (max, "U", sizeof (max));
 -              }
 -              else
 -                      ssnprintf (max, sizeof (max), "%lf", d->max);
 -
 -              status = ssnprintf (buffer, sizeof (buffer),
 -                              "DS:%s:%s:%i:%s:%s",
 -                              d->name, type,
 -                              (heartbeat > 0) ? heartbeat : (2 * vl->interval),
 -                              min, max);
 -              if ((status < 1) || (status >= sizeof (buffer)))
 -                      break;
 -
 -              ds_def[ds_num] = sstrdup (buffer);
 -      } /* for ds_num = 0 .. ds->ds_num */
 -
 -#if COLLECT_DEBUG
 -{
 -      int i;
 -      DEBUG ("ds_num = %i", ds_num);
 -      for (i = 0; i < ds_num; i++)
 -              DEBUG ("  %s", ds_def[i]);
 -}
 -#endif
 -
 -      if (ds_num != ds->ds_num)
 -      {
 -              ds_free (ds_num, ds_def);
 -              return (-1);
 -      }
 -
 -      *ret = ds_def;
 -      return (ds_num);
 -}
 -
  #if HAVE_THREADSAFE_LIBRRD
 -static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
 -              int argc, const char **argv)
 -{
 -      int status;
 -
 -      optind = 0; /* bug in librrd? */
 -      rrd_clear_error ();
 -
 -      status = rrd_create_r (filename, pdp_step, last_up, argc, (void *) argv);
 -
 -      if (status != 0)
 -      {
 -              WARNING ("rrdtool plugin: rrd_create_r (%s) failed: %s",
 -                              filename, rrd_get_error ());
 -      }
 -
 -      return (status);
 -} /* int srrd_create */
 -
  static int srrd_update (char *filename, char *template,
                int argc, const char **argv)
  {
  /* #endif HAVE_THREADSAFE_LIBRRD */
  
  #else /* !HAVE_THREADSAFE_LIBRRD */
 -static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
 -              int argc, const char **argv)
 -{
 -      int status;
 -
 -      int new_argc;
 -      char **new_argv;
 -
 -      char pdp_step_str[16];
 -      char last_up_str[16];
 -
 -      new_argc = 6 + argc;
 -      new_argv = (char **) malloc ((new_argc + 1) * sizeof (char *));
 -      if (new_argv == NULL)
 -      {
 -              ERROR ("rrdtool plugin: malloc failed.");
 -              return (-1);
 -      }
 -
 -      if (last_up == 0)
 -              last_up = time (NULL) - 10;
 -
 -      ssnprintf (pdp_step_str, sizeof (pdp_step_str), "%lu", pdp_step);
 -      ssnprintf (last_up_str, sizeof (last_up_str), "%u", (unsigned int) last_up);
 -
 -      new_argv[0] = "create";
 -      new_argv[1] = filename;
 -      new_argv[2] = "-s";
 -      new_argv[3] = pdp_step_str;
 -      new_argv[4] = "-b";
 -      new_argv[5] = last_up_str;
 -
 -      memcpy (new_argv + 6, argv, argc * sizeof (char *));
 -      new_argv[new_argc] = NULL;
 -      
 -      pthread_mutex_lock (&librrd_lock);
 -      optind = 0; /* bug in librrd? */
 -      rrd_clear_error ();
 -
 -      status = rrd_create (new_argc, new_argv);
 -      pthread_mutex_unlock (&librrd_lock);
 -
 -      if (status != 0)
 -      {
 -              WARNING ("rrdtool plugin: rrd_create (%s) failed: %s",
 -                              filename, rrd_get_error ());
 -      }
 -
 -      sfree (new_argv);
 -
 -      return (status);
 -} /* int srrd_create */
 -
  static int srrd_update (char *filename, char *template,
                int argc, const char **argv)
  {
  } /* int srrd_update */
  #endif /* !HAVE_THREADSAFE_LIBRRD */
  
 -static int rrd_create_file (char *filename, const data_set_t *ds, const value_list_t *vl)
 -{
 -      char **argv;
 -      int argc;
 -      char **rra_def;
 -      int rra_num;
 -      char **ds_def;
 -      int ds_num;
 -      int status = 0;
 -
 -      if (check_create_dir (filename))
 -              return (-1);
 -
 -      if ((rra_num = rra_get (&rra_def, vl)) < 1)
 -      {
 -              ERROR ("rrd_create_file failed: Could not calculate RRAs");
 -              return (-1);
 -      }
 -
 -      if ((ds_num = ds_get (&ds_def, ds, vl)) < 1)
 -      {
 -              ERROR ("rrd_create_file failed: Could not calculate DSes");
 -              return (-1);
 -      }
 -
 -      argc = ds_num + rra_num;
 -
 -      if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
 -      {
 -              char errbuf[1024];
 -              ERROR ("rrd_create failed: %s",
 -                              sstrerror (errno, errbuf, sizeof (errbuf)));
 -              return (-1);
 -      }
 -
 -      memcpy (argv, ds_def, ds_num * sizeof (char *));
 -      memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
 -      argv[ds_num + rra_num] = NULL;
 -
 -      assert (vl->time > 10);
 -      status = srrd_create (filename,
 -                      (stepsize > 0) ? stepsize : vl->interval,
 -                      vl->time - 10,
 -                      argc, (const char **)argv);
 -
 -      free (argv);
 -      ds_free (ds_num, ds_def);
 -      rra_free (rra_num, rra_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 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)
 +              const data_set_t __attribute__((unused)) *ds, const value_list_t *vl)
  {
        int offset = 0;
        int status;
        return (0);
  } /* int value_list_to_filename */
  
 -static void *rrd_queue_thread (void *data)
 +static void *rrd_queue_thread (void __attribute__((unused)) *data)
  {
          struct timeval tv_next_update;
          struct timeval tv_now;
                rrd_cache_t *cache_entry;
                char **values;
                int    values_num;
+               int    status;
                int    i;
  
                  pthread_mutex_lock (&queue_lock);
                  while (true)
                  {
                    struct timespec ts_wait;
-                   int status;
  
                    while ((flushq_head == NULL) && (queue_head == NULL)
                        && (do_shutdown == 0))
                      break;
  
                    gettimeofday (&tv_now, /* timezone = */ NULL);
 -                  status = timeval_sub_timespec (&tv_next_update, &tv_now,
 -                      &ts_wait);
 +                  status = timeval_cmp (tv_next_update, tv_now, NULL);
                    /* We're good to go */
 -                  if (status != 0)
 +                  if (status <= 0)
                      break;
  
                    /* We're supposed to wait a bit with this update, so we'll
                 * we make a copy of it's values */
                pthread_mutex_lock (&cache_lock);
  
-               c_avl_get (cache, queue_entry->filename, (void *) &cache_entry);
+               status = c_avl_get (cache, queue_entry->filename,
+                               (void *) &cache_entry);
  
-               values = cache_entry->values;
-               values_num = cache_entry->values_num;
+               if (status == 0)
+               {
+                       values = cache_entry->values;
+                       values_num = cache_entry->values_num;
  
-               cache_entry->values = NULL;
-               cache_entry->values_num = 0;
-               cache_entry->flags = FLAG_NONE;
+                       cache_entry->values = NULL;
+                       cache_entry->values_num = 0;
+                       cache_entry->flags = FLAG_NONE;
+               }
  
                pthread_mutex_unlock (&cache_lock);
  
+               if (status != 0)
+               {
+                       sfree (queue_entry->filename);
+                       sfree (queue_entry);
+                       continue;
+               }
                /* Update `tv_next_update' */
                if (write_rate > 0.0) 
                  {
@@@ -625,6 -979,15 +636,15 @@@ static int rrd_cache_insert (const cha
  
        pthread_mutex_lock (&cache_lock);
  
+       /* This shouldn't happen, but it did happen at least once, so we'll be
+        * careful. */
+       if (cache == NULL)
+       {
+               pthread_mutex_unlock (&cache_lock);
+               WARNING ("rrdtool plugin: cache == NULL.");
+               return (-1);
+       }
        c_avl_get (cache, filename, (void *) &rc);
  
        if (rc == NULL)
@@@ -768,9 -1131,7 +788,9 @@@ static int rrd_write (const data_set_t 
        {
                if (errno == ENOENT)
                {
 -                      if (rrd_create_file (filename, ds, vl))
 +                      status = cu_rrd_create_file (filename,
 +                                      ds, vl, &rrdcreate_config);
 +                      if (status != 0)
                                return (-1);
                }
                else
@@@ -859,15 -1220,15 +879,15 @@@ static int rrd_config (const char *key
        }
        else if (strcasecmp ("StepSize", key) == 0)
        {
 -              stepsize = atoi (value);
 -              if (stepsize < 0)
 -                      stepsize = 0;
 +              int temp = atoi (value);
 +              if (temp > 0)
 +                      rrdcreate_config.stepsize = temp;
        }
        else if (strcasecmp ("HeartBeat", key) == 0)
        {
 -              heartbeat = atoi (value);
 -              if (heartbeat < 0)
 -                      heartbeat = 0;
 +              int temp = atoi (value);
 +              if (temp > 0)
 +                      rrdcreate_config.heartbeat = temp;
        }
        else if (strcasecmp ("RRARows", key) == 0)
        {
                                        "be greater than 0.\n");
                        return (1);
                }
 -              rrarows = tmp;
 +              rrdcreate_config.rrarows = tmp;
        }
        else if (strcasecmp ("RRATimespan", key) == 0)
        {
                {
                        dummy = NULL;
                        
 -                      tmp_alloc = realloc (rra_timespans_custom,
 -                                      sizeof (int) * (rra_timespans_custom_num + 1));
 +                      tmp_alloc = realloc (rrdcreate_config.timespans,
 +                                      sizeof (int) * (rrdcreate_config.timespans_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++;
 +                      rrdcreate_config.timespans = tmp_alloc;
 +                      rrdcreate_config.timespans[rrdcreate_config.timespans_num] = atoi (ptr);
 +                      if (rrdcreate_config.timespans[rrdcreate_config.timespans_num] != 0)
 +                              rrdcreate_config.timespans_num++;
                } /* while (strtok_r) */
  
 -              qsort (/* base = */ rra_timespans_custom,
 -                              /* nmemb  = */ rra_timespans_custom_num,
 -                              /* size   = */ sizeof (rra_timespans_custom[0]),
 +              qsort (/* base = */ rrdcreate_config.timespans,
 +                              /* nmemb  = */ rrdcreate_config.timespans_num,
 +                              /* size   = */ sizeof (rrdcreate_config.timespans[0]),
                                /* compar = */ rrd_compare_numeric);
  
                free (value_copy);
                                        "be in the range 0 to 1 (exclusive).");
                        return (1);
                }
 -              xff = tmp;
 +              rrdcreate_config.xff = tmp;
        }
        else if (strcasecmp ("WritesPerSecond", key) == 0)
        {
@@@ -986,18 -1347,16 +1006,18 @@@ static int rrd_init (void
  {
        int status;
  
 -      if (stepsize < 0)
 -              stepsize = 0;
 -      if (heartbeat <= 0)
 -              heartbeat = 2 * stepsize;
 +      if (rrdcreate_config.stepsize < 0)
 +              rrdcreate_config.stepsize = 0;
 +      if (rrdcreate_config.heartbeat <= 0)
 +              rrdcreate_config.heartbeat = 2 * rrdcreate_config.stepsize;
  
 -      if ((heartbeat > 0) && (heartbeat < interval_g))
 +      if ((rrdcreate_config.heartbeat > 0)
 +                      && (rrdcreate_config.heartbeat < interval_g))
                WARNING ("rrdtool plugin: Your `heartbeat' is "
                                "smaller than your `interval'. This will "
                                "likely cause problems.");
 -      else if ((stepsize > 0) && (stepsize < interval_g))
 +      else if ((rrdcreate_config.stepsize > 0)
 +                      && (rrdcreate_config.stepsize < interval_g))
                WARNING ("rrdtool plugin: Your `stepsize' is "
                                "smaller than your `interval'. This will "
                                "create needlessly big RRD-files.");
        DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
                        " heartbeat = %i; rrarows = %i; xff = %lf;",
                        (datadir == NULL) ? "(null)" : datadir,
 -                      stepsize, heartbeat, rrarows, xff);
 +                      rrdcreate_config.stepsize,
 +                      rrdcreate_config.heartbeat,
 +                      rrdcreate_config.rrarows,
 +                      rrdcreate_config.xff);
  
        return (0);
  } /* int rrd_init */
diff --combined src/snmp.c
@@@ -22,7 -22,6 +22,7 @@@
  #include "collectd.h"
  #include "common.h"
  #include "plugin.h"
 +#include "utils_complain.h"
  
  #include <pthread.h>
  
@@@ -68,7 -67,6 +68,7 @@@ struct host_definition_
    char *community;
    int version;
    void *sess_handle;
 +  c_complain_t complaint;
    uint32_t interval;
    time_t next_update;
    data_definition_t **data_list;
@@@ -118,7 -116,6 +118,7 @@@ static pthread_cond_t  host_cond = PTHR
  /*
   * Private functions
   */
 +/* Many functions to handle the configuration. {{{ */
  /* First there are many functions which do configuration stuff. It's a big
   * bloated and messy, I'm afraid. */
  
@@@ -530,9 -527,9 +530,9 @@@ static int csnmp_config_add_host_interv
      return (-1);
    }
  
 -  hd->interval = (int) ci->values[0].value.number;
 -  if (hd->interval < 0)
 -    hd->interval = 0;
 +  hd->interval = ci->values[0].value.number >= 0
 +    ? (uint32_t) ci->values[0].value.number
 +    : 0;
  
    return (0);
  } /* int csnmp_config_add_host_interval */
@@@ -554,7 -551,6 +554,7 @@@ static int csnmp_config_add_host (oconf
      return (-1);
    memset (hd, '\0', sizeof (host_definition_t));
    hd->version = 2;
 +  C_COMPLAIN_INIT (&hd->complaint);
  
    hd->name = strdup (ci->values[0].value.string);
    if (hd->name == NULL)
@@@ -657,7 -653,7 +657,7 @@@ static int csnmp_config (oconfig_item_
    return (0);
  } /* int csnmp_config */
  
 -/* End of the config stuff. Now the interesting part begins */
 +/* }}} End of the config stuff. Now the interesting part begins */
  
  static void csnmp_host_close_session (host_definition_t *host)
  {
@@@ -696,6 -692,7 +696,7 @@@ static void csnmp_host_open_session (ho
    }
  } /* void csnmp_host_open_session */
  
+ /* TODO: Check if negative values wrap around. Problem: negative temperatures. */
  static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
      double scale, double shift)
  {
@@@ -963,6 -960,7 +964,6 @@@ static int csnmp_dispatch_table (host_d
    sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin));
  
    vl.interval = host->interval;
 -  vl.time = time (NULL);
  
    subid = 0;
    have_more = 1;
@@@ -1138,7 -1136,7 +1139,7 @@@ static int csnmp_read_table (host_defin
        break;
      }
  
 -    for (i = 0; i < oid_list_len; i++)
 +    for (i = 0; (uint32_t) i < oid_list_len; i++)
        snmp_add_null_var (req, oid_list[i].oid, oid_list[i].oid_len);
  
      res = NULL;
        char *errstr = NULL;
  
        snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
 -      ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
 +
 +      c_complain (LOG_ERR, &host->complaint,
 +        "snmp plugin: host %s: snmp_sess_synch_response failed: %s",
          host->name, (errstr == NULL) ? "Unknown problem" : errstr);
  
        if (res != NULL)
      }
      status = 0;
      assert (res != NULL);
 +    c_release (LOG_INFO, &host->complaint,
 +      "snmp plugin: host %s: snmp_sess_synch_response successful.",
 +      host->name);
  
      vb = res->variables;
      if (vb == NULL)
@@@ -1384,6 -1377,7 +1385,6 @@@ static int csnmp_read_value (host_defin
      return (-1);
    }
  
 -  vl.time = time (NULL);
  
    for (vb = res->variables; vb != NULL; vb = vb->next_variable)
    {
@@@ -1441,7 -1435,7 +1442,7 @@@ static int csnmp_read_host (host_defini
    time_end = time (NULL);
    DEBUG ("snmp plugin: csnmp_read_host (%s) finished at %u;", host->name,
        (unsigned int) time_end);
 -  if ((time_end - time_start) > host->interval)
 +  if ((uint32_t) (time_end - time_start) > host->interval)
    {
      WARNING ("snmp plugin: Host `%s' should be queried every %i seconds, "
        "but reading all values takes %u seconds.",
    return (0);
  } /* int csnmp_read_host */
  
 -static void *csnmp_read_thread (void *data)
 +static void *csnmp_read_thread (void __attribute__((unused)) *data)
  {
    host_definition_t *host;
  
@@@ -1504,7 -1498,7 +1505,7 @@@ static int csnmp_init (void
      {
        host->interval = interval_g;
      }
 -    else if (host->interval < interval_g)
 +    else if (host->interval < (uint32_t) interval_g)
      {
        host->interval = interval_g;
        WARNING ("snmp plugin: Data for host `%s' will be collected every %i seconds.",
@@@ -1633,5 -1627,5 +1634,5 @@@ void module_register (void
  } /* void module_register */
  
  /*
 - * vim: shiftwidth=2 softtabstop=2 tabstop=8
 + * vim: shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker
   */