Merge branch 'collectd-4.10' into collectd-5.0
authorFlorian Forster <octo@collectd.org>
Sun, 11 Nov 2012 11:05:17 +0000 (12:05 +0100)
committerFlorian Forster <octo@collectd.org>
Sun, 11 Nov 2012 11:05:17 +0000 (12:05 +0100)
Conflicts:
ChangeLog
src/pyvalues.c
version-gen.sh

128 files changed:
.gitignore
AUTHORS
ChangeLog
README
bindings/java/org/collectd/api/CollectdFlushInterface.java
bindings/java/org/collectd/api/ValueList.java
bindings/java/org/collectd/java/GenericJMXConfConnection.java
bindings/java/org/collectd/java/GenericJMXConfMBean.java
bindings/perl/lib/Collectd.pm
configure.in
contrib/collectd_network.py
contrib/exec-munin.px
contrib/exec-nagios.px
contrib/exec-smartctl
contrib/migrate-4-5.px [new file with mode: 0755]
src/Makefile.am
src/amqp.c [new file with mode: 0644]
src/apache.c
src/bind.c
src/collectd-exec.pod
src/collectd-java.pod
src/collectd-nagios.c
src/collectd-nagios.pod
src/collectd-perl.pod
src/collectd-threshold.pod [new file with mode: 0644]
src/collectd.c
src/collectd.conf.in
src/collectd.conf.pod
src/collectd.h
src/collectdctl.c [new file with mode: 0644]
src/collectdctl.pod [new file with mode: 0644]
src/common.c
src/common.h
src/configfile.c
src/configfile.h
src/contextswitch.c
src/cpu.c
src/cpython.h
src/csv.c
src/curl.c
src/curl_json.c
src/dbi.c
src/df.c
src/disk.c
src/dns.c
src/email.c
src/exec.c
src/fscache.c
src/gmond.c
src/hddtemp.c
src/interface.c
src/ipmi.c
src/iptables.c
src/ipvs.c
src/irq.c
src/java.c
src/libcollectdclient/client.c
src/libcollectdclient/client.h
src/libvirt.c
src/logfile.c
src/lpar.c [new file with mode: 0644]
src/madwifi.c
src/match_timediff.c
src/memcachec.c
src/memcached.c
src/modbus.c
src/mysql.c
src/netapp.c
src/netlink.c
src/network.c
src/network.h
src/nfs.c
src/nginx.c
src/notify_email.c
src/onewire.c
src/openvpn.c
src/oracle.c
src/perl.c
src/plugin.c
src/plugin.h
src/postgresql.c
src/powerdns.c
src/processes.c
src/protocols.c
src/python.c
src/pyvalues.c
src/redis.c [new file with mode: 0644]
src/routeros.c
src/rrdcached.c
src/rrdtool.c
src/serial.c
src/snmp.c
src/swap.c
src/tape.c
src/target_notification.c
src/target_scale.c
src/target_v5upgrade.c [new file with mode: 0644]
src/teamspeak2.c
src/ted.c
src/thermal.c
src/threshold.c [new file with mode: 0644]
src/types.db
src/types_list.c
src/unixsock.c
src/utils_cache.c
src/utils_cache.h
src/utils_cmd_flush.c
src/utils_cmd_listval.c
src/utils_cmd_putval.c
src/utils_cmd_putval.h
src/utils_db_query.c
src/utils_db_query.h
src/utils_dns.c
src/utils_dns.h
src/utils_format_json.c
src/utils_rrdcreate.c
src/utils_rrdcreate.h
src/utils_threshold.c [deleted file]
src/utils_threshold.h [deleted file]
src/utils_time.c [new file with mode: 0644]
src/utils_time.h [new file with mode: 0644]
src/varnish.c [new file with mode: 0644]
src/vmem.c
src/vserver.c
src/write_http.c
src/write_redis.c [new file with mode: 0644]
src/zfs_arc.c
version-gen.sh

index b85bdec..75cb307 100644 (file)
@@ -66,3 +66,9 @@ bindings/java/org/collectd/java/*.class
 
 # python stuff
 *.pyc
+
+# tag stuff
+src/tags
+
+# backup stuff
+*~
diff --git a/AUTHORS b/AUTHORS
index f090840..0e0a5fe 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -34,6 +34,10 @@ Anthony Gialluca <tonyabg at charter.net>
 Antony Dovgal <tony at daylessday.org>
  - memcached plugin.
 
+Aurélien Reynaud <collectd at wattapower.net>
+ - LPAR plugin.
+ - Various fixes for AIX, HP-UX and Solaris.
+
 Bruno Prémont <bonbons at linux-vserver.org>
  - BIND plugin.
  - Many bugreports and -fixes in various plugins,
@@ -75,6 +79,9 @@ Franck Lombardi
 Jason Pepas <cell at ices.utexas.edu>
  - nfs plugin.
 
+Jérôme Renard <jerome.renard at gmail.com>
+ - varnish plugin.
+
 Luboš Staněk <kolektor at atlas.cz>
  - sensors plugin improvements.
  - Time and effort to find a nasty bug in the ntpd-plugin.
@@ -162,6 +169,9 @@ Rodolphe Quiédeville <rquiedeville at bearstech.com>
 Scott Garrett <sgarrett at technomancer.com>
  - tape plugin.
 
+Sebastien Pahl <sebastien.pahl at dotcloud.com>
+ - AMQP plugin.
+
 Simon Kuhnle <simon at blarzwurst.de>
  - OpenBSD code for the cpu and memory plugins.
 
index 21c046b..8d478ad 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,174 @@
+2012-04-01, Version 5.0.4
+       * Build system: Fix the use of a libltdl macro. Thanks to Clemens Lang
+         for fixing this. Adresses some issues with building the iptables
+         plugin under Gentoo.
+       * libcollectdclient: A memory leak in the lcc_getval() function has
+         been fixed. Thanks to Jason Schmidlapp for finding and fixing this
+         issue.
+       * bind plugin: The use of 'QType" types has been fixed.
+       * df plugin: Fixed compiler issue under Mac OS X 10.7.
+       * conntrack plugin: Support zero as legitimate value. Thanks to Louis
+         Opter for his patch.
+       * memcached plugin: Increased the size of a static buffer, which was
+         truncating status messages form memcached. Thanks to Timon for the
+         patch.
+       * network plugin: Forwarding of notifications has been disabled. This
+         was a contition not checked for before, which may retult in an
+         endless loop.
+       * processes plugin: Support for process names with spaces has been
+         added to the Linux implementation. Thanks to Darrell Bishop for his
+         patch.
+       * perl plugin: A race condition in several callbacks, including log and
+         write callbacks, has been fixed. Thanks to "Rrpv" for reporting this
+         bug.
+       * snmp plugin: A bug when casting unsigned integers to gauge values has
+         been fixed: Unsigned integers would be cast to a signed integer and
+         then to a gauge, possibly resulting in a negative value.
+       * tcpconns plugin: Compilation with newer versions of the FreeBSD
+         runtime has been fixed.
+
+2012-02-19, Version 5.0.3
+       * Build system: Fix problems when building the ipvs and iptables
+         plugins. Thanks to Sebastian Harl for his patch. A bashism in the
+         version-gen.sh script has been fixed. Thanks to Jo-Philipp Wich for
+         his patch.
+       * csv and rrdtool plugins: Print a more helpful error message when the
+         DataDir is a symlink pointing to a non-existing location. Thanks to
+         Jonathan Nieder for his patch.
+       * exec plugin: Fix a problem when using select(2) to read from file
+         handles. Thanks to Gerrie Roos for his patch.
+       * network plugin: An incorrect error message in the handling of the
+         "Interface" configuration option has been fixed. Thanks to Gerrie
+         Roos for his patch.
+       * oracle plugin: A potential endless loop in the error handling has
+         been fixed.
+       * python plugin: A crash bug in the configuration handling has been
+         fixed. Thanks to Sven Trenkel for his patch.
+       * interfaces plugin: The change which was supposed to ignore "bogus"
+         interfaces has been reverted, since it ignored legit interfaces, such
+         as bonding pseudo-devices as well.
+
+2012-01-21, Version 5.0.2
+       * curl_xml plugin: Fix handling of file:// and other URLs (which don't
+         follow HTTP status codes). Thanks to Fabien Wernli for his patch!
+       * df plugin: Fix handling of negative "available" counts. This can
+         occur with some file systems, for example UFS. Thanks to Toni Ylenius
+         for his patch.
+       * interface plugin: "mac" interfaces are now ignored on Solaris. These
+         pseudo-interfaces occur multiple times, causing warnings. Also switch
+         to 64-bit counters on Solaris, improving overflow behavior for
+         high-speed interfaces. Thanks to Eddy Geez and Fabien Wernli for
+         their patches.
+       * memory plugin: Account kernel and unused memory under Solaris. Thanks
+         to Fabien Wernli for his patch.
+       * network plugin: A bug in the interaction between the Network plugin
+         and filter chains has been fixed: When a filter modified a field such
+         as the hostname, subsequent values in the same network packets could
+         have ended up using the modified name rather than the original name.
+         Thanks to Sebastian Harl for identifying the problem.
+       * oracle plugin: A memory leak has been fixed in the parameter handling.
+       * python plugin: A memory leak has been fixed. Thanks to Sven Trenkel
+         for fixing this bug!
+
+2011-10-07, Version 5.0.1
+       * collectd: A mutex leak has been fixed in the meta data code. Thanks
+         to Rafal Lesniak for his patch.
+       * collectd: Compatibility fixes for GCC 4.6 have been applied. Thanks
+         to Peter Green for his patch.
+       * csv plugin: The line buffer size has been increased. Thanks to Colin
+         McCabe for the patch.
+       * curl_json plugin: Don't use the "parent" node to build the type
+         instance, if it is empty. Compatibility with libyajl 2 has been
+         added. Thanks to "spupykin" of the Arch Linux project for the initial
+         code. Formatting of time has been fixed in the JSON module.
+       * exec plugin: Fix the timestamp value passed to notification scripts.
+         Thanks to Alexander Kovalenko for fixing this.
+       * iptables plugin: Fix linking with some versions of libiptc.
+       * irq plugin: Fix support for interrupts under Linux. The old code
+         assumed that interrupts have a numeric value -- this is no longer
+         true for Linux. Thanks to Bostjan Skufca for implementing this.
+       * notify_desktop plugin: Compatibility with libnotify 0.7 has been
+         added. Thanks to Samuli Suominen for his patch.
+       * processes plugin: Fix handling of regular expressions containing
+         spaces. Thanks for Sebastian Harl for fixing this.
+       * rrdtool, rrdcached plugins: Improve precision of the XFF parameter.
+         Previously, values like 0.999 would have been rounded to 1.0. Thanks
+         to Francois-Xavier Bourlet for fixing this.
+       * varnish plugin: Fix data type handling of some metrics. Some values
+         were submitted as gauge even though they were derives.
+       * Various plugin: Set a multi-threading flag in libcurl. Thanks to Mike
+         Flisher for the fix.
+
+2011-03-28, Version 5.0.0
+       * collectd: The "FQDNLookup" option is now enabled by default.
+       * collectd: The internal representation of time has been changed to
+         allow a higher accuracy than one second.
+       * collectdcmd: This new command line utility can send various commands
+         to collectd using the UnixSock plugin. Thanks to Håkon Dugstad
+         Johnsen and Sebastian Harl for their code.
+       * collectd-nagios: The "-m" option has been implemented (treat NaNs as
+         critical).
+       * collectd-tg: Traffic generator creating bogus network traffic
+         compatible to the Network plugin. This utility can be used to
+         stress-test new write plugins and collectd in general.
+       * libcollectdclient: Creating and sending network packets has been
+         added to the collectd client library.
+       * All data sets: The data source name of all data sets with exactly
+         one data source has been changed to "value".
+       * All plugins: All "counter" data sources have been converted to
+         "derive" data sources. All plugins now use "derive" by default, but
+         plugins such as the network plugin can still handle "counter", of
+         course. The minimum value of all derive data sources is zero, the
+         maximum value is unspecified.
+       * amqp plugin: The new AMQP plugin can send data to and receive data
+         from an AMQP broker. Thanks to Sebastien Pahl for his code.
+       * apache plugin: Backwards compatibility code has been removed.
+         Support for the IBM HTTP Server has been added. Thanks to Manuel
+         Luis Sanmartín Rozada for his patch.
+       * contextswitch plugin: Support for sysctlbyname(3) has been added.
+         Thanks to Kimo Rosenbaum for his patch.
+       * df plugin: The default behavior has been changed to be equivalent to
+         the "ReportReserved" behavior of v4.
+       * dns plugin: Improved RFC 1035 name parsing has been imported from
+         "dnstop".
+       * exec plugin: Backwards compatibility code has been removed.
+       * GenericJMX plugin: The "InstancePrefix" option has been added to
+         "Connection" blocks.
+       * hddtemp plugin: The "TranslateDevicename" config option has been
+         removed.
+       * interface plugin: Use the "plugin instance" to store the interface
+         value.
+       * libvirt plugin: The "InterfaceFormat" option has been added. Thanks
+         to Ruben Kerkhof for his patch.
+       * lpar plugin: New plugins for "logical partitions", a virtualization
+         technique of POWER CPUs. Thanks to Aurélien Reynaud for his code and
+         patience.
+       * modbus plugin: Support for libmodbus 2.9.2 has been added and the
+         license has been changes to LGPLv2.1.
+       * mysql plugin: Backwards compatibility code has been removed. The
+         data sets used have been improved.
+       * network plugin: The default buffer size has been increased to
+         1452 bytes.
+       * perl plugin: Backwards compatibility code has been removed.
+       * postgresql plugin: Backwards compatibility code has been removed.
+       * redis plugin: Plugin for collecting statistics from Redis, a key-
+         value store, has been added. Thanks to Andres J. Diaz for his code.
+       * swap plugin: Implement collection of physical and virtual memory
+         statistics under Solaris. The new default is collecting physical
+         memory. Thanks to Aurélien Reynaud for his patches.
+       * threshold plugin: The threshold configuration has been moved into
+         this separate plugin.
+       * unixsock plugin: The "DeleteSocket" option has been added.
+       * varnish plugin: The new Varnish plugin reads statistics from
+         Varnish, a web accelerator. Thanks to Jérôme Renard and Marc
+         Fournier for their contributions.
+       * write_redis: New plugin for writing data to Redis, a key-value
+         store.
+       * zfs_arc plugin: The data sets have been replaced by more elegant
+         alternatives.
+       * v5upgrade target: Target for converting v4 data sets to the v5
+         schema.
+
 2012-11-11, Version 4.10.8
        * collectd: Create new directories with mode 0777 and let umask remove
          unwanted permission bits.
diff --git a/README b/README
index 34caa85..ac79ce5 100644 (file)
--- a/README
+++ b/README
@@ -125,6 +125,10 @@ Features
     - load
       System load average over the last 1, 5 and 15 minutes.
 
+    - lpar
+      Detailed CPU statistics of the “Logical Partitions” virtualization
+      technique built into IBM's POWER processors.
+
     - libvirt
       CPU, disk and network I/O statistics from virtual machines.
 
@@ -235,6 +239,10 @@ Features
       collectd without the need to start a heavy interpreter every interval.
       See collectd-python(5) for details.
 
+    - redis
+      The redis plugin gathers information from a redis server, including:
+      uptime, used memory, total connections etc.
+
     - routeros
       Query interface and wireless registration statistics from RouterOS.
 
@@ -288,6 +296,9 @@ Features
     - users
       Users currently logged in.
 
+    - varnish
+      Various statistics from Varnish, an HTTP accelerator.
+
     - vmem
       Virtual memory statistics, e. g. the number of page-ins/-outs or the
       number of pagefaults.
@@ -308,6 +319,10 @@ Features
   * Output can be written or sent to various destinations by the following
     plugins:
 
+    - amqp
+      Sends JSON-encoded data to an Advanced Message Queuing Protocol (AMQP)
+      server, such as RabbitMQ.
+
     - csv
       Write to comma separated values (CSV) files. This needs lots of
       diskspace but is extremely portable and can be analysed with almost
@@ -348,6 +363,9 @@ Features
       requests. The transmitted data is either in a form understood by the
       Exec plugin or formatted in JSON.
 
+    - write_redis
+      Sends the values to a Redis key-value database server.
+
   * Logging is, as everything in collectd, provided by plugins. The following
     plugins keep up informed about what's going on:
 
@@ -427,6 +445,10 @@ Features
 
   * Miscellaneous plugins:
 
+    - threshold
+      Checks values against configured thresholds and creates notifications if
+      values are out of bounds. See collectd-threshold(5) for details.
+
     - uuid
       Sets the hostname to an unique identifier. This is meant for setups
       where each client may migrate to another physical host, possibly going
@@ -504,6 +526,10 @@ Prerequisites
   * libclntsh (optional)
     Used by the `oracle' plugin.
 
+  * libcredis (optional)
+    Used by the redis plugin. Please note that you require a 0.2.2 version
+    or higher. <http://code.google.com/p/credis/>
+
   * libcurl (optional)
     If you want to use the `apache', `ascent', `curl', `nginx', or `write_http'
     plugin.
@@ -610,6 +636,10 @@ Prerequisites
     are supported.
     <http://www.python.org/>
 
+  * librabbitmq (optional; also called “rabbitmq-c”)
+    Used by the AMQP plugin for AMQP connections, for example to RabbitMQ.
+    <http://hg.rabbitmq.com/rabbitmq-c/>
+
   * librouteros (optional)
     Used by the `routeros' plugin to connect to a device running `RouterOS'.
     <http://verplant.org/librouteros/>
@@ -656,6 +686,10 @@ Prerequisites
     Parse JSON data. This is needed for the `curl_json' plugin.
     <http://github.com/lloyd/yajl>
 
+  * libvarnish (optional)
+     Fetches statistics from a Varnish instance. This is needed for the Varnish plugin
+     <http://varnish-cache.org>
+
 Configuring / Compiling / Installing
 ------------------------------------
 
index 3e492dd..410c61c 100644 (file)
@@ -29,5 +29,5 @@ package org.collectd.api;
  */
 public interface CollectdFlushInterface
 {
-       public int flush (int timeout, String identifier);
+       public int flush (Number timeout, String identifier);
 }
index 1baeff2..b8d6f40 100644 (file)
@@ -87,10 +87,16 @@ public class ValueList extends PluginData {
         _ds = new DataSet (_type, dsrc);
     }
 
+    /**
+     * Returns the interval (in milliseconds) of the value list.
+     */
     public long getInterval() {
         return _interval;
     }
 
+    /**
+     * Sets the interval (in milliseconds) of the value list.
+     */
     public void setInterval(long interval) {
         _interval = interval;
     }
index ffa9ded..0c81bc9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * collectd/java - org/collectd/java/GenericJMXConfConnection.java
- * Copyright (C) 2009  Florian octo Forster
+ * Copyright (C) 2009,2010  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
@@ -45,6 +45,7 @@ class GenericJMXConfConnection
   private String _username = null;
   private String _password = null;
   private String _host = null;
+  private String _instance_prefix = null;
   private String _service_url = null;
   private MBeanServerConnection _jmx_connection = null;
   private List<GenericJMXConfMBean> _mbeans = null;
@@ -162,6 +163,12 @@ private void connect () /* {{{ */
         if (tmp != null)
           this._service_url = tmp;
       }
+      else if (child.getKey ().equalsIgnoreCase ("InstancePrefix"))
+      {
+        String tmp = getConfigString (child);
+        if (tmp != null)
+          this._instance_prefix = tmp;
+      }
       else if (child.getKey ().equalsIgnoreCase ("Collect"))
       {
         String tmp = getConfigString (child);
@@ -211,7 +218,8 @@ private void connect () /* {{{ */
     {
       int status;
 
-      status = this._mbeans.get (i).query (this._jmx_connection, pd);
+      status = this._mbeans.get (i).query (this._jmx_connection, pd,
+          this._instance_prefix);
       if (status != 0)
       {
         this._jmx_connection = null;
index 1587bd5..b1fbfb3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * collectd/java - org/collectd/java/GenericJMXConfMBean.java
- * Copyright (C) 2009  Florian octo Forster
+ * Copyright (C) 2009,2010  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
@@ -67,22 +67,6 @@ class GenericJMXConfMBean
     return (v.getString ());
   } /* }}} String getConfigString */
 
-  private String join (String separator, List<String> list) /* {{{ */
-  {
-    StringBuffer sb;
-
-    sb = new StringBuffer ();
-
-    for (int i = 0; i < list.size (); i++)
-    {
-      if (i > 0)
-        sb.append ("-");
-      sb.append (list.get (i));
-    }
-
-    return (sb.toString ());
-  } /* }}} String join */
-
 /*
  * <MBean "alias name">
  *   ObjectName "object name"
@@ -170,7 +154,8 @@ class GenericJMXConfMBean
     return (this._name);
   } /* }}} */
 
-  public int query (MBeanServerConnection conn, PluginData pd) /* {{{ */
+  public int query (MBeanServerConnection conn, PluginData pd, /* {{{ */
+      String instance_prefix)
   {
     Set<ObjectName> names;
     Iterator<ObjectName> iter;
@@ -197,11 +182,12 @@ class GenericJMXConfMBean
       ObjectName   objName;
       PluginData   pd_tmp;
       List<String> instanceList;
-      String       instance;
+      StringBuffer instance;
 
       objName      = iter.next ();
       pd_tmp       = new PluginData (pd);
       instanceList = new ArrayList<String> ();
+      instance     = new StringBuffer ();
 
       Collectd.logDebug ("GenericJMXConfMBean: objName = "
           + objName.toString ());
@@ -224,14 +210,22 @@ class GenericJMXConfMBean
         }
       }
 
+      if (instance_prefix != null)
+        instance.append (instance_prefix);
+
       if (this._instance_prefix != null)
-        instance = new String (this._instance_prefix
-            + join ("-", instanceList));
-      else
-        instance = join ("-", instanceList);
-      pd_tmp.setPluginInstance (instance);
+        instance.append (this._instance_prefix);
+
+      for (int i = 0; i < instanceList.size (); i++)
+      {
+        if (i > 0)
+          instance.append ("-");
+        instance.append (instanceList.get (i));
+      }
+
+      pd_tmp.setPluginInstance (instance.toString ());
 
-      Collectd.logDebug ("GenericJMXConfMBean: instance = " + instance);
+      Collectd.logDebug ("GenericJMXConfMBean: instance = " + instance.toString ());
 
       for (int i = 0; i < this._values.size (); i++)
         this._values.get (i).query (conn, objName, pd_tmp);
index f1b5d85..ca3b5d2 100644 (file)
@@ -465,35 +465,6 @@ sub plugin_flush {
        }
 }
 
-sub plugin_flush_one {
-       my $timeout = shift;
-       my $name    = shift;
-
-       WARNING ("Collectd::plugin_flush_one is deprecated - "
-               . "use Collectd::plugin_flush instead.");
-
-       if (! (defined ($timeout) && defined ($name))) {
-               ERROR ("Usage: Collectd::plugin_flush_one(timeout, name)");
-               return;
-       }
-
-       plugin_flush (plugins => $name, timeout => $timeout);
-}
-
-sub plugin_flush_all {
-       my $timeout = shift;
-
-       WARNING ("Collectd::plugin_flush_all is deprecated - "
-               . "use Collectd::plugin_flush instead.");
-
-       if (! defined ($timeout)) {
-               ERROR ("Usage: Collectd::plugin_flush_all(timeout)");
-               return;
-       }
-
-       plugin_flush (timeout => $timeout);
-}
-
 sub fc_call {
        my $type    = shift;
        my $name    = shift;
index b2b496a..027bf9c 100644 (file)
@@ -91,6 +91,7 @@ fi
 if test "x$ac_system" = "xSolaris"
 then
        AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Define to enforce POSIX thread semantics under Solaris.])
+       AC_DEFINE(_REENTRANT,               1, [Define to enable reentrancy interfaces.])
 fi
 if test "x$ac_system" = "xAIX"
 then
@@ -109,9 +110,13 @@ AC_ARG_ENABLE(standards,
 if test "x$enable_standards" = "xyes"
 then
        AC_DEFINE(_ISOC99_SOURCE,        1, [Define to enforce ISO C99 compliance.])
-       AC_DEFINE(_POSIX_C_SOURCE, 200112L, [Define to enforce POSIX.1-2001 compliance.])
-       AC_DEFINE(_XOPEN_SOURCE,       600, [Define to enforce X/Open 6 (XSI) compliance.])
+       AC_DEFINE(_POSIX_C_SOURCE, 200809L, [Define to enforce POSIX.1-2008 compliance.])
+       AC_DEFINE(_XOPEN_SOURCE,       700, [Define to enforce X/Open 7 (XSI) compliance.])
        AC_DEFINE(_REENTRANT,            1, [Define to enable reentrancy interfaces.])
+       if test "x$GCC" = "xyes"
+       then
+               CFLAGS="$CFLAGS -std=c99"
+       fi
 fi
 AM_CONDITIONAL(BUILD_FEATURE_STANDARDS, test "x$enable_standards" = "xyes")
 
@@ -486,6 +491,8 @@ AC_CHECK_HEADERS(netinet/if_ether.h, [], [],
 #endif
 ])
 
+AC_CHECK_HEADERS(netinet/ip_compat.h)
+
 # For the multimeter plugin
 have_termios_h="no"
 AC_CHECK_HEADERS(termios.h, [have_termios_h="yes"])
@@ -587,6 +594,27 @@ socket_needs_socket="no"
 AC_CHECK_FUNCS(socket, [], AC_CHECK_LIB(socket, socket, [socket_needs_socket="yes"], AC_MSG_ERROR(cannot find socket)))
 AM_CONDITIONAL(BUILD_WITH_LIBSOCKET, test "x$socket_needs_socket" = "xyes")
 
+clock_gettime_needs_rt="no"
+clock_gettime_needs_posix4="no"
+have_clock_gettime="no"
+AC_CHECK_FUNCS(clock_gettime, [have_clock_gettime="yes"])
+if test "x$have_clock_gettime" = "xno"
+then
+       AC_CHECK_LIB(rt, clock_gettime, [clock_gettime_needs_rt="yes"
+                                        have_clock_gettime="yes"])
+fi
+if test "x$have_clock_gettime" = "xno"
+then
+       AC_CHECK_LIB(posix4, clock_gettime, [clock_gettime_needs_posix4="yes"
+                                            have_clock_gettime="yes"])
+fi
+if test "x$have_clock_gettime" = "xyes"
+then
+       AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if the clock_gettime(2) function is available.])
+else
+       AC_MSG_WARN(cannot find clock_gettime)
+fi
+
 nanosleep_needs_rt="no"
 nanosleep_needs_posix4="no"
 AC_CHECK_FUNCS(nanosleep,
@@ -596,8 +624,9 @@ AC_CHECK_FUNCS(nanosleep,
         AC_CHECK_LIB(posix4, nanosleep,
             [nanosleep_needs_posix4="yes"],
             AC_MSG_ERROR(cannot find nanosleep))))
-AM_CONDITIONAL(BUILD_WITH_LIBRT, test "x$nanosleep_needs_rt" = "xyes")
-AM_CONDITIONAL(BUILD_WITH_LIBPOSIX4, test "x$nanosleep_needs_posix4" = "xyes")
+
+AM_CONDITIONAL(BUILD_WITH_LIBRT, test "x$clock_gettime_needs_rt" = "xyes" || test "x$nanosleep_needs_rt" = "xyes")
+AM_CONDITIONAL(BUILD_WITH_LIBPOSIX4, test "x$clock_gettime_needs_posix4" = "xyes" || test "x$nanosleep_needs_posix4" = "xyes")
 
 AC_CHECK_FUNCS(sysctl, [have_sysctl="yes"], [have_sysctl="no"])
 AC_CHECK_FUNCS(sysctlbyname, [have_sysctlbyname="yes"], [have_sysctlbyname="no"])
@@ -607,13 +636,127 @@ AC_CHECK_FUNCS(thread_info, [have_thread_info="yes"], [have_thread_info="no"])
 AC_CHECK_FUNCS(statfs, [have_statfs="yes"], [have_statfs="no"])
 AC_CHECK_FUNCS(statvfs, [have_statvfs="yes"], [have_statvfs="no"])
 AC_CHECK_FUNCS(getifaddrs, [have_getifaddrs="yes"], [have_getifaddrs="no"])
+AC_CHECK_FUNCS(getloadavg, [have_getloadavg="yes"], [have_getloadavg="no"])
 AC_CHECK_FUNCS(syslog, [have_syslog="yes"], [have_syslog="no"])
 AC_CHECK_FUNCS(getutent, [have_getutent="yes"], [have_getutent="no"])
 AC_CHECK_FUNCS(getutxent, [have_getutxent="yes"], [have_getutxent="no"])
-AC_CHECK_FUNCS(swapctl, [have_swapctl="yes"], [have_swapctl="no"])
 
-# For load module
-AC_CHECK_FUNCS(getloadavg, [have_getloadavg="yes"], [have_getloadavg="no"])
+# Check for strptime {{{
+if test "x$GCC" = "xyes"
+then
+       SAVE_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -Wall -Wextra -Werror"
+fi
+
+AC_CHECK_FUNCS(strptime, [have_strptime="yes"], [have_strptime="no"])
+if test "x$have_strptime" = "xyes"
+then
+       AC_CACHE_CHECK([whether strptime is exported by default],
+                      [c_cv_have_strptime_default],
+                      AC_COMPILE_IFELSE(
+AC_LANG_PROGRAM(
+[[
+AC_INCLUDES_DEFAULT
+#include <time.h>
+]],
+[[
+ struct tm stm;
+ (void) strptime ("2010-12-30%13:42:42", "%Y-%m-%dT%T", &stm);
+]]),
+                      [c_cv_have_strptime_default="yes"],
+                      [c_cv_have_strptime_default="no"]))
+fi
+if test "x$have_strptime" = "xyes" && test "x$c_cv_have_strptime_default" = "xno"
+then
+       AC_CACHE_CHECK([whether strptime needs standards mode],
+                      [c_cv_have_strptime_standards],
+                      AC_COMPILE_IFELSE(
+AC_LANG_PROGRAM(
+[[
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE 1
+#endif
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 500
+#endif
+AC_INCLUDES_DEFAULT
+#include <time.h>
+]],
+[[
+ struct tm stm;
+ (void) strptime ("2010-12-30%13:42:42", "%Y-%m-%dT%T", &stm);
+]]),
+                      [c_cv_have_strptime_standards="yes"],
+                      [c_cv_have_strptime_standards="no"]))
+
+       if test "x$c_cv_have_strptime_standards" = "xyes"
+       then
+               AC_DEFINE([STRPTIME_NEEDS_STANDARDS], 1, [Set to true if strptime is only exported in X/Open mode (GNU libc).])
+       else
+               have_strptime="no"
+       fi
+fi
+
+if test "x$GCC" = "xyes"
+then
+       CFLAGS="$SAVE_CFLAGS"
+fi
+
+# }}} Check for strptime
+
+AC_CHECK_FUNCS(swapctl, [have_swapctl="yes"], [have_swapctl="no"])
+if test "x$have_swapctl" = "xyes"; then
+        AC_CACHE_CHECK([whether swapctl takes two arguments],
+                [c_cv_have_swapctl_two_args],
+                AC_COMPILE_IFELSE(
+                        AC_LANG_PROGRAM([[AC_INCLUDES_DEFAULT
+#if HAVE_SYS_SWAP_H && !defined(_LP64) && _FILE_OFFSET_BITS == 64
+#  undef _FILE_OFFSET_BITS
+#  undef _LARGEFILE64_SOURCE
+#endif
+#include <sys/stat.h>
+#include <sys/swap.h>]],
+                                [[
+                                int num = swapctl(0, NULL);
+                                ]]
+                        ),
+                        [c_cv_have_swapctl_two_args="yes"],
+                        [c_cv_have_swapctl_two_args="no"]
+                )
+        )
+        AC_CACHE_CHECK([whether swapctl takes three arguments],
+                [c_cv_have_swapctl_three_args],
+                AC_COMPILE_IFELSE(
+                        AC_LANG_PROGRAM([[AC_INCLUDES_DEFAULT
+#if HAVE_SYS_SWAP_H && !defined(_LP64) && _FILE_OFFSET_BITS == 64
+#  undef _FILE_OFFSET_BITS
+#  undef _LARGEFILE64_SOURCE
+#endif
+#include <sys/stat.h>
+#include <sys/swap.h>]],
+                                [[
+                                int num = swapctl(0, NULL,0);
+                                ]]
+                        ),
+                        [c_cv_have_swapctl_three_args="yes"],
+                        [c_cv_have_swapctl_three_args="no"]
+                )
+        )
+fi
+# Check for different versions of `swapctl' here..
+if test "x$have_swapctl" = "xyes"; then
+        if test "x$c_cv_have_swapctl_two_args" = "xyes"; then
+                AC_DEFINE(HAVE_SWAPCTL_TWO_ARGS, 1,
+                          [Define if the function swapctl exists and takes two arguments.])
+        fi
+        if test "x$c_cv_have_swapctl_three_args" = "xyes"; then
+                AC_DEFINE(HAVE_SWAPCTL_THREE_ARGS, 1,
+                          [Define if the function swapctl exists and takes three arguments.])
+        fi
+fi
 
 # Check for NAN
 AC_ARG_WITH(nan-emulation, [AS_HELP_STRING([--with-nan-emulation], [use emulated NAN. For crosscompiling only.])],
@@ -635,7 +778,7 @@ if test "x$nan_type" = "xnone"; then
       [[
 #include <stdlib.h>
 #include <math.h>
-static float foo = NAN;
+static double foo = NAN;
       ]],
       [[
        if (isnan (foo))
@@ -661,7 +804,7 @@ if test "x$nan_type" = "xnone"; then
 #include <stdlib.h>
 #define __USE_ISOC99 1
 #include <math.h>
-static float foo = NAN;
+static double foo = NAN;
       ]],
       [[
        if (isnan (foo))
@@ -695,7 +838,7 @@ if test "x$nan_type" = "xnone"; then
 #ifndef isnan
 # define isnan(f) ((f) != (f))
 #endif
-static float foo = NAN;
+static double foo = NAN;
       ]],
       [[
        if (isnan (foo))
@@ -1165,6 +1308,12 @@ fi
 if test "x$with_perfstat" = "xyes"
 then
         AC_DEFINE(HAVE_PERFSTAT, 1, [Define to 1 if you have the 'perfstat' library (-lperfstat)])
+        # struct members pertaining to donation have been added to libperfstat somewhere between AIX5.3ML5 and AIX5.3ML9
+        AC_CHECK_MEMBER([perfstat_partition_type_t.b.donate_enabled], [], [], [[#include <libperfstat.h]])
+        if test "x$av_cv_member_perfstat_partition_type_t_b_donate_enabled" = "xyes"
+        then
+               AC_DEFINE(PERFSTAT_SUPPORTS_DONATION, 1, [Define to 1 if your version of the 'perfstat' library supports donation])
+        fi
 fi
 AM_CONDITIONAL(BUILD_WITH_PERFSTAT, test "x$with_perfstat" = "xyes")
 
@@ -1252,6 +1401,64 @@ then
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBKVM_OPENFILES, test "x$with_kvm_openfiles" = "xyes")
 
+# --with-libcredis {{{
+AC_ARG_WITH(libcredis, [AS_HELP_STRING([--with-libcredis@<:@=PREFIX@:>@], [Path to libcredis.])],
+[
+ if test "x$withval" = "xyes"
+ then
+        with_libcredis="yes"
+ else if test "x$withval" = "xno"
+ then
+        with_libcredis="no"
+ else
+        with_libcredis="yes"
+        LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS -I$withval/include"
+        LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS -L$withval/lib"
+ fi; fi
+],
+[with_libcredis="yes"])
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+
+CPPFLAGS="$CPPFLAGS $LIBCREDIS_CPPFLAGS"
+LDFLAGS="$LDFLAGS $LIBCREDIS_LDFLAGS"
+
+if test "x$with_libcredis" = "xyes"
+then
+       if test "x$LIBCREDIS_CPPFLAGS" != "x"
+       then
+               AC_MSG_NOTICE([libcredis CPPFLAGS: $LIBCREDIS_CPPFLAGS])
+       fi
+       AC_CHECK_HEADERS(credis.h,
+       [with_libcredis="yes"],
+       [with_libcredis="no (credis.h not found)"])
+fi
+if test "x$with_libcredis" = "xyes"
+then
+       if test "x$LIBCREDIS_LDFLAGS" != "x"
+       then
+               AC_MSG_NOTICE([libcredis LDFLAGS: $LIBCREDIS_LDFLAGS])
+       fi
+       AC_CHECK_LIB(credis, credis_info,
+       [with_libcredis="yes"],
+       [with_libcredis="no (symbol 'credis_info' not found)"])
+
+fi
+
+CPPFLAGS="$SAVE_CPPFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
+
+if test "x$with_libcredis" = "xyes"
+then
+       BUILD_WITH_LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS"
+       BUILD_WITH_LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS"
+       AC_SUBST(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_LIBCREDIS_LDFLAGS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBCREDIS, test "x$with_libcredis" = "xyes")
+# }}}
+
 # --with-libcurl {{{
 with_curl_config="curl-config"
 with_curl_cflags=""
@@ -1957,7 +2164,7 @@ then
        $PKG_CONFIG --exists 'modbus' 2>/dev/null
        if test $? -ne 0
        then
-               with_libmodbus="no (pkg-config doesn't know library)"
+               with_libmodbus="no (pkg-config doesn't know modbus)"
        fi
 fi
 if test "x$with_libmodbus" = "xuse_pkgconfig"
@@ -1997,9 +2204,9 @@ then
        CPPFLAGS="$CPPFLAGS $with_libmodbus_cflags"
        LDFLAGS="$LDFLAGS $with_libmodbus_libs"
 
-       AC_CHECK_LIB(modbus, modbus_init_tcp,
+       AC_CHECK_LIB(modbus, modbus_connect,
                     [with_libmodbus="yes"],
-                    [with_libmodbus="no (symbol modbus_init_tcp not found)"])
+                    [with_libmodbus="no (symbol modbus_connect not found)"])
 
        CPPFLAGS="$SAVE_CPPFLAGS"
        LDFLAGS="$SAVE_LDFLAGS"
@@ -2491,7 +2698,7 @@ then
        fi
        AC_CHECK_HEADERS(oping.h,
        [with_liboping="yes"],
-       [with_liboping="no ('oping.h' not found)"])
+       [with_liboping="no (oping.h not found)"])
 fi
 if test "x$with_liboping" = "xyes"
 then
@@ -2662,7 +2869,8 @@ then
 fi
 if test "x$with_libpcap" = "xyes"
 then
-       AC_CHECK_HEADERS(pcap-bpf.h)
+       AC_CHECK_HEADERS(pcap-bpf.h,,
+                        [with_libpcap="no (pcap-bpf.h not found)"])
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBPCAP, test "x$with_libpcap" = "xyes")
 # }}}
@@ -3097,6 +3305,72 @@ then
 fi
 # }}} --with-python
 
+# --with-librabbitmq {{{
+with_librabbitmq_cppflags=""
+with_librabbitmq_ldflags=""
+AC_ARG_WITH(librabbitmq, [AS_HELP_STRING([--with-librabbitmq@<:@=PREFIX@:>@], [Path to librabbitmq.])],
+[
+       if test "x$withval" != "xno" && test "x$withval" != "xyes"
+       then
+               with_librabbitmq_cppflags="-I$withval/include"
+               with_librabbitmq_ldflags="-L$withval/lib"
+               with_librabbitmq="yes"
+       else
+               with_librabbitmq="$withval"
+       fi
+],
+[
+       with_librabbitmq="yes"
+])
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
+LDFLAGS="$LDFLAGS $with_librabbitmq_ldflags"
+if test "x$with_librabbitmq" = "xyes"
+then
+       AC_CHECK_HEADERS(amqp.h, [with_librabbitmq="yes"], [with_librabbitmq="no (amqp.h not found)"])
+fi
+if test "x$with_librabbitmq" = "xyes"
+then
+       # librabbitmq up to version 0.9.1 provides "library_errno", later
+       # versions use "library_error". The library does not provide a version
+       # macro :( Use "AC_CHECK_MEMBERS" (plural) for automatic defines.
+       AC_CHECK_MEMBERS([amqp_rpc_reply_t.library_errno],,,
+                        [
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_STDIO_H
+# include <stdio.h>
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#include <amqp.h>
+                         ])
+fi
+if test "x$with_librabbitmq" = "xyes"
+then
+       AC_CHECK_LIB(rabbitmq, amqp_basic_publish, [with_librabbitmq="yes"], [with_librabbitmq="no (Symbol 'amqp_basic_publish' not found)"])
+fi
+if test "x$with_librabbitmq" = "xyes"
+then
+       BUILD_WITH_LIBRABBITMQ_CPPFLAGS="$with_librabbitmq_cppflags"
+       BUILD_WITH_LIBRABBITMQ_LDFLAGS="$with_librabbitmq_ldflags"
+       BUILD_WITH_LIBRABBITMQ_LIBS="-lrabbitmq"
+       AC_SUBST(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
+       AC_SUBST(BUILD_WITH_LIBRABBITMQ_LIBS)
+       AC_DEFINE(HAVE_LIBRABBITMQ, 1, [Define if librabbitmq is present and usable.])
+fi
+CPPFLAGS="$SAVE_CPPFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
+AM_CONDITIONAL(BUILD_WITH_LIBRABBITMQ, test "x$with_librabbitmq" = "xyes")
+# }}}
+
 # --with-librouteros {{{
 AC_ARG_WITH(librouteros, [AS_HELP_STRING([--with-librouteros@<:@=PREFIX@:>@], [Path to librouteros.])],
 [
@@ -3128,7 +3402,7 @@ then
        fi
        AC_CHECK_HEADERS(routeros_api.h,
        [with_librouteros="yes"],
-       [with_librouteros="no ('routeros_api.h' not found)"])
+       [with_librouteros="no (routeros_api.h not found)"])
 fi
 if test "x$with_librouteros" = "xyes"
 then
@@ -3327,7 +3601,7 @@ then
     if test "$?" != "0"
     then
       with_libstatgrab_pkg_config="no"
-      with_libstatgrab="no ($PKG_CONFIG doesn't know libstatgrab)"
+      with_libstatgrab="no (pkg-config doesn't know libstatgrab)"
       temp_result="not found"
     fi
     AC_MSG_RESULT([$temp_result])
@@ -3547,7 +3821,7 @@ then
        $PKG_CONFIG --exists 'libupsclient' 2>/dev/null
        if test $? -ne 0
        then
-               with_libupsclient="no (pkg-config doesn't know library)"
+               with_libupsclient="no (pkg-config doesn't know libupsclient)"
        fi
 fi
 if test "x$with_libupsclient" = "xuse_pkgconfig"
@@ -3737,6 +4011,98 @@ fi
 AM_CONDITIONAL(BUILD_WITH_LIBYAJL, test "x$with_libyajl" = "xyes")
 # }}}
 
+# --with-libvarnish {{{
+with_libvarnish_cppflags=""
+with_libvarnish_cflags=""
+with_libvarnish_libs=""
+AC_ARG_WITH(libvarnish, [AS_HELP_STRING([--with-libvarnish@<:@=PREFIX@:>@], [Path to libvarnish.])],
+[
+       if test "x$withval" = "xno"
+       then
+               with_libvarnish="no"
+       else if test "x$withval" = "xyes"
+       then
+               with_libvarnish="use_pkgconfig"
+       else if test -d "$with_libvarnish/lib"
+       then
+               AC_MSG_NOTICE([Not checking for libvarnish: Manually configured])
+               with_libvarnish_cflags="-I$withval/include"
+               with_libvarnish_libs="-L$withval/lib -lvarnishapi"
+               with_libvarnish="yes"
+       fi; fi; fi
+],
+[with_libvarnish="use_pkgconfig"])
+
+# configure using pkg-config
+if test "x$with_libvarnish" = "xuse_pkgconfig"
+then
+       if test "x$PKG_CONFIG" = "x"
+       then
+               with_libvarnish="no (Don't have pkg-config)"
+       fi
+fi
+if test "x$with_libvarnish" = "xuse_pkgconfig"
+then
+       AC_MSG_NOTICE([Checking for varnishapi using $PKG_CONFIG])
+       $PKG_CONFIG --exists 'varnishapi' 2>/dev/null
+       if test $? -ne 0
+       then
+               with_libvarnish="no (pkg-config doesn't know varnishapi)"
+       fi
+fi
+if test "x$with_libvarnish" = "xuse_pkgconfig"
+then
+       with_libvarnish_cflags="`$PKG_CONFIG --cflags 'varnishapi'`"
+       if test $? -ne 0
+       then
+               with_libvarnish="no ($PKG_CONFIG failed)"
+       fi
+       with_libvarnish_libs="`$PKG_CONFIG --libs 'varnishapi'`"
+       if test $? -ne 0
+       then
+               with_libvarnish="no ($PKG_CONFIG failed)"
+       fi
+fi
+if test "x$with_libvarnish" = "xuse_pkgconfig"
+then
+       with_libvarnish="yes"
+fi
+
+# with_libvarnish_cflags and with_libvarnish_libs are set up now, let's do
+# the actual checks.
+if test "x$with_libvarnish" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_libvarnish_cflags"
+       AC_CHECK_HEADERS(varnish/varnishapi.h, [], [with_libvarnish="no (varnish/varnishapi.h not found)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libvarnish" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       #SAVE_LDFLAGS="$LDFLAGS"
+
+       CPPFLAGS="$CPPFLAGS $with_libvarnish_cflags"
+       #LDFLAGS="$LDFLAGS $with_libvarnish_libs"
+
+       AC_CHECK_LIB(varnishapi, VSL_OpenStats,
+                    [with_libvarnish="yes"],
+                    [with_libvarnish="no (symbol VSL_OpenStats not found)"],
+                    [$with_libvarnish_libs])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+       #LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_libvarnish" = "xyes"
+then
+       BUILD_WITH_LIBVARNISH_CFLAGS="$with_libvarnish_cflags"
+       BUILD_WITH_LIBVARNISH_LIBS="$with_libvarnish_libs"
+       AC_SUBST(BUILD_WITH_LIBVARNISH_CFLAGS)
+       AC_SUBST(BUILD_WITH_LIBVARNISH_LIBS)
+fi
+# }}}
+
 # pkg-config --exists 'libxml-2.0'; pkg-config --exists libvirt {{{
 with_libxml2="no (pkg-config isn't available)"
 with_libxml2_cflags=""
@@ -3751,7 +4117,7 @@ then
        then
                with_libxml2="yes"
        else
-               with_libxml2="no (pkg-config doesn't know library)"
+               with_libxml2="no (pkg-config doesn't know libxml-2.0)"
        fi
 
        pkg-config --exists libvirt 2>/dev/null
@@ -3759,7 +4125,7 @@ then
        then
                with_libvirt="yes"
        else
-               with_libvirt="no (pkg-config doesn't know library)"
+               with_libvirt="no (pkg-config doesn't know libvirt)"
        fi
 fi
 if test "x$with_libxml2" = "xyes"
@@ -3876,7 +4242,7 @@ then
        $PKG_CONFIG --exists OpenIPMIpthread 2>/dev/null
        if test "$?" != "0"
        then
-               with_libopenipmipthread="no ($PKG_CONFIG doesn't know OpenIPMIpthread)"
+               with_libopenipmipthread="no (pkg-config doesn't know OpenIPMIpthread)"
        fi
        AC_MSG_RESULT([$with_libopenipmipthread])
 fi
@@ -3937,7 +4303,11 @@ fi
 
 PKG_CHECK_MODULES([LIBNOTIFY], [libnotify],
                [with_libnotify="yes"],
-               [with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"])
+               [if test "x$LIBNOTIFY_PKG_ERRORS" = "x"; then
+                        with_libnotify="no"
+                else
+                        with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"
+                fi])
 
 # Check for enabled/disabled features
 #
@@ -4180,11 +4550,6 @@ then
        plugin_tape="yes"
 fi
 
-if test "x$have_sys_swap_h$with_kstat$ac_system" = "xyesyesSolaris"
-then
-       plugin_swap="yes"
-fi
-
 # libstatgrab
 if test "x$with_libstatgrab" = "xyes"
 then
@@ -4200,7 +4565,10 @@ fi
 if test "x$with_libcurl" = "xyes" && test "x$with_libxml2" = "xyes"
 then
        plugin_ascent="yes"
-       plugin_bind="yes"
+       if test "x$have_strptime" = "xyes"
+       then
+               plugin_bind="yes"
+       fi
 fi
 
 if test "x$with_libopenipmipthread" = "xyes"
@@ -4226,11 +4594,15 @@ if test "x$have_sysctl" = "xyes"
 then
        plugin_cpu="yes"
        plugin_memory="yes"
-       plugin_swap="yes"
        plugin_uptime="yes"
+       if test "x$ac_system" = "xDarwin"
+       then
+               plugin_swap="yes"
+       fi
 fi
 if test "x$have_sysctlbyname" = "xyes"
 then
+       plugin_contextswitch="yes"
        plugin_cpu="yes"
        plugin_memory="yes"
        plugin_tcpconns="yes"
@@ -4318,7 +4690,7 @@ then
        plugin_swap="yes"
 fi
 
-if test "x$have_swapctl" = "xyes"
+if test "x$have_swapctl" = "xyes" && test "x$c_cv_have_swapctl_two_args" = "xyes"
 then
        plugin_swap="yes"
 fi
@@ -4358,6 +4730,7 @@ AC_ARG_ENABLE([all-plugins],
 
 m4_divert_once([HELP_ENABLE], [])
 
+AC_PLUGIN([amqp],        [$with_librabbitmq],  [AMQP output plugin])
 AC_PLUGIN([apache],      [$with_libcurl],      [Apache httpd statistics])
 AC_PLUGIN([apcups],      [yes],                [Statistics of UPSes by APC])
 AC_PLUGIN([apple_sensors], [$with_libiokit],   [Apple's hardware sensors])
@@ -4392,6 +4765,7 @@ AC_PLUGIN([java],        [$with_java],         [Embed the Java Virtual Machine])
 AC_PLUGIN([libvirt],     [$plugin_libvirt],    [Virtual machine statistics])
 AC_PLUGIN([load],        [$plugin_load],       [System load])
 AC_PLUGIN([logfile],     [yes],                [File logging plugin])
+AC_PLUGIN([lpar],        [$with_perfstat],     [AIX logical partitions statistics])
 AC_PLUGIN([madwifi],     [$have_linux_wireless_h], [Madwifi wireless statistics])
 AC_PLUGIN([match_empty_counter], [yes],        [The empty counter match])
 AC_PLUGIN([match_hashed], [yes],               [The hashed match])
@@ -4427,6 +4801,7 @@ AC_PLUGIN([powerdns],    [yes],                [PowerDNS statistics])
 AC_PLUGIN([processes],   [$plugin_processes],  [Process statistics])
 AC_PLUGIN([protocols],   [$plugin_protocols],  [Protocol (IP, TCP, ...) statistics])
 AC_PLUGIN([python],      [$with_python],       [Embed a Python interpreter])
+AC_PLUGIN([redis],       [$with_libcredis],    [Redis plugin])
 AC_PLUGIN([routeros],    [$with_librouteros],  [RouterOS plugin])
 AC_PLUGIN([rrdcached],   [$librrd_rrdc_update], [RRDTool output plugin])
 AC_PLUGIN([rrdtool],     [$with_librrd],       [RRDTool output plugin])
@@ -4442,19 +4817,23 @@ AC_PLUGIN([target_notification], [yes],        [The notification target])
 AC_PLUGIN([target_replace], [yes],             [The replace target])
 AC_PLUGIN([target_scale],[yes],                [The scale target])
 AC_PLUGIN([target_set],  [yes],                [The set target])
+AC_PLUGIN([target_v5upgrade], [yes],           [The v5upgrade target])
 AC_PLUGIN([tcpconns],    [$plugin_tcpconns],   [TCP connection statistics])
 AC_PLUGIN([teamspeak2],  [yes],                [TeamSpeak2 server statistics])
 AC_PLUGIN([ted],         [$plugin_ted],        [Read The Energy Detective values])
 AC_PLUGIN([thermal],     [$plugin_thermal],    [Linux ACPI thermal zone statistics])
+AC_PLUGIN([threshold],   [yes],                [Threshold checking plugin])
 AC_PLUGIN([tokyotyrant], [$with_libtokyotyrant],  [TokyoTyrant database statistics])
 AC_PLUGIN([unixsock],    [yes],                [Unixsock communication plugin])
 AC_PLUGIN([uptime],      [$plugin_uptime],     [Uptime statistics])
 AC_PLUGIN([users],       [$plugin_users],      [User statistics])
 AC_PLUGIN([uuid],        [yes],                [UUID as hostname plugin])
+AC_PLUGIN([varnish],     [$with_libvarnish],   [Varnish cache statistics])
 AC_PLUGIN([vmem],        [$plugin_vmem],       [Virtual memory statistics])
 AC_PLUGIN([vserver],     [$plugin_vserver],    [Linux VServer statistics])
 AC_PLUGIN([wireless],    [$plugin_wireless],   [Wireless statistics])
 AC_PLUGIN([write_http],  [$with_libcurl],      [HTTP output plugin])
+AC_PLUGIN([write_redis], [$with_libcredis],    [Redis output plugin])
 AC_PLUGIN([xmms],        [$with_libxmms],      [XMMS statistics])
 AC_PLUGIN([zfs_arc],     [$plugin_zfs_arc],    [ZFS ARC statistics])
 
@@ -4629,6 +5008,7 @@ Configuration:
   Libraries:
     libcurl . . . . . . . $with_libcurl
     libdbi  . . . . . . . $with_libdbi
+    libcredis . . . . . . $with_libcredis
     libesmtp  . . . . . . $with_libesmtp
     libganglia  . . . . . $with_libganglia
     libgcrypt . . . . . . $with_libgcrypt
@@ -4652,12 +5032,14 @@ Configuration:
     libperl . . . . . . . $with_libperl
     libpq . . . . . . . . $with_libpq
     libpthread  . . . . . $with_libpthread
+    librabbitmq . . . . . $with_librabbitmq
     librouteros . . . . . $with_librouteros
     librrd  . . . . . . . $with_librrd
     libsensors  . . . . . $with_libsensors
     libstatgrab . . . . . $with_libstatgrab
     libtokyotyrant  . . . $with_libtokyotyrant
     libupsclient  . . . . $with_libupsclient
+    libvarnish  . . . . . $with_libvarnish
     libvirt . . . . . . . $with_libvirt
     libxml2 . . . . . . . $with_libxml2
     libxmms . . . . . . . $with_libxmms
@@ -4675,6 +5057,7 @@ Configuration:
     perl  . . . . . . . . $with_perl_bindings
 
   Modules:
+    amqp    . . . . . . . $enable_amqp
     apache  . . . . . . . $enable_apache
     apcups  . . . . . . . $enable_apcups
     apple_sensors . . . . $enable_apple_sensors
@@ -4709,6 +5092,7 @@ Configuration:
     libvirt . . . . . . . $enable_libvirt
     load  . . . . . . . . $enable_load
     logfile . . . . . . . $enable_logfile
+    lpar... . . . . . . . $enable_lpar
     madwifi . . . . . . . $enable_madwifi
     match_empty_counter . $enable_match_empty_counter
     match_hashed  . . . . $enable_match_hashed
@@ -4743,6 +5127,7 @@ Configuration:
     processes . . . . . . $enable_processes
     protocols . . . . . . $enable_protocols
     python  . . . . . . . $enable_python
+    redis . . . . . . . . $enable_redis
     routeros  . . . . . . $enable_routeros
     rrdcached . . . . . . $enable_rrdcached
     rrdtool . . . . . . . $enable_rrdtool
@@ -4758,19 +5143,23 @@ Configuration:
     target_replace  . . . $enable_target_replace
     target_scale  . . . . $enable_target_scale
     target_set  . . . . . $enable_target_set
+    target_v5upgrade  . . $enable_target_v5upgrade
     tcpconns  . . . . . . $enable_tcpconns
     teamspeak2  . . . . . $enable_teamspeak2
     ted . . . . . . . . . $enable_ted
     thermal . . . . . . . $enable_thermal
+    threshold . . . . . . $enable_threshold
     tokyotyrant . . . . . $enable_tokyotyrant
     unixsock  . . . . . . $enable_unixsock
     uptime  . . . . . . . $enable_uptime
     users . . . . . . . . $enable_users
     uuid  . . . . . . . . $enable_uuid
+    varnish . . . . . . . $enable_varnish
     vmem  . . . . . . . . $enable_vmem
     vserver . . . . . . . $enable_vserver
     wireless  . . . . . . $enable_wireless
     write_http  . . . . . $enable_write_http
+    write_redis . . . . . $enable_write_redis
     xmms  . . . . . . . . $enable_xmms
     zfs_arc . . . . . . . $enable_zfs_arc
 
index 445b183..9af0fb0 100644 (file)
@@ -4,19 +4,23 @@
 #
 # Copyright © 2009 Adrian Perez <aperez@igalia.com>
 #
-# Distributed under terms of the GPLv2 license.
+# Distributed under terms of the GPLv2 license or newer.
+# 
+# Frank Marien (frank@apsu.be) 6 Sep 2012
+# - quick fixes for 5.1 binary protocol
+# - updated to python 3
+# - fixed for larger packet sizes (possible on lo interface)
+# - fixed comment typo (decode_network_string decodes a string)
 
 """
 Collectd network protocol implementation.
 """
 
-import socket
-import struct
-
+import socket,struct,sys
 try:
-    from cStringIO import StringIO
+  from io import StringIO
 except ImportError:
-    from StringIO import StringIO
+  from cStringIO import StringIO
 
 from datetime import datetime
 from copy import deepcopy
@@ -31,17 +35,19 @@ DEFAULT_IPv4_GROUP = "239.192.74.66"
 DEFAULT_IPv6_GROUP = "ff18::efc0:4a42"
 """Default IPv6 multicast group"""
 
-
+HR_TIME_DIV = (2.0**30)
 
 # Message kinds
 TYPE_HOST            = 0x0000
 TYPE_TIME            = 0x0001
+TYPE_TIME_HR         = 0x0008
 TYPE_PLUGIN          = 0x0002
 TYPE_PLUGIN_INSTANCE = 0x0003
 TYPE_TYPE            = 0x0004
 TYPE_TYPE_INSTANCE   = 0x0005
 TYPE_VALUES          = 0x0006
 TYPE_INTERVAL        = 0x0007
+TYPE_INTERVAL_HR     = 0x0009
 
 # For notifications
 TYPE_MESSAGE         = 0x0100
@@ -50,14 +56,14 @@ TYPE_SEVERITY        = 0x0101
 # DS kinds
 DS_TYPE_COUNTER      = 0
 DS_TYPE_GAUGE        = 1
-
+DS_TYPE_DERIVE       = 2
+DS_TYPE_ABSOLUTE     = 3
 
 header = struct.Struct("!2H")
 number = struct.Struct("!Q")
 short  = struct.Struct("!H")
 double = struct.Struct("<d")
 
-
 def decode_network_values(ptype, plen, buf):
     """Decodes a list of DS values in collectd network format
     """
@@ -70,13 +76,19 @@ def decode_network_values(ptype, plen, buf):
     assert double.size == number.size
 
     result = []
-    for dstype in map(ord, buf[header.size+short.size:off]):
+    for dstype in buf[header.size+short.size:off]:
         if dstype == DS_TYPE_COUNTER:
             result.append((dstype, number.unpack_from(buf, off)[0]))
             off += valskip
         elif dstype == DS_TYPE_GAUGE:
             result.append((dstype, double.unpack_from(buf, off)[0]))
             off += valskip
+        elif dstype == DS_TYPE_DERIVE:
+            result.append((dstype, number.unpack_from(buf, off)[0]))
+            off += valskip
+        elif dstype == DS_TYPE_ABSOLUTE:
+            result.append((dstype, number.unpack_from(buf, off)[0]))
+            off += valskip
         else:
             raise ValueError("DS type %i unsupported" % dstype)
 
@@ -84,13 +96,13 @@ def decode_network_values(ptype, plen, buf):
 
 
 def decode_network_number(ptype, plen, buf):
-    """Decodes a number (64-bit unsigned) in collectd network format.
+    """Decodes a number (64-bit unsigned) from collectd network format.
     """
     return number.unpack_from(buf, header.size)[0]
 
 
 def decode_network_string(msgtype, plen, buf):
-    """Decodes a floating point number (64-bit) in collectd network format.
+    """Decodes a string from collectd network format.
     """
     return buf[header.size:plen-1]
 
@@ -99,7 +111,9 @@ def decode_network_string(msgtype, plen, buf):
 _decoders = {
     TYPE_VALUES         : decode_network_values,
     TYPE_TIME           : decode_network_number,
+    TYPE_TIME_HR        : decode_network_number,
     TYPE_INTERVAL       : decode_network_number,
+    TYPE_INTERVAL_HR    : decode_network_number,
     TYPE_HOST           : decode_network_string,
     TYPE_PLUGIN         : decode_network_string,
     TYPE_PLUGIN_INSTANCE: decode_network_string,
@@ -115,6 +129,7 @@ def decode_network_packet(buf):
     """
     off = 0
     blen = len(buf)
+
     while off < blen:
         ptype, plen = header.unpack_from(buf, off)
 
@@ -128,9 +143,6 @@ def decode_network_packet(buf):
         off += plen
 
 
-
-
-
 class Data(object):
     time = 0
     host = None
@@ -140,7 +152,7 @@ class Data(object):
     typeinstance = None
 
     def __init__(self, **kw):
-        [setattr(self, k, v) for k, v in kw.iteritems()]
+        [setattr(self, k, v) for k, v in kw.items()]
 
     @property
     def datetime(self):
@@ -150,19 +162,19 @@ class Data(object):
     def source(self):
         buf = StringIO()
         if self.host:
-            buf.write(self.host)
+            buf.write(str(self.host))
         if self.plugin:
             buf.write("/")
-            buf.write(self.plugin)
+            buf.write(str(self.plugin))
         if self.plugininstance:
             buf.write("/")
-            buf.write(self.plugininstance)
+            buf.write(str(self.plugininstance))
         if self.type:
             buf.write("/")
-            buf.write(self.type)
+            buf.write(str(self.type))
         if self.typeinstance:
             buf.write("/")
-            buf.write(self.typeinstance)
+            buf.write(str(self.typeinstance))
         return buf.getvalue()
 
     def __str__(self):
@@ -215,8 +227,12 @@ def interpret_opcodes(iterable):
     for kind, data in iterable:
         if kind == TYPE_TIME:
             vl.time = nt.time = data
+        elif kind == TYPE_TIME_HR:
+            vl.time = nt.time = data / HR_TIME_DIV
         elif kind == TYPE_INTERVAL:
             vl.interval = data
+        elif kind == TYPE_INTERVAL_HR:
+            vl.interval = data / HR_TIME_DIV
         elif kind == TYPE_HOST:
             vl.host = nt.host = data
         elif kind == TYPE_PLUGIN:
@@ -248,7 +264,7 @@ class Reader(object):
     host = None
     port = DEFAULT_PORT
 
-    BUFFER_SIZE = 1024
+    BUFFER_SIZE = 16384
 
 
     def __init__(self, host=None, port=DEFAULT_PORT, multicast=False):
@@ -311,8 +327,6 @@ class Reader(object):
         """
         if iterable is None:
             iterable = self.decode()
-        if isinstance(iterable, basestring):
+        if isinstance(iterable, str):
             iterable = self.decode(iterable)
         return interpret_opcodes(iterable)
-
-
index 907ea9b..3e62ce0 100755 (executable)
@@ -46,7 +46,8 @@ use Regexp::Common ('number');
 our $ConfigFile = '/etc/exec-munin.conf';
 our $TypeMap = {};
 our $Scripts = [];
-our $Interval = 300;
+our $Interval = defined ($ENV{'COLLECTD_INTERVAL'}) ? (0 + $ENV{'COLLECTD_INTERVAL'}) : 300;
+our $Hostname = defined ($ENV{'COLLECTD_HOSTNAME'}) ? $ENV{'COLLECTD_HOSTNAME'} : '';
 
 main ();
 exit (0);
@@ -189,7 +190,7 @@ sub execute_script
   my $pinst;
   my $time = time ();
   my $script = shift;
-  my $host = hostname () || 'localhost';
+  my $host = $Hostname || hostname () || 'localhost';
   if (!open ($fh, '-|', $script))
   {
     print STDERR "Cannot execute $script: $!";
@@ -206,8 +207,11 @@ sub execute_script
       my $field = $1;
       my $value = $2;
       my $type = (defined ($TypeMap->{$field})) ? $TypeMap->{$field} : $field;
+      my $ident = "$host/munin-$pinst/$type";
 
-      print "$host/munin-$pinst/$type interval=$Interval $time:$value\n";
+      $ident =~ s/"/\\"/g;
+
+      print qq(PUTVAL "$ident" interval=$Interval $time:$value\n);
     }
   }
 
index 02bd0a3..c7f18c5 100755 (executable)
@@ -25,7 +25,8 @@ our $ConfigFile = '/etc/exec-nagios.conf';
 our $TypeMap = {};
 our $NRPEMap = {};
 our $Scripts = [];
-our $Interval = 300;
+our $Interval = defined ($ENV{'COLLECTD_INTERVAL'}) ? (0 + $ENV{'COLLECTD_INTERVAL'}) : 300;
+our $Hostname = defined ($ENV{'COLLECTD_HOSTNAME'}) ? $ENV{'COLLECTD_HOSTNAME'} : '';
 
 main ();
 exit (0);
@@ -351,6 +352,7 @@ sub handle_performance_data
   my $type = shift;
   my $time = shift;
   my $line = shift;
+  my $ident = "$host/$plugin-$pinst/$type-$tinst";
 
   my $tinst;
   my $value;
@@ -366,7 +368,9 @@ sub handle_performance_data
     return;
   }
 
-  print "PUTVAL $host/$plugin-$pinst/$type-$tinst interval=$Interval ${time}:$value\n";
+  $ident =~ s/"/\\"/g;
+
+  print qq(PUTVAL "$ident" interval=$Interval ${time}:$value\n);
 }
 
 sub execute_script
@@ -376,7 +380,7 @@ sub execute_script
   my $time = time ();
   my $script = shift;
   my @args = ();
-  my $host = hostname () || 'localhost';
+  my $host = $Hostname || hostname () || 'localhost';
 
   my $state = 0;
   my $serviceoutput;
index d469816..99b6986 100755 (executable)
 # smart   ALL = (root) NOPASSWD: SMARTCTL
 # -- >8 --
 
-HOST="huhu"
-INTERVAL=60
+HOSTNAME="${COLLECTD_HOSTNAME:-`hostname -f`}"
+INTERVAL="${COLLECTD_INTERVAL:-60}"
 
-while true
+while sleep "$INTERVAL"
 do
        TEMP=$((sudo smartctl -d 3ware,0 -A /dev/twe0 | grep Temperature_Celsius | awk '{ print $10; }') 2>/dev/null);
        if [ $? -ne 0 ]
        then
                TEMP="U"
        fi
-       echo "$HOST/exec-smart/temperature-3ware_0 interval=$INTERVAL N:$TEMP"
+       echo "PUTVAL $HOSTNAME/exec-smart/temperature-3ware_0 interval=$INTERVAL N:$TEMP"
 
        TEMP=$((sudo smartctl -d 3ware,1 -A /dev/twe0 | grep Temperature_Celsius | awk '{ print $10; }') 2>/dev/null);
        if [ $? -ne 0 ]
        then
                TEMP="U"
        fi
-       echo "$HOST/exec-smart/temperature-3ware_1 interval=$INTERVAL N:$TEMP"
+       echo "PUTVAL $HOSTNAME/exec-smart/temperature-3ware_1 interval=$INTERVAL N:$TEMP"
 
        TEMP=$((sudo smartctl -d ata -A /dev/sda | grep Temperature_Celsius | awk '{ print $10; }') 2>/dev/null);
        if [ $? -ne 0 ]
        then
                TEMP="U"
        fi
-       echo "$HOST/exec-smart/temperature-sata_0 interval=$INTERVAL N:$TEMP"
-
-       sleep $INTERVAL
+       echo "PUTVAL $HOSTNAME/exec-smart/temperature-sata_0 interval=$INTERVAL N:$TEMP"
 done
diff --git a/contrib/migrate-4-5.px b/contrib/migrate-4-5.px
new file mode 100755 (executable)
index 0000000..c2a9555
--- /dev/null
@@ -0,0 +1,255 @@
+#!/usr/bin/perl
+
+# collectd - contrib/migrate-4-5.px
+# Copyright (C) 2010  Florian Forster
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+# Authors:
+#   Florian Forster <octo at collectd.org>
+
+use strict;
+use warnings;
+
+use Getopt::Long ('GetOptions');
+use Data::Dumper ();
+use File::Basename ('dirname');
+
+our $InDir = '/var/lib/collectd';
+our $RRDtool = 'rrdtool';
+our $RRDFilter = 'rrd_filter.px';
+
+our %TypesCounterToDerive = # {{{
+(
+  apache_bytes => ["count"],
+  apache_requests => ["count"],
+  arc_counts => ["demand_data", "demand_metadata", "prefetch_data", "prefetch_metadata"],
+  arc_l2_bytes => ["read", "write"],
+  ath_stat => ["value"],
+  compression => ["uncompressed", "compressed"],
+  connections => ["value"],
+  cpu => ["value"],
+  current => ["value"],
+  disk_merged => ["read", "write"],
+  disk_octets => ["read", "write"],
+  disk_ops => ["read", "write"],
+  disk_ops_complex => ["value"],
+  disk_time => ["read", "write"],
+  dns_answer => ["value"],
+  dns_notify => ["value"],
+  dns_octets => ["queries", "responses"],
+  dns_opcode => ["value"],
+  dns_qtype => ["value"],
+  dns_query => ["value"],
+  dns_question => ["value"],
+  dns_rcode => ["value"],
+  dns_reject => ["value"],
+  dns_request => ["value"],
+  dns_resolver => ["value"],
+  dns_response => ["value"],
+  dns_transfer => ["value"],
+  dns_update => ["value"],
+  dns_zops => ["value"],
+  fscache_stat => ["value"],
+  fork_rate => ["value"],
+  http_request_methods => ["count"],
+  http_requests => ["count"],
+  http_response_codes => ["count"],
+  if_collisions => ["value"],
+  if_dropped => ["rx", "tx"],
+  if_errors => ["rx", "tx"],
+  if_multicast => ["value"],
+  if_octets => ["rx", "tx"],
+  if_packets => ["rx", "tx"],
+  if_rx_errors => ["value"],
+  if_tx_errors => ["value"],
+  io_octets => ["rx", "tx"],
+  io_packets => ["rx", "tx"],
+  ipt_bytes => ["value"],
+  ipt_packets => ["value"],
+  irq => ["value"],
+  memcached_command => ["value"],
+  memcached_octets => ["rx", "tx"],
+  memcached_ops => ["value"],
+  mysql_commands => ["value"],
+  mysql_handler => ["value"],
+  mysql_locks => ["value"],
+  mysql_log_position => ["value"],
+  mysql_octets => ["rx", "tx"],
+  nfs_procedure => ["value"],
+  nginx_requests => ["value"],
+  node_octets => ["rx", "tx"],
+  node_stat => ["value"],
+  operations => ["value"],
+  pg_blks => ["value"],
+  pg_n_tup_c => ["value"],
+  pg_scan => ["value"],
+  pg_xact => ["value"],
+  protocol_counter => ["value"],
+  ps_cputime => ["user", "syst"],
+  ps_pagefaults => ["minflt", "majflt"],
+  ps_code => ["value"],
+  ps_data => ["value"],
+  serial_octets => ["rx", "tx"],
+  swap_io => ["value"],
+  virt_cpu_total => ["ns"],
+  virt_vcpu => ["ns"],
+  vmpage_action => ["value"],
+  vmpage_faults => ["minflt", "majflt"],
+  vmpage_io => ["in", "out"],
+); # }}} %TypesCounterToDerive
+
+our %TypesRenameDataSource = # {{{
+(
+  absolute => "count",
+  apache_bytes => "count",
+  apache_connections => "count",
+  apache_idle_workers => "count",
+  apache_requests => "count",
+  apache_scoreboard => "count",
+  conntrack => "entropy",
+  contextswitch => "contextswitches",
+  delay => "seconds",
+  entropy => "entropy",
+  file_size => "bytes",
+  frequency => "frequency",
+  frequency_offset => "ppm",
+  http_request_methods => "count",
+  http_requests => "count",
+  http_response_codes => "count",
+  percent => "percent",
+  ping => "ping",
+  records => "count",
+  time_dispersion => "seconds",
+  timeleft => "timeleft",
+  time_offset => "seconds",
+  users => "users",
+  virt_cpu_total => "ns",
+  virt_vcpu => "ns",
+); # }}} %TypesRenameDataSource
+
+sub handle_file # {{{
+{
+  my @path = @_;
+  my $path = join ('/', @path);
+
+  if (!($path =~ m/\.rrd$/))
+  {
+    return;
+  }
+
+  my $tmp = pop (@path);
+  $tmp =~ s/\.rrd$//;
+  my ($type, $type_inst) = split (m/-/, $tmp, 2);
+  $type_inst ||= '';
+
+  $tmp = pop (@path);
+  my ($plugin, $plugin_inst) = split (m/-/, $tmp, 2);
+  $plugin_inst ||= '';
+
+  if ($TypesRenameDataSource{$type})
+  {
+    my $old_ds = $TypesRenameDataSource{$type};
+    print "$RRDtool tune \"$path\" --data-source-rename ${old_ds}:value\n";
+  }
+
+  if ($TypesCounterToDerive{$type})
+  {
+    my $ds_names = $TypesCounterToDerive{$type};
+    
+    for (@$ds_names)
+    {
+      my $name = $_;
+      print "$RRDtool tune \"$path\" --data-source-type ${name}:DERIVE --minimum ${name}:0 --maximum ${name}:U\n";
+    }
+  }
+
+  if ((($plugin eq 'df') || ($plugin eq 'interface'))
+    && (!$plugin_inst) && ($type_inst))
+  {
+    my $dir = join ('/', @path);
+    print "mkdir -p \"$dir/$plugin-$type_inst\"\n";
+    if (($plugin eq 'df') and ($type eq 'df'))
+    {
+      print "$RRDFilter --infile=\"$path\" --outfile=\"$dir/$plugin-$type_inst/df_complex-free.rrd\" --map free:value\n";
+      print "$RRDFilter --infile=\"$path\" --outfile=\"$dir/$plugin-$type_inst/df_complex-used.rrd\" --map used:value\n";
+    }
+    else
+    {
+      print "mv \"$path\" \"$dir/$plugin-$type_inst/$type.rrd\"\n";
+    }
+  }
+} # }}} sub handle_file
+
+sub scan_dir # {{{
+{
+  my @dir_parts = @_;
+  my $dir_str = join ('/', @dir_parts);
+  my $dh;
+
+  opendir ($dh, $dir_str) || die;
+  while (my $entry = readdir ($dh))
+  {
+    my $entry_path = "$dir_str/$entry";
+
+    if ($entry =~ m/^\./)
+    {
+      next;
+    }
+
+    if (-d $entry_path)
+    {
+      scan_dir (@dir_parts, $entry);
+    }
+    elsif (-f $entry_path)
+    {
+      handle_file (@dir_parts, $entry);
+    }
+  }
+  closedir ($dh);
+} # }}} sub scan_dir
+
+sub exit_usage # {{{
+{
+  print STDERR <<EOF;
+migrate-4-5.px [OPTIONS]
+
+Valid options are:
+
+  --indir <dir>         Source directory
+                        Default: $InDir
+  --rrdtool <path>      Path to the RRDtool binary
+                        Default: $RRDtool
+  --rrdfilter <path>    Path to the rrd_filter.px script
+                        Default: $RRDFilter
+
+EOF
+  exit (1);
+} # }}} sub exit_usage
+
+GetOptions ("indir|i=s" => \$InDir,
+        "rrdtool=s" => \$RRDtool,
+        "rrdfilter=s" => \$RRDFilter,
+        "help|h" => \&exit_usage) or exit_usage ();
+
+print "#!/bin/bash\n\n";
+
+scan_dir ($InDir);
+
+# vim: set sw=2 sts=2 et fdm=marker :
index 40b8293..45fd6f1 100644 (file)
@@ -21,7 +21,7 @@ AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
 AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
 
 sbin_PROGRAMS = collectd collectdmon
-bin_PROGRAMS = collectd-nagios
+bin_PROGRAMS = collectd-nagios collectdctl
 
 collectd_SOURCES = collectd.c collectd.h \
                   common.c common.h \
@@ -40,7 +40,7 @@ collectd_SOURCES = collectd.c collectd.h \
                   utils_match.c utils_match.h \
                   utils_subst.c utils_subst.h \
                   utils_tail.c utils_tail.h \
-                  utils_threshold.c utils_threshold.h \
+                  utils_time.c utils_time.h \
                   types_list.c types_list.h
 
 collectd_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL)
@@ -104,11 +104,36 @@ endif
 collectd_nagios_LDADD += libcollectdclient/libcollectdclient.la
 collectd_nagios_DEPENDENCIES = libcollectdclient/libcollectdclient.la
 
+
+collectdctl_SOURCES = collectdctl.c
+collectdctl_LDADD =
+if BUILD_WITH_LIBSOCKET
+collectdctl_LDADD += -lsocket
+endif
+if BUILD_AIX
+collectdctl_LDADD += -lm
+endif
+collectdctl_LDADD += libcollectdclient/libcollectdclient.la
+collectdctl_DEPENDENCIES = libcollectdclient/libcollectdclient.la
+
+
 pkglib_LTLIBRARIES = 
 
 BUILT_SOURCES = 
 CLEANFILES = 
 
+if BUILD_PLUGIN_AMQP
+pkglib_LTLIBRARIES += amqp.la
+amqp_la_SOURCES = amqp.c \
+                 utils_cmd_putval.c utils_cmd_putval.h \
+                 utils_format_json.c utils_format_json.h
+amqp_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
+amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
+amqp_la_LIBADD = $(BUILD_WITH_LIBRABBITMQ_LIBS)
+collectd_LDADD += "-dlopen" amqp.la
+collectd_DEPENDENCIES += amqp.la
+endif
+
 if BUILD_PLUGIN_APACHE
 pkglib_LTLIBRARIES += apache.la
 apache_la_SOURCES = apache.c
@@ -500,6 +525,15 @@ collectd_LDADD += "-dlopen" logfile.la
 collectd_DEPENDENCIES += logfile.la
 endif
 
+if BUILD_PLUGIN_LPAR
+pkglib_LTLIBRARIES += lpar.la
+lpar_la_SOURCES = lpar.c
+lpar_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" lpar.la
+collectd_DEPENDENCIES += lpar.la
+lpar_la_LIBADD = -lperfstat
+endif
+
 if BUILD_PLUGIN_MADWIFI
 pkglib_LTLIBRARIES += madwifi.la
 madwifi_la_SOURCES = madwifi.c madwifi.h
@@ -886,6 +920,16 @@ collectd_LDADD += "-dlopen" protocols.la
 collectd_DEPENDENCIES += protocols.la
 endif
 
+if BUILD_PLUGIN_REDIS
+pkglib_LTLIBRARIES += redis.la
+redis_la_SOURCES = redis.c
+redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
+redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+redis_la_LIBADD = -lcredis
+collectd_LDADD += "-dlopen" redis.la
+collectd_DEPENDENCIES += redis.la
+endif
+
 if BUILD_PLUGIN_ROUTEROS
 pkglib_LTLIBRARIES += routeros.la
 routeros_la_SOURCES = routeros.c
@@ -1043,6 +1087,14 @@ collectd_LDADD += "-dlopen" target_set.la
 collectd_DEPENDENCIES += target_set.la
 endif
 
+if BUILD_PLUGIN_TARGET_V5UPGRADE
+pkglib_LTLIBRARIES += target_v5upgrade.la
+target_v5upgrade_la_SOURCES = target_v5upgrade.c
+target_v5upgrade_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" target_v5upgrade.la
+collectd_DEPENDENCIES += target_v5upgrade.la
+endif
+
 if BUILD_PLUGIN_TCPCONNS
 pkglib_LTLIBRARIES += tcpconns.la
 tcpconns_la_SOURCES = tcpconns.c
@@ -1079,6 +1131,14 @@ collectd_LDADD += "-dlopen" thermal.la
 collectd_DEPENDENCIES += thermal.la
 endif
 
+if BUILD_PLUGIN_THRESHOLD
+pkglib_LTLIBRARIES += threshold.la
+threshold_la_SOURCES = threshold.c
+threshold_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" threshold.la
+collectd_DEPENDENCIES += threshold.la
+endif
+
 if BUILD_PLUGIN_TOKYOTYRANT
 pkglib_LTLIBRARIES += tokyotyrant.la
 tokyotyrant_la_SOURCES = tokyotyrant.c
@@ -1097,7 +1157,6 @@ pkglib_LTLIBRARIES += unixsock.la
 unixsock_la_SOURCES = unixsock.c \
                      utils_cmd_flush.h utils_cmd_flush.c \
                      utils_cmd_getval.h utils_cmd_getval.c \
-                     utils_cmd_getthreshold.h utils_cmd_getthreshold.c \
                      utils_cmd_listval.h utils_cmd_listval.c \
                      utils_cmd_putval.h utils_cmd_putval.c \
                      utils_cmd_putnotif.h utils_cmd_putnotif.c
@@ -1144,6 +1203,16 @@ collectd_LDADD += "-dlopen" uuid.la
 collectd_DEPENDENCIES += uuid.la
 endif
 
+if BUILD_PLUGIN_VARNISH
+pkglib_LTLIBRARIES += varnish.la
+varnish_la_SOURCES = varnish.c
+varnish_la_LDFLAGS = -module -avoid-version
+varnish_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBVARNISH_CFLAGS)
+varnish_la_LIBADD = $(BUILD_WITH_LIBVARNISH_LIBS)
+collectd_LDADD += "-dlopen" varnish.la
+collectd_DEPENDENCIES += varnish.la
+endif
+
 if BUILD_PLUGIN_VMEM
 pkglib_LTLIBRARIES += vmem.la
 vmem_la_SOURCES = vmem.c
@@ -1183,6 +1252,16 @@ endif
 collectd_DEPENDENCIES += write_http.la
 endif
 
+if BUILD_PLUGIN_WRITE_REDIS
+pkglib_LTLIBRARIES += write_redis.la
+write_redis_la_SOURCES = write_redis.c
+write_redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
+write_redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+write_redis_la_LIBADD = -lcredis
+collectd_LDADD += "-dlopen" write_redis.la
+collectd_DEPENDENCIES += write_redis.la
+endif
+
 if BUILD_PLUGIN_XMMS
 pkglib_LTLIBRARIES += xmms.la
 xmms_la_SOURCES = xmms.c
@@ -1209,12 +1288,14 @@ dist_man_MANS = collectd.1 \
                collectd.conf.5 \
                collectd-email.5 \
                collectd-exec.5 \
+               collectdctl.1 \
                collectd-java.5 \
                collectdmon.1 \
                collectd-nagios.1 \
                collectd-perl.5 \
                collectd-python.5 \
                collectd-snmp.5 \
+               collectd-threshold.5 \
                collectd-unixsock.5 \
                types.db.5
 
@@ -1225,6 +1306,7 @@ EXTRA_DIST = types.db pinba.proto
 EXTRA_DIST +=   collectd.conf.pod \
                collectd-email.pod \
                collectd-exec.pod \
+               collectdctl.pod \
                collectd-java.pod \
                collectdmon.pod \
                collectd-nagios.pod \
@@ -1232,6 +1314,7 @@ EXTRA_DIST +=   collectd.conf.pod \
                collectd-python.pod \
                collectd.pod \
                collectd-snmp.pod \
+               collectd-threshold.pod \
                collectd-unixsock.pod \
                postgresql_default.conf \
                types.db.pod
@@ -1253,7 +1336,7 @@ EXTRA_DIST +=   collectd.conf.pod \
        fi
 
 pinba.pb-c.c pinba.pb-c.h: pinba.proto
-       protoc-c --c_out $(builddir) pinba.proto
+       protoc-c --c_out . pinba.proto
 
 install-exec-hook:
        $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
diff --git a/src/amqp.c b/src/amqp.c
new file mode 100644 (file)
index 0000000..89284c8
--- /dev/null
@@ -0,0 +1,994 @@
+/**
+ * collectd - src/amqp.c
+ * Copyright (C) 2009       Sebastien Pahl
+ * Copyright (C) 2010-2012  Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Sebastien Pahl <sebastien.pahl at dotcloud.com>
+ *   Florian Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_cmd_putval.h"
+#include "utils_format_json.h"
+
+#include <pthread.h>
+
+#include <amqp.h>
+#include <amqp_framing.h>
+
+/* Defines for the delivery mode. I have no idea why they're not defined by the
+ * library.. */
+#define CAMQP_DM_VOLATILE   1
+#define CAMQP_DM_PERSISTENT 2
+
+#define CAMQP_FORMAT_COMMAND 1
+#define CAMQP_FORMAT_JSON    2
+
+#define CAMQP_CHANNEL 1
+
+/*
+ * Data types
+ */
+struct camqp_config_s
+{
+    _Bool   publish;
+    char   *name;
+
+    char   *host;
+    int     port;
+    char   *vhost;
+    char   *user;
+    char   *password;
+
+    char   *exchange;
+    char   *routing_key;
+
+    /* publish only */
+    uint8_t delivery_mode;
+    _Bool   store_rates;
+    int     format;
+
+    /* subscribe only */
+    char   *exchange_type;
+    char   *queue;
+
+    amqp_connection_state_t connection;
+    pthread_mutex_t lock;
+};
+typedef struct camqp_config_s camqp_config_t;
+
+/*
+ * Global variables
+ */
+static const char *def_host       = "localhost";
+static const char *def_vhost      = "/";
+static const char *def_user       = "guest";
+static const char *def_password   = "guest";
+static const char *def_exchange   = "amq.fanout";
+
+static pthread_t *subscriber_threads     = NULL;
+static size_t     subscriber_threads_num = 0;
+static _Bool      subscriber_threads_running = 1;
+
+#define CONF(c,f) (((c)->f != NULL) ? (c)->f : def_##f)
+
+/*
+ * Functions
+ */
+static void camqp_close_connection (camqp_config_t *conf) /* {{{ */
+{
+    int sockfd;
+
+    if ((conf == NULL) || (conf->connection == NULL))
+        return;
+
+    sockfd = amqp_get_sockfd (conf->connection);
+    amqp_channel_close (conf->connection, CAMQP_CHANNEL, AMQP_REPLY_SUCCESS);
+    amqp_connection_close (conf->connection, AMQP_REPLY_SUCCESS);
+    amqp_destroy_connection (conf->connection);
+    close (sockfd);
+    conf->connection = NULL;
+} /* }}} void camqp_close_connection */
+
+static void camqp_config_free (void *ptr) /* {{{ */
+{
+    camqp_config_t *conf = ptr;
+
+    if (conf == NULL)
+        return;
+
+    camqp_close_connection (conf);
+
+    sfree (conf->name);
+    sfree (conf->host);
+    sfree (conf->vhost);
+    sfree (conf->user);
+    sfree (conf->password);
+    sfree (conf->exchange);
+    sfree (conf->exchange_type);
+    sfree (conf->queue);
+    sfree (conf->routing_key);
+
+    sfree (conf);
+} /* }}} void camqp_config_free */
+
+static char *camqp_bytes_cstring (amqp_bytes_t *in) /* {{{ */
+{
+    char *ret;
+
+    if ((in == NULL) || (in->bytes == NULL))
+        return (NULL);
+
+    ret = malloc (in->len + 1);
+    if (ret == NULL)
+        return (NULL);
+
+    memcpy (ret, in->bytes, in->len);
+    ret[in->len] = 0;
+
+    return (ret);
+} /* }}} char *camqp_bytes_cstring */
+
+static _Bool camqp_is_error (camqp_config_t *conf) /* {{{ */
+{
+    amqp_rpc_reply_t r;
+
+    r = amqp_get_rpc_reply (conf->connection);
+    if (r.reply_type == AMQP_RESPONSE_NORMAL)
+        return (0);
+
+    return (1);
+} /* }}} _Bool camqp_is_error */
+
+static char *camqp_strerror (camqp_config_t *conf, /* {{{ */
+        char *buffer, size_t buffer_size)
+{
+    amqp_rpc_reply_t r;
+
+    r = amqp_get_rpc_reply (conf->connection);
+    switch (r.reply_type)
+    {
+        case AMQP_RESPONSE_NORMAL:
+            sstrncpy (buffer, "Success", sizeof (buffer));
+            break;
+
+        case AMQP_RESPONSE_NONE:
+            sstrncpy (buffer, "Missing RPC reply type", sizeof (buffer));
+            break;
+
+        case AMQP_RESPONSE_LIBRARY_EXCEPTION:
+#if HAVE_AMQP_RPC_REPLY_T_LIBRARY_ERRNO
+            if (r.library_errno)
+                return (sstrerror (r.library_errno, buffer, buffer_size));
+#else
+            if (r.library_error)
+                return (sstrerror (r.library_error, buffer, buffer_size));
+#endif
+            else
+                sstrncpy (buffer, "End of stream", sizeof (buffer));
+            break;
+
+        case AMQP_RESPONSE_SERVER_EXCEPTION:
+            if (r.reply.id == AMQP_CONNECTION_CLOSE_METHOD)
+            {
+                amqp_connection_close_t *m = r.reply.decoded;
+                char *tmp = camqp_bytes_cstring (&m->reply_text);
+                ssnprintf (buffer, buffer_size, "Server connection error %d: %s",
+                        m->reply_code, tmp);
+                sfree (tmp);
+            }
+            else if (r.reply.id == AMQP_CHANNEL_CLOSE_METHOD)
+            {
+                amqp_channel_close_t *m = r.reply.decoded;
+                char *tmp = camqp_bytes_cstring (&m->reply_text);
+                ssnprintf (buffer, buffer_size, "Server channel error %d: %s",
+                        m->reply_code, tmp);
+                sfree (tmp);
+            }
+            else
+            {
+                ssnprintf (buffer, buffer_size, "Server error method %#"PRIx32,
+                        r.reply.id);
+            }
+            break;
+
+        default:
+            ssnprintf (buffer, buffer_size, "Unknown reply type %i",
+                    (int) r.reply_type);
+    }
+
+    return (buffer);
+} /* }}} char *camqp_strerror */
+
+#if HAVE_AMQP_RPC_REPLY_T_LIBRARY_ERRNO
+static int camqp_create_exchange (camqp_config_t *conf) /* {{{ */
+{
+    amqp_exchange_declare_ok_t *ed_ret;
+
+    if (conf->exchange_type == NULL)
+        return (0);
+
+    ed_ret = amqp_exchange_declare (conf->connection,
+            /* channel     = */ CAMQP_CHANNEL,
+            /* exchange    = */ amqp_cstring_bytes (conf->exchange),
+            /* type        = */ amqp_cstring_bytes (conf->exchange_type),
+            /* passive     = */ 0,
+            /* durable     = */ 0,
+            /* auto_delete = */ 1,
+            /* arguments   = */ AMQP_EMPTY_TABLE);
+    if ((ed_ret == NULL) && camqp_is_error (conf))
+    {
+        char errbuf[1024];
+        ERROR ("amqp plugin: amqp_exchange_declare failed: %s",
+                camqp_strerror (conf, errbuf, sizeof (errbuf)));
+        camqp_close_connection (conf);
+        return (-1);
+    }
+
+    INFO ("amqp plugin: Successfully created exchange \"%s\" "
+            "with type \"%s\".",
+            conf->exchange, conf->exchange_type);
+
+    return (0);
+} /* }}} int camqp_create_exchange */
+#else
+static int camqp_create_exchange (camqp_config_t *conf) /* {{{ */
+{
+    amqp_exchange_declare_ok_t *ed_ret;
+    amqp_table_t argument_table;
+    struct amqp_table_entry_t_ argument_table_entries[1];
+
+    if (conf->exchange_type == NULL)
+        return (0);
+
+    /* Valid arguments: "auto_delete", "internal" */
+    argument_table.num_entries = STATIC_ARRAY_SIZE (argument_table_entries);
+    argument_table.entries = argument_table_entries;
+    argument_table_entries[0].key = amqp_cstring_bytes ("auto_delete");
+    argument_table_entries[0].value.kind = AMQP_FIELD_KIND_BOOLEAN;
+    argument_table_entries[0].value.value.boolean = 1;
+
+    ed_ret = amqp_exchange_declare (conf->connection,
+            /* channel     = */ CAMQP_CHANNEL,
+            /* exchange    = */ amqp_cstring_bytes (conf->exchange),
+            /* type        = */ amqp_cstring_bytes (conf->exchange_type),
+            /* passive     = */ 0,
+            /* durable     = */ 0,
+            /* arguments   = */ argument_table);
+    if ((ed_ret == NULL) && camqp_is_error (conf))
+    {
+        char errbuf[1024];
+        ERROR ("amqp plugin: amqp_exchange_declare failed: %s",
+                camqp_strerror (conf, errbuf, sizeof (errbuf)));
+        camqp_close_connection (conf);
+        return (-1);
+    }
+
+    INFO ("amqp plugin: Successfully created exchange \"%s\" "
+            "with type \"%s\".",
+            conf->exchange, conf->exchange_type);
+
+    return (0);
+} /* }}} int camqp_create_exchange */
+#endif
+
+static int camqp_setup_queue (camqp_config_t *conf) /* {{{ */
+{
+    amqp_queue_declare_ok_t *qd_ret;
+    amqp_basic_consume_ok_t *cm_ret;
+
+    qd_ret = amqp_queue_declare (conf->connection,
+            /* channel     = */ CAMQP_CHANNEL,
+            /* queue       = */ (conf->queue != NULL)
+            ? amqp_cstring_bytes (conf->queue)
+            : AMQP_EMPTY_BYTES,
+            /* passive     = */ 0,
+            /* durable     = */ 0,
+            /* exclusive   = */ 0,
+            /* auto_delete = */ 1,
+            /* arguments   = */ AMQP_EMPTY_TABLE);
+    if (qd_ret == NULL)
+    {
+        ERROR ("amqp plugin: amqp_queue_declare failed.");
+        camqp_close_connection (conf);
+        return (-1);
+    }
+
+    if (conf->queue == NULL)
+    {
+        conf->queue = camqp_bytes_cstring (&qd_ret->queue);
+        if (conf->queue == NULL)
+        {
+            ERROR ("amqp plugin: camqp_bytes_cstring failed.");
+            camqp_close_connection (conf);
+            return (-1);
+        }
+
+        INFO ("amqp plugin: Created queue \"%s\".", conf->queue);
+    }
+    DEBUG ("amqp plugin: Successfully created queue \"%s\".", conf->queue);
+
+    /* bind to an exchange */
+    if (conf->exchange != NULL)
+    {
+        amqp_queue_bind_ok_t *qb_ret;
+
+        assert (conf->queue != NULL);
+        qb_ret = amqp_queue_bind (conf->connection,
+                /* channel     = */ CAMQP_CHANNEL,
+                /* queue       = */ amqp_cstring_bytes (conf->queue),
+                /* exchange    = */ amqp_cstring_bytes (conf->exchange),
+                /* routing_key = */ (conf->routing_key != NULL)
+                ? amqp_cstring_bytes (conf->routing_key)
+                : AMQP_EMPTY_BYTES,
+                /* arguments   = */ AMQP_EMPTY_TABLE);
+        if ((qb_ret == NULL) && camqp_is_error (conf))
+        {
+            char errbuf[1024];
+            ERROR ("amqp plugin: amqp_queue_bind failed: %s",
+                    camqp_strerror (conf, errbuf, sizeof (errbuf)));
+            camqp_close_connection (conf);
+            return (-1);
+        }
+
+        DEBUG ("amqp plugin: Successfully bound queue \"%s\" to exchange \"%s\".",
+                conf->queue, conf->exchange);
+    } /* if (conf->exchange != NULL) */
+
+    cm_ret = amqp_basic_consume (conf->connection,
+            /* channel      = */ CAMQP_CHANNEL,
+            /* queue        = */ amqp_cstring_bytes (conf->queue),
+            /* consumer_tag = */ AMQP_EMPTY_BYTES,
+            /* no_local     = */ 0,
+            /* no_ack       = */ 1,
+            /* exclusive    = */ 0,
+            /* arguments    = */ AMQP_EMPTY_TABLE
+        );
+    if ((cm_ret == NULL) && camqp_is_error (conf))
+    {
+        char errbuf[1024];
+        ERROR ("amqp plugin: amqp_basic_consume failed: %s",
+                    camqp_strerror (conf, errbuf, sizeof (errbuf)));
+        camqp_close_connection (conf);
+        return (-1);
+    }
+
+    return (0);
+} /* }}} int camqp_setup_queue */
+
+static int camqp_connect (camqp_config_t *conf) /* {{{ */
+{
+    amqp_rpc_reply_t reply;
+    int sockfd;
+    int status;
+
+    if (conf->connection != NULL)
+        return (0);
+
+    conf->connection = amqp_new_connection ();
+    if (conf->connection == NULL)
+    {
+        ERROR ("amqp plugin: amqp_new_connection failed.");
+        return (ENOMEM);
+    }
+
+    sockfd = amqp_open_socket (CONF(conf, host), conf->port);
+    if (sockfd < 0)
+    {
+        char errbuf[1024];
+        status = (-1) * sockfd;
+        ERROR ("amqp plugin: amqp_open_socket failed: %s",
+                sstrerror (status, errbuf, sizeof (errbuf)));
+        amqp_destroy_connection (conf->connection);
+        conf->connection = NULL;
+        return (status);
+    }
+    amqp_set_sockfd (conf->connection, sockfd);
+
+    reply = amqp_login (conf->connection, CONF(conf, vhost),
+            /* channel max = */      0,
+            /* frame max   = */ 131072,
+            /* heartbeat   = */      0,
+            /* authentication = */ AMQP_SASL_METHOD_PLAIN,
+            CONF(conf, user), CONF(conf, password));
+    if (reply.reply_type != AMQP_RESPONSE_NORMAL)
+    {
+        ERROR ("amqp plugin: amqp_login (vhost = %s, user = %s) failed.",
+                CONF(conf, vhost), CONF(conf, user));
+        amqp_destroy_connection (conf->connection);
+        close (sockfd);
+        conf->connection = NULL;
+        return (1);
+    }
+
+    amqp_channel_open (conf->connection, /* channel = */ 1);
+    /* FIXME: Is checking "reply.reply_type" really correct here? How does
+     * it get set? --octo */
+    if (reply.reply_type != AMQP_RESPONSE_NORMAL)
+    {
+        ERROR ("amqp plugin: amqp_channel_open failed.");
+        amqp_connection_close (conf->connection, AMQP_REPLY_SUCCESS);
+        amqp_destroy_connection (conf->connection);
+        close(sockfd);
+        conf->connection = NULL;
+        return (1);
+    }
+
+    INFO ("amqp plugin: Successfully opened connection to vhost \"%s\" "
+            "on %s:%i.", CONF(conf, vhost), CONF(conf, host), conf->port);
+
+    status = camqp_create_exchange (conf);
+    if (status != 0)
+        return (status);
+
+    if (!conf->publish)
+        return (camqp_setup_queue (conf));
+    return (0);
+} /* }}} int camqp_connect */
+
+static int camqp_shutdown (void) /* {{{ */
+{
+    size_t i;
+
+    DEBUG ("amqp plugin: Shutting down %zu subscriber threads.",
+            subscriber_threads_num);
+
+    subscriber_threads_running = 0;
+    for (i = 0; i < subscriber_threads_num; i++)
+    {
+        /* FIXME: Sending a signal is not very elegant here. Maybe find out how
+         * to use a timeout in the thread and check for the variable in regular
+         * intervals. */
+        pthread_kill (subscriber_threads[i], SIGTERM);
+        pthread_join (subscriber_threads[i], /* retval = */ NULL);
+    }
+
+    subscriber_threads_num = 0;
+    sfree (subscriber_threads);
+
+    DEBUG ("amqp plugin: All subscriber threads exited.");
+
+    return (0);
+} /* }}} int camqp_shutdown */
+
+/*
+ * Subscribing code
+ */
+static int camqp_read_body (camqp_config_t *conf, /* {{{ */
+        size_t body_size, const char *content_type)
+{
+    char body[body_size + 1];
+    char *body_ptr;
+    size_t received;
+    amqp_frame_t frame;
+    int status;
+
+    memset (body, 0, sizeof (body));
+    body_ptr = &body[0];
+    received = 0;
+
+    while (received < body_size)
+    {
+        status = amqp_simple_wait_frame (conf->connection, &frame);
+        if (status < 0)
+        {
+            char errbuf[1024];
+            status = (-1) * status;
+            ERROR ("amqp plugin: amqp_simple_wait_frame failed: %s",
+                    sstrerror (status, errbuf, sizeof (errbuf)));
+            camqp_close_connection (conf);
+            return (status);
+        }
+
+        if (frame.frame_type != AMQP_FRAME_BODY)
+        {
+            NOTICE ("amqp plugin: Unexpected frame type: %#"PRIx8,
+                    frame.frame_type);
+            return (-1);
+        }
+
+        if ((body_size - received) < frame.payload.body_fragment.len)
+        {
+            WARNING ("amqp plugin: Body is larger than indicated by header.");
+            return (-1);
+        }
+
+        memcpy (body_ptr, frame.payload.body_fragment.bytes,
+                frame.payload.body_fragment.len);
+        body_ptr += frame.payload.body_fragment.len;
+        received += frame.payload.body_fragment.len;
+    } /* while (received < body_size) */
+
+    if (strcasecmp ("text/collectd", content_type) == 0)
+    {
+        status = handle_putval (stderr, body);
+        if (status != 0)
+            ERROR ("amqp plugin: handle_putval failed with status %i.",
+                    status);
+        return (status);
+    }
+    else if (strcasecmp ("application/json", content_type) == 0)
+    {
+        ERROR ("amqp plugin: camqp_read_body: Parsing JSON data has not "
+                "been implemented yet. FIXME!");
+        return (0);
+    }
+    else
+    {
+        ERROR ("amqp plugin: camqp_read_body: Unknown content type \"%s\".",
+                content_type);
+        return (EINVAL);
+    }
+
+    /* not reached */
+    return (0);
+} /* }}} int camqp_read_body */
+
+static int camqp_read_header (camqp_config_t *conf) /* {{{ */
+{
+    int status;
+    amqp_frame_t frame;
+    amqp_basic_properties_t *properties;
+    char *content_type;
+
+    status = amqp_simple_wait_frame (conf->connection, &frame);
+    if (status < 0)
+    {
+        char errbuf[1024];
+        status = (-1) * status;
+        ERROR ("amqp plugin: amqp_simple_wait_frame failed: %s",
+                    sstrerror (status, errbuf, sizeof (errbuf)));
+        camqp_close_connection (conf);
+        return (status);
+    }
+
+    if (frame.frame_type != AMQP_FRAME_HEADER)
+    {
+        NOTICE ("amqp plugin: Unexpected frame type: %#"PRIx8,
+                frame.frame_type);
+        return (-1);
+    }
+
+    properties = frame.payload.properties.decoded;
+    content_type = camqp_bytes_cstring (&properties->content_type);
+    if (content_type == NULL)
+    {
+        ERROR ("amqp plugin: Unable to determine content type.");
+        return (-1);
+    }
+
+    status = camqp_read_body (conf,
+            (size_t) frame.payload.properties.body_size,
+            content_type);
+
+    sfree (content_type);
+    return (status);
+} /* }}} int camqp_read_header */
+
+static void *camqp_subscribe_thread (void *user_data) /* {{{ */
+{
+    camqp_config_t *conf = user_data;
+    int status;
+
+    while (subscriber_threads_running)
+    {
+        amqp_frame_t frame;
+
+        status = camqp_connect (conf);
+        if (status != 0)
+        {
+            struct timespec ts_interval;
+            ERROR ("amqp plugin: camqp_connect failed. "
+                    "Will sleep for %.3f seconds.",
+                    CDTIME_T_TO_DOUBLE (interval_g));
+            CDTIME_T_TO_TIMESPEC (interval_g, &ts_interval);
+            nanosleep (&ts_interval, /* remaining = */ NULL);
+            continue;
+        }
+
+        status = amqp_simple_wait_frame (conf->connection, &frame);
+        if (status < 0)
+        {
+            struct timespec ts_interval;
+            ERROR ("amqp plugin: amqp_simple_wait_frame failed. "
+                    "Will sleep for %.3f seconds.",
+                    CDTIME_T_TO_DOUBLE (interval_g));
+            camqp_close_connection (conf);
+            CDTIME_T_TO_TIMESPEC (interval_g, &ts_interval);
+            nanosleep (&ts_interval, /* remaining = */ NULL);
+            continue;
+        }
+
+        if (frame.frame_type != AMQP_FRAME_METHOD)
+        {
+            DEBUG ("amqp plugin: Unexpected frame type: %#"PRIx8,
+                    frame.frame_type);
+            continue;
+        }
+
+        if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD)
+        {
+            DEBUG ("amqp plugin: Unexpected method id: %#"PRIx32,
+                    frame.payload.method.id);
+            continue;
+        }
+
+        status = camqp_read_header (conf);
+
+        amqp_maybe_release_buffers (conf->connection);
+    } /* while (subscriber_threads_running) */
+
+    camqp_config_free (conf);
+    pthread_exit (NULL);
+    return (NULL);
+} /* }}} void *camqp_subscribe_thread */
+
+static int camqp_subscribe_init (camqp_config_t *conf) /* {{{ */
+{
+    int status;
+    pthread_t *tmp;
+
+    tmp = realloc (subscriber_threads,
+            sizeof (*subscriber_threads) * (subscriber_threads_num + 1));
+    if (tmp == NULL)
+    {
+        ERROR ("amqp plugin: realloc failed.");
+        camqp_config_free (conf);
+        return (ENOMEM);
+    }
+    subscriber_threads = tmp;
+    tmp = subscriber_threads + subscriber_threads_num;
+    memset (tmp, 0, sizeof (*tmp));
+
+    status = pthread_create (tmp, /* attr = */ NULL,
+            camqp_subscribe_thread, conf);
+    if (status != 0)
+    {
+        char errbuf[1024];
+        ERROR ("amqp plugin: pthread_create failed: %s",
+                sstrerror (status, errbuf, sizeof (errbuf)));
+        camqp_config_free (conf);
+        return (status);
+    }
+
+    subscriber_threads_num++;
+
+    return (0);
+} /* }}} int camqp_subscribe_init */
+
+/*
+ * Publishing code
+ */
+/* XXX: You must hold "conf->lock" when calling this function! */
+static int camqp_write_locked (camqp_config_t *conf, /* {{{ */
+        const char *buffer, const char *routing_key)
+{
+    amqp_basic_properties_t props;
+    int status;
+
+    status = camqp_connect (conf);
+    if (status != 0)
+        return (status);
+
+    memset (&props, 0, sizeof (props));
+    props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG
+        | AMQP_BASIC_DELIVERY_MODE_FLAG
+        | AMQP_BASIC_APP_ID_FLAG;
+    if (conf->format == CAMQP_FORMAT_COMMAND)
+        props.content_type = amqp_cstring_bytes("text/collectd");
+    else if (conf->format == CAMQP_FORMAT_JSON)
+        props.content_type = amqp_cstring_bytes("application/json");
+    else
+        assert (23 == 42);
+    props.delivery_mode = conf->delivery_mode;
+    props.app_id = amqp_cstring_bytes("collectd");
+
+    status = amqp_basic_publish(conf->connection,
+                /* channel = */ 1,
+                amqp_cstring_bytes(CONF(conf, exchange)),
+                amqp_cstring_bytes (routing_key),
+                /* mandatory = */ 0,
+                /* immediate = */ 0,
+                &props,
+                amqp_cstring_bytes(buffer));
+    if (status != 0)
+    {
+        ERROR ("amqp plugin: amqp_basic_publish failed with status %i.",
+                status);
+        camqp_close_connection (conf);
+    }
+
+    return (status);
+} /* }}} int camqp_write_locked */
+
+static int camqp_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
+        user_data_t *user_data)
+{
+    camqp_config_t *conf = user_data->data;
+    char routing_key[6 * DATA_MAX_NAME_LEN];
+    char buffer[4096];
+    int status;
+
+    if ((ds == NULL) || (vl == NULL) || (conf == NULL))
+        return (EINVAL);
+
+    memset (buffer, 0, sizeof (buffer));
+
+    if (conf->routing_key != NULL)
+    {
+        sstrncpy (routing_key, conf->routing_key, sizeof (routing_key));
+    }
+    else
+    {
+        size_t i;
+        ssnprintf (routing_key, sizeof (routing_key), "collectd/%s/%s/%s/%s/%s",
+                vl->host,
+                vl->plugin, vl->plugin_instance,
+                vl->type, vl->type_instance);
+
+        /* Switch slashes (the only character forbidden by collectd) and dots
+         * (the separation character used by AMQP). */
+        for (i = 0; routing_key[i] != 0; i++)
+        {
+            if (routing_key[i] == '.')
+                routing_key[i] = '/';
+            else if (routing_key[i] == '/')
+                routing_key[i] = '.';
+        }
+    }
+
+    if (conf->format == CAMQP_FORMAT_COMMAND)
+    {
+        status = create_putval (buffer, sizeof (buffer), ds, vl);
+        if (status != 0)
+        {
+            ERROR ("amqp plugin: create_putval failed with status %i.",
+                    status);
+            return (status);
+        }
+    }
+    else if (conf->format == CAMQP_FORMAT_JSON)
+    {
+        size_t bfree = sizeof (buffer);
+        size_t bfill = 0;
+
+        format_json_initialize (buffer, &bfill, &bfree);
+        format_json_value_list (buffer, &bfill, &bfree, ds, vl, conf->store_rates);
+        format_json_finalize (buffer, &bfill, &bfree);
+    }
+    else
+    {
+        ERROR ("amqp plugin: Invalid format (%i).", conf->format);
+        return (-1);
+    }
+
+    pthread_mutex_lock (&conf->lock);
+    status = camqp_write_locked (conf, buffer, routing_key);
+    pthread_mutex_unlock (&conf->lock);
+
+    return (status);
+} /* }}} int camqp_write */
+
+/*
+ * Config handling
+ */
+static int camqp_config_set_format (oconfig_item_t *ci, /* {{{ */
+        camqp_config_t *conf)
+{
+    char *string;
+    int status;
+
+    string = NULL;
+    status = cf_util_get_string (ci, &string);
+    if (status != 0)
+        return (status);
+
+    assert (string != NULL);
+    if (strcasecmp ("Command", string) == 0)
+        conf->format = CAMQP_FORMAT_COMMAND;
+    else if (strcasecmp ("JSON", string) == 0)
+        conf->format = CAMQP_FORMAT_JSON;
+    else
+    {
+        WARNING ("amqp plugin: Invalid format string: %s",
+                string);
+    }
+
+    free (string);
+
+    return (0);
+} /* }}} int config_set_string */
+
+static int camqp_config_connection (oconfig_item_t *ci, /* {{{ */
+        _Bool publish)
+{
+    camqp_config_t *conf;
+    int status;
+    int i;
+
+    conf = malloc (sizeof (*conf));
+    if (conf == NULL)
+    {
+        ERROR ("amqp plugin: malloc failed.");
+        return (ENOMEM);
+    }
+
+    /* Initialize "conf" {{{ */
+    memset (conf, 0, sizeof (*conf));
+    conf->publish = publish;
+    conf->name = NULL;
+    conf->format = CAMQP_FORMAT_COMMAND;
+    conf->host = NULL;
+    conf->port = 5672;
+    conf->vhost = NULL;
+    conf->user = NULL;
+    conf->password = NULL;
+    conf->exchange = NULL;
+    conf->routing_key = NULL;
+    /* publish only */
+    conf->delivery_mode = CAMQP_DM_VOLATILE;
+    conf->store_rates = 0;
+    /* subscribe only */
+    conf->exchange_type = NULL;
+    conf->queue = NULL;
+    /* general */
+    conf->connection = NULL;
+    pthread_mutex_init (&conf->lock, /* attr = */ NULL);
+    /* }}} */
+
+    status = cf_util_get_string (ci, &conf->name);
+    if (status != 0)
+    {
+        sfree (conf);
+        return (status);
+    }
+
+    for (i = 0; i < ci->children_num; i++)
+    {
+        oconfig_item_t *child = ci->children + i;
+
+        if (strcasecmp ("Host", child->key) == 0)
+            status = cf_util_get_string (child, &conf->host);
+        else if (strcasecmp ("Port", child->key) == 0)
+        {
+            status = cf_util_get_port_number (child);
+            if (status > 0)
+            {
+                conf->port = status;
+                status = 0;
+            }
+        }
+        else if (strcasecmp ("VHost", child->key) == 0)
+            status = cf_util_get_string (child, &conf->vhost);
+        else if (strcasecmp ("User", child->key) == 0)
+            status = cf_util_get_string (child, &conf->user);
+        else if (strcasecmp ("Password", child->key) == 0)
+            status = cf_util_get_string (child, &conf->password);
+        else if (strcasecmp ("Exchange", child->key) == 0)
+            status = cf_util_get_string (child, &conf->exchange);
+        else if ((strcasecmp ("ExchangeType", child->key) == 0) && !publish)
+            status = cf_util_get_string (child, &conf->exchange_type);
+        else if ((strcasecmp ("Queue", child->key) == 0) && !publish)
+            status = cf_util_get_string (child, &conf->queue);
+        else if (strcasecmp ("RoutingKey", child->key) == 0)
+            status = cf_util_get_string (child, &conf->routing_key);
+        else if ((strcasecmp ("Persistent", child->key) == 0) && publish)
+        {
+            _Bool tmp = 0;
+            status = cf_util_get_boolean (child, &tmp);
+            if (tmp)
+                conf->delivery_mode = CAMQP_DM_PERSISTENT;
+            else
+                conf->delivery_mode = CAMQP_DM_VOLATILE;
+        }
+        else if ((strcasecmp ("StoreRates", child->key) == 0) && publish)
+            status = cf_util_get_boolean (child, &conf->store_rates);
+        else if ((strcasecmp ("Format", child->key) == 0) && publish)
+            status = camqp_config_set_format (child, conf);
+        else
+            WARNING ("amqp plugin: Ignoring unknown "
+                    "configuration option \"%s\".", child->key);
+
+        if (status != 0)
+            break;
+    } /* for (i = 0; i < ci->children_num; i++) */
+
+    if ((status == 0) && (conf->exchange == NULL))
+    {
+        if (conf->exchange_type != NULL)
+            WARNING ("amqp plugin: The option \"ExchangeType\" was given "
+                    "without the \"Exchange\" option. It will be ignored.");
+
+        if (!publish && (conf->routing_key != NULL))
+            WARNING ("amqp plugin: The option \"RoutingKey\" was given "
+                    "without the \"Exchange\" option. It will be ignored.");
+
+    }
+
+    if (status != 0)
+    {
+        camqp_config_free (conf);
+        return (status);
+    }
+
+    if (conf->exchange != NULL)
+    {
+        DEBUG ("amqp plugin: camqp_config_connection: exchange = %s;",
+                conf->exchange);
+    }
+
+    if (publish)
+    {
+        char cbname[128];
+        user_data_t ud = { conf, camqp_config_free };
+
+        ssnprintf (cbname, sizeof (cbname), "amqp/%s", conf->name);
+
+        status = plugin_register_write (cbname, camqp_write, &ud);
+        if (status != 0)
+        {
+            camqp_config_free (conf);
+            return (status);
+        }
+    }
+    else
+    {
+        status = camqp_subscribe_init (conf);
+        if (status != 0)
+        {
+            camqp_config_free (conf);
+            return (status);
+        }
+    }
+
+    return (0);
+} /* }}} int camqp_config_connection */
+
+static int camqp_config (oconfig_item_t *ci) /* {{{ */
+{
+    int i;
+
+    for (i = 0; i < ci->children_num; i++)
+    {
+        oconfig_item_t *child = ci->children + i;
+
+        if (strcasecmp ("Publish", child->key) == 0)
+            camqp_config_connection (child, /* publish = */ 1);
+        else if (strcasecmp ("Subscribe", child->key) == 0)
+            camqp_config_connection (child, /* publish = */ 0);
+        else
+            WARNING ("amqp plugin: Ignoring unknown config option \"%s\".",
+                    child->key);
+    } /* for (ci->children_num) */
+
+    return (0);
+} /* }}} int camqp_config */
+
+void module_register (void)
+{
+    plugin_register_complex_config ("amqp", camqp_config);
+    plugin_register_shutdown ("amqp", camqp_shutdown);
+} /* void module_register */
+
+/* vim: set sw=4 sts=4 et fdm=marker : */
index 5f5441f..c31dd87 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/apache.c
- * Copyright (C) 2006-2009  Florian octo Forster
+ * Copyright (C) 2006-2010  Florian octo Forster
  * Copyright (C) 2007       Florent EppO Monbillard
  * Copyright (C) 2009       Amit Gupta
  *
@@ -144,6 +144,8 @@ static size_t apache_header_callback (void *buf, size_t size, size_t nmemb,
                st->server_type = APACHE;
        else if (strstr (buf, "lighttpd") != NULL)
                st->server_type = LIGHTTPD;
+       else if (strstr (buf, "IBM_HTTP_Server") != NULL)
+               st->server_type = APACHE;
        else
        {
                const char *hdr = buf;
@@ -333,57 +335,22 @@ static int config (oconfig_item_t *ci)
 {
        int status = 0;
        int i;
-       oconfig_item_t *lci = NULL; /* legacy config */
 
        for (i = 0; i < ci->children_num; i++)
        {
                oconfig_item_t *child = ci->children + i;
 
-               if (strcasecmp ("Instance", child->key) == 0 && child->children_num > 0)
+               if (strcasecmp ("Instance", child->key) == 0)
                        config_add (child);
                else
-               {
-                       /* legacy mode - convert to <Instance ...> config */
-                       if (lci == NULL)
-                       {
-                               lci = malloc (sizeof(*lci));
-                               if (lci == NULL)
-                               {
-                                       ERROR ("apache plugin: malloc failed.");
-                                       return (-1);
-                               }
-                               memset (lci, '\0', sizeof (*lci));
-                       }
-
-                       lci->children_num++;
-                       lci->children =
-                               realloc (lci->children,
-                                        lci->children_num * sizeof (*child));
-                       if (lci->children == NULL)
-                       {
-                               ERROR ("apache plugin: realloc failed.");
-                               return (-1);
-                       }
-                       memcpy (&lci->children[lci->children_num-1], child, sizeof (*child));
-               }
+                       WARNING ("apache plugin: The configuration option "
+                                       "\"%s\" is not allowed here. Did you "
+                                       "forget to add an <Instance /> block "
+                                       "around the configuration?",
+                                       child->key);
        } /* for (ci->children) */
 
-       if (lci)
-       {
-               /* create a <Instance ""> entry */
-               lci->key = "Instance";
-               lci->values_num = 1;
-               lci->values = (oconfig_value_t *) malloc (lci->values_num * sizeof (oconfig_value_t));
-               lci->values[0].type = OCONFIG_TYPE_STRING;
-               lci->values[0].value.string = "";
-
-               status = config_add (lci);
-               sfree (lci->values);
-               sfree (lci->children);
-               sfree (lci);
-       }
-
-       return status;
+       return (status);
 } /* int config */
 
 /* initialize curl for each host */
@@ -421,6 +388,8 @@ static int init_host (apache_t *st) /* {{{ */
                        st->server_type = APACHE;
                else if (strcasecmp(st->server, "lighttpd") == 0)
                        st->server_type = LIGHTTPD;
+               else if (strcasecmp(st->server, "ibm_http_server") == 0)
+                       st->server_type = APACHE;
                else
                        WARNING ("apache plugin: Unknown `Server' setting: %s",
                                        st->server);
@@ -508,13 +477,13 @@ static void submit_value (const char *type, const char *type_instance,
        plugin_dispatch_values (&vl);
 } /* void submit_value */
 
-static void submit_counter (const char *type, const char *type_instance,
-               counter_t c, apache_t *st)
+static void submit_derive (const char *type, const char *type_instance,
+               derive_t c, apache_t *st)
 {
        value_t v;
-       v.counter = c;
+       v.derive = c;
        submit_value (type, type_instance, v, st);
-} /* void submit_counter */
+} /* void submit_derive */
 
 static void submit_gauge (const char *type, const char *type_instance,
                gauge_t g, apache_t *st)
@@ -676,11 +645,11 @@ static int apache_read_host (user_data_t *user_data) /* {{{ */
                {
                        if ((strcmp (fields[0], "Total") == 0)
                                        && (strcmp (fields[1], "Accesses:") == 0))
-                               submit_counter ("apache_requests", "",
+                               submit_derive ("apache_requests", "",
                                                atoll (fields[2]), st);
                        else if ((strcmp (fields[0], "Total") == 0)
                                        && (strcmp (fields[1], "kBytes:") == 0))
-                               submit_counter ("apache_bytes", "",
+                               submit_derive ("apache_bytes", "",
                                                1024LL * atoll (fields[2]), st);
                }
                else if (fields_num == 2)
index 28c1e56..38d4a27 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * collectd - src/bind.c
- * Copyright (C) 2009  Bruno Prémont
- * Copyright (C) 2009  Florian Forster
+ * Copyright (C) 2009       Bruno Prémont
+ * Copyright (C) 2009,2010  Florian 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
  *
  * Authors:
  *   Bruno Prémont <bonbons at linux-vserver.org>
- *   Florian Forster <octo at verplant.org>
+ *   Florian Forster <octo at collectd.org>
  **/
 
 #include "config.h"
 
-#ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 600 /* glibc2 needs this for strptime */
-#endif
+#if STRPTIME_NEEDS_STANDARDS
+# ifndef _ISOC99_SOURCE
+#  define _ISOC99_SOURCE 1
+# endif
+# ifndef _POSIX_C_SOURCE
+#  define _POSIX_C_SOURCE 200112L
+# endif
+# ifndef _XOPEN_SOURCE
+#  define _XOPEN_SOURCE 500
+# endif
+#endif /* STRPTIME_NEEDS_STANDARDS */
 
 #include "collectd.h"
 #include "common.h"
@@ -241,7 +249,7 @@ static void submit (time_t ts, const char *plugin_instance, /* {{{ */
 
   vl.values = values;
   vl.values_len = 1;
-  vl.time = ts;
+  vl.time = TIME_T_TO_CDTIME_T (ts);
   sstrncpy(vl.host, hostname_g, sizeof(vl.host));
   sstrncpy(vl.plugin, "bind", sizeof(vl.plugin));
   if (plugin_instance) {
@@ -337,36 +345,31 @@ static int bind_xml_list_callback (const char *name, /* {{{ */
   return (0);
 } /* }}} int bind_xml_list_callback */
 
-static int bind_xml_read_counter (xmlDoc *doc, xmlNode *node, /* {{{ */
-    counter_t *ret_value)
+static int bind_xml_read_derive (xmlDoc *doc, xmlNode *node, /* {{{ */
+    derive_t *ret_value)
 {
-  char *str_ptr, *end_ptr;
-  long long int value;
+  char *str_ptr;
+  value_t value;
+  int status;
 
   str_ptr = (char *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
   if (str_ptr == NULL)
   {
-    ERROR ("bind plugin: bind_xml_read_counter: xmlNodeListGetString failed.");
+    ERROR ("bind plugin: bind_xml_read_derive: xmlNodeListGetString failed.");
     return (-1);
   }
 
-  errno = 0;
-  value = strtoll (str_ptr, &end_ptr, 10);
-  xmlFree(str_ptr);
-  if (str_ptr == end_ptr || errno)
+  status = parse_value (str_ptr, &value, DS_TYPE_DERIVE);
+  if (status != 0)
   {
-    if (errno && (value < 0))
-      ERROR ("bind plugin: bind_xml_read_counter: strtoll failed with underflow.");
-    else if (errno && (value > 0))
-      ERROR ("bind plugin: bind_xml_read_counter: strtoll failed with overflow.");
-    else
-      ERROR ("bind plugin: bind_xml_read_counter: strtoll failed.");
+    ERROR ("bind plugin: Parsing string \"%s\" to derive value failed.",
+        str_ptr);
     return (-1);
   }
 
-  *ret_value = value;
+  *ret_value = value.derive;
   return (0);
-} /* }}} int bind_xml_read_counter */
+} /* }}} int bind_xml_read_derive */
 
 static int bind_xml_read_gauge (xmlDoc *doc, xmlNode *node, /* {{{ */
     gauge_t *ret_value)
@@ -527,7 +530,7 @@ static int bind_parse_generic_name_value (const char *xpath_expression, /* {{{ *
       if (ds_type == DS_TYPE_GAUGE)
         status = bind_xml_read_gauge (doc, counter, &value.gauge);
       else
-        status = bind_xml_read_counter (doc, counter, &value.counter);
+        status = bind_xml_read_derive (doc, counter, &value.derive);
       if (status != 0)
         continue;
 
@@ -600,7 +603,7 @@ static int bind_parse_generic_value_list (const char *xpath_expression, /* {{{ *
       if (ds_type == DS_TYPE_GAUGE)
         status = bind_xml_read_gauge (doc, child, &value.gauge);
       else
-        status = bind_xml_read_counter (doc, child, &value.counter);
+        status = bind_xml_read_derive (doc, child, &value.derive);
       if (status != 0)
         continue;
 
index 81b3a2e..10f6829 100644 (file)
@@ -273,6 +273,14 @@ to make use of collectd's more powerful interface.
 The user, the binary is executed as, may not have root privileges, i.E<nbsp>e.
 must have an UID that is non-zero. This is for your own good.
 
+=item
+
+Early versions of the plugin did not use a command but treated all lines as if
+they were arguments to the I<PUTVAL> command. When the I<PUTNOTIF> command was
+implemented, this behavior was kept for lines which start with an unknown
+command for backwards compatibility. This compatibility code has been removed
+in I<collectdE<nbsp>5>.
+
 =back
 
 =head1 SEE ALSO
index 9c0c6eb..9e2f81a 100644 (file)
@@ -667,6 +667,14 @@ will be used.
 Use I<password> to authenticate to the server. If not given, unauthenticated
 access is used.
 
+=item B<InstancePrefix> I<prefix>
+
+Prefixes the generated I<plugin instance> with I<prefix>. If a second
+I<InstancePrefix> is specified in a referenced I<MBean> block, the prefix
+specified in the I<Connection> block will appear at the beginning of the
+I<plugin instance>, the prefix specified in the I<MBean> block will be appended
+to it.
+
 =item B<Collect> I<mbean_block_name>
 
 Configures which of the I<MBean> blocks to use with this connection. May be
index 45162bd..af8744d 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd-nagios - src/collectd-nagios.c
- * Copyright (C) 2008  Florian octo Forster
+ * Copyright (C) 2008-2010  Florian octo Forster
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
 #include <strings.h>
 #include <assert.h>
 
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include "libcollectdclient/client.h"
-
-/*
- * This is copied directly from collectd.h. Make changes there!
- */
 #if NAN_STATIC_DEFAULT
 # include <math.h>
 /* #endif NAN_STATIC_DEFAULT*/
 # ifndef isnan
 #  define isnan(f) ((f) != (f))
 # endif /* !defined(isnan) */
+# ifndef isfinite
+#  define isfinite(f) (((f) - (f)) == 0.0)
+# endif
+# ifndef isinf
+#  define isinf(f) (!isfinite(f) && !isnan(f))
+# endif
 #endif /* NAN_ZERO_ZERO */
 
+#include "libcollectdclient/client.h"
+
 #define RET_OKAY     0
 #define RET_WARNING  1
 #define RET_CRITICAL 2
@@ -96,6 +96,7 @@ static char *hostname_g = NULL;
 static range_t range_critical_g;
 static range_t range_warning_g;
 static int consolitation_g = CON_NONE;
+static _Bool nan_is_error_g = 0;
 
 static char **match_ds_g = NULL;
 static int    match_ds_num_g = 0;
@@ -254,6 +255,7 @@ static void usage (const char *name)
                        "  -H <host>      Hostname to query the values for.\n"
                        "  -c <range>     Critical range\n"
                        "  -w <range>     Warning range\n"
+                       "  -m             Treat \"Not a Number\" (NaN) as critical (default: warning)\n"
                        "\n"
                        "Consolidation functions:\n"
                        "  none:          Apply the warning- and critical-ranges to each data-source\n"
@@ -280,7 +282,12 @@ static int do_check_con_none (size_t values_num,
        for (i = 0; i < values_num; i++)
        {
                if (isnan (values[i]))
-                       num_warning++;
+               {
+                       if (nan_is_error_g)
+                               num_critical++;
+                       else
+                               num_warning++;
+               }
                else if (match_range (&range_critical_g, values[i]) != 0)
                        num_critical++;
                else if (match_range (&range_warning_g, values[i]) != 0)
@@ -337,11 +344,18 @@ static int do_check_con_average (size_t values_num,
        total_num = 0;
        for (i = 0; i < values_num; i++)
        {
-               if (!isnan (values[i]))
+               if (isnan (values[i]))
                {
-                       total += values[i];
-                       total_num++;
+                       if (!nan_is_error_g)
+                               continue;
+
+                       printf ("CRITICAL: Data source \"%s\" is NaN\n",
+                                       values_names[i]);
+                       return (RET_CRITICAL);
                }
+
+               total += values[i];
+               total_num++;
        }
 
        if (total_num == 0)
@@ -389,11 +403,18 @@ static int do_check_con_sum (size_t values_num,
        total_num = 0;
        for (i = 0; i < values_num; i++)
        {
-               if (!isnan (values[i]))
+               if (isnan (values[i]))
                {
-                       total += values[i];
-                       total_num++;
+                       if (!nan_is_error_g)
+                               continue;
+
+                       printf ("CRITICAL: Data source \"%s\" is NaN\n",
+                                       values_names[i]);
+                       return (RET_CRITICAL);
                }
+
+               total += values[i];
+               total_num++;
        }
 
        if (total_num == 0)
@@ -443,8 +464,19 @@ static int do_check_con_percentage (size_t values_num,
        }
 
        for (i = 0; i < values_num; i++)
-               if (!isnan (values[i]))
-                       sum += values[i];
+       {
+               if (isnan (values[i]))
+               {
+                       if (!nan_is_error_g)
+                               continue;
+
+                       printf ("CRITICAL: Data source \"%s\" is NaN\n",
+                                       values_names[i]);
+                       return (RET_CRITICAL);
+               }
+
+               sum += values[i];
+       }
 
        if (sum == 0.0)
        {
@@ -563,7 +595,7 @@ int main (int argc, char **argv)
        {
                int c;
 
-               c = getopt (argc, argv, "w:c:s:n:H:g:d:h");
+               c = getopt (argc, argv, "w:c:s:n:H:g:d:hm");
                if (c < 0)
                        break;
 
@@ -623,6 +655,9 @@ int main (int argc, char **argv)
                                match_ds_num_g++;
                                break;
                        }
+                       case 'm':
+                               nan_is_error_g = 1;
+                               break;
                        default:
                                usage (argv[0]);
                } /* switch (c) */
index c6347ea..d7c749c 100644 (file)
@@ -94,6 +94,12 @@ I<min> (and the colon) may be omitted,
 I<min> is then assumed to be zero. If I<max> (but not the trailing colon) is
 omitted, I<max> is assumed to be positive infinity.
 
+=item B<-m>
+
+If this option is given, "Not a Number" (NaN) is treated as I<critical>. By
+default, the I<none> consolidation reports NaNs as I<warning>. Other
+consolidations simply ignore NaN values.
+
 =back
 
 =head1 RETURN VALUE
index 5c11b65..d5401dd 100644 (file)
@@ -376,11 +376,6 @@ is found (and the number of values matches the number of data-sources) then the
 type, data-set and value-list is passed to all write-callbacks that are
 registered with the daemon.
 
-B<Note>: Prior to version 4.4 of collectd, the data-set type used to be passed
-as the first argument to B<plugin_register>. This syntax is still supported
-for backwards compatibility but has been deprecated and will be removed in
-some future version of collectd.
-
 =item B<plugin_write> ([B<plugins> => I<...>][, B<datasets> => I<...>],
 B<valuelists> => I<...>)
 
@@ -405,23 +400,6 @@ argument has been specified, only named plugins will be flushed. The value of
 the B<plugins> and B<identifiers> arguments may either be a string or a
 reference to an array of strings.
 
-=item B<plugin_flush_one> (I<timeout>, I<plugin>)
-
-This is identical to using "plugin_flush (timeout =E<gt> I<timeout>, plugins
-=E<gt> I<plugin>".
-
-B<Note>: Starting with version 4.5 of collectd, B<plugin_flush_one> has been
-deprecated and will be removed in some future version of collectd. Use
-B<plugin_flush> instead.
-
-=item B<plugin_flush_all> (I<timeout>)
-
-This is identical to using "plugin_flush (timeout =E<gt> I<timeout>)".
-
-B<Note>: Starting with version 4.5 of collectd, B<plugin_flush_all> has been
-deprecated and will be removed in some future version of collectd. Use
-B<plugin_flush> instead.
-
 =item B<plugin_dispatch_notification> (I<notification>)
 
 Submits a I<notification> to the daemon which will then pass it to all
@@ -678,9 +656,9 @@ A very simple read function might look like:
 
   sub foobar_read
   {
-    my $vl = { plugin => 'foobar' };
+    my $vl = { plugin => 'foobar', type => 'gauge' };
     $vl->{'values'} = [ rand(42) ];
-    plugin_dispatch_values ('gauge', $vl);
+    plugin_dispatch_values ($vl);
     return 1;
   }
 
diff --git a/src/collectd-threshold.pod b/src/collectd-threshold.pod
new file mode 100644 (file)
index 0000000..5d1a645
--- /dev/null
@@ -0,0 +1,194 @@
+=head1 NAME
+
+collectd-threshold - Documentation of collectd's I<Threshold plugin>
+
+=head1 SYNOPSIS
+
+ LoadPlugin "threshold"
+ <Plugin "threshold">
+   <Type "foo">
+     WarningMin    0.00
+     WarningMax 1000.00
+     FailureMin    0.00
+     FailureMax 1200.00
+     Invert false
+     Instance "bar"
+   </Type>
+ </Plugin>
+
+=head1 DESCRIPTION
+
+Starting with version C<4.3.0> I<collectd> has support for B<monitoring>. By
+that we mean that the values are not only stored or sent somewhere, but that
+they are judged and, if a problem is recognized, acted upon. The only action
+the I<Threshold plugin> takes itself is to generate and dispatch a
+I<notification>. Other plugins can register to receive notifications and
+perform appropriate further actions.
+
+Since systems and what you expect them to do differ a lot, you can configure
+I<thresholds> for your values freely. This gives you a lot of flexibility but
+also a lot of responsibility.
+
+Every time a value is out of range, a notification is dispatched. This means
+that the idle percentage of your CPU needs to be less then the configured
+threshold only once for a notification to be generated. There's no such thing
+as a moving average or similar - at least not now.
+
+Also, all values that match a threshold are considered to be relevant or
+"interesting". As a consequence collectd will issue a notification if they are
+not received for B<Timeout> iterations. The B<Timeout> configuration option is
+explained in section L<collectd.conf(5)/"GLOBAL OPTIONS">. If, for example,
+B<Timeout> is set to "2" (the default) and some hosts sends it's CPU statistics
+to the server every 60 seconds, a notification will be dispatched after about
+120 seconds. It may take a little longer because the timeout is checked only
+once each B<Interval> on the server.
+
+When a value comes within range again or is received after it was missing, an
+"OKAY-notification" is dispatched.
+
+=head1 CONFIGURATION
+
+Here is a configuration example to get you started. Read below for more
+information.
+
+ LoadPlugin "threshold"
+ <Plugin "threshold">
+   <Type "foo">
+     WarningMin    0.00
+     WarningMax 1000.00
+     FailureMin    0.00
+     FailureMax 1200.00
+     Invert false
+     Instance "bar"
+   </Type>
+   
+   <Plugin "interface">
+     Instance "eth0"
+     <Type "if_octets">
+       FailureMax 10000000
+       DataSource "rx"
+     </Type>
+   </Plugin>
+   
+   <Host "hostname">
+     <Type "cpu">
+       Instance "idle"
+       FailureMin 10
+     </Type>
+   
+     <Plugin "memory">
+       <Type "memory">
+         Instance "cached"
+         WarningMin 100000000
+       </Type>
+     </Plugin>
+   
+     <Type "load">
+       DataSource "midterm"
+       FailureMax 4
+       Hits 3
+       Hysteresis 3
+     </Type>
+   </Host>
+ </Plugin>
+
+There are basically two types of configuration statements: The C<Host>,
+C<Plugin>, and C<Type> blocks select the value for which a threshold should be
+configured. The C<Plugin> and C<Type> blocks may be specified further using the
+C<Instance> option. You can combine the block by nesting the blocks, though
+they must be nested in the above order, i.e. C<Host> may contain either
+C<Plugin> and C<Type> blocks, C<Plugin> may only contain C<Type> blocks and
+C<Type> may not contain other blocks. If multiple blocks apply to the same
+value the most specific block is used.
+
+The other statements specify the threshold to configure. They B<must> be
+included in a C<Type> block. Currently the following statements are recognized:
+
+=over 4
+
+=item B<FailureMax> I<Value>
+
+=item B<WarningMax> I<Value>
+
+Sets the upper bound of acceptable values. If unset defaults to positive
+infinity. If a value is greater than B<FailureMax> a B<FAILURE> notification
+will be created. If the value is greater than B<WarningMax> but less than (or
+equal to) B<FailureMax> a B<WARNING> notification will be created.
+
+=item B<FailureMin> I<Value>
+
+=item B<WarningMin> I<Value>
+
+Sets the lower bound of acceptable values. If unset defaults to negative
+infinity. If a value is less than B<FailureMin> a B<FAILURE> notification will
+be created. If the value is less than B<WarningMin> but greater than (or equal
+to) B<FailureMin> a B<WARNING> notification will be created.
+
+=item B<DataSource> I<DSName>
+
+Some data sets have more than one "data source". Interesting examples are the
+C<if_octets> data set, which has received (C<rx>) and sent (C<tx>) bytes and
+the C<disk_ops> data set, which holds C<read> and C<write> operations. The
+system load data set, C<load>, even has three data sources: C<shortterm>,
+C<midterm>, and C<longterm>.
+
+Normally, all data sources are checked against a configured threshold. If this
+is undesirable, or if you want to specify different limits for each data
+source, you can use the B<DataSource> option to have a threshold apply only to
+one data source.
+
+=item B<Invert> B<true>|B<false>
+
+If set to B<true> the range of acceptable values is inverted, i.e. values
+between B<FailureMin> and B<FailureMax> (B<WarningMin> and B<WarningMax>) are
+not okay. Defaults to B<false>.
+
+=item B<Persist> B<true>|B<false>
+
+Sets how often notifications are generated. If set to B<true> one notification
+will be generated for each value that is out of the acceptable range. If set to
+B<false> (the default) then a notification is only generated if a value is out
+of range but the previous value was okay.
+
+This applies to missing values, too: If set to B<true> a notification about a
+missing value is generated once every B<Interval> seconds. If set to B<false>
+only one such notification is generated until the value appears again.
+
+=item B<Percentage> B<true>|B<false>
+
+If set to B<true>, the minimum and maximum values given are interpreted as
+percentage value, relative to the other data sources. This is helpful for
+example for the "df" type, where you may want to issue a warning when less than
+5E<nbsp>% of the total space is available. Defaults to B<false>.
+
+=item B<Hits> I<Value>
+
+Sets the number of occurrences which the threshold must be raised before to
+dispatch any notification or, in other words, the number of B<Interval>s
+that the threshold must be match before dispatch any notification.
+
+=item B<Hysteresis> I<Value>
+
+Sets the hysteresis value for threshold. The hysteresis is a method to prevent
+flapping between states, until a new received value for a previously matched
+threshold down below the threshold condition (B<WarningMax>, B<FailureMin> or
+everything else) minus the hysteresis value, the failure (respectively warning)
+state will be keep.
+
+=item B<Interesting> B<true>|B<false>
+
+If set to B<true> (the default), the threshold must be treated as interesting
+and, when a number of B<Timeout> values will lost, then a missing notification
+will be dispatched. On the other hand, if set to B<false>, the missing
+notification will never dispatched for this threshold.
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>,
+L<collectd.conf(5)>
+
+=head1 AUTHOR
+
+Florian Forster E<lt>octoE<nbsp>atE<nbsp>collectd.orgE<gt>
index 6b77d59..ceb184b 100644 (file)
@@ -40,7 +40,7 @@
  * Global variables
  */
 char hostname_g[DATA_MAX_NAME_LEN];
-int  interval_g;
+cdtime_t interval_g;
 int  timeout_g;
 #if HAVE_LIBKSTAT
 kstat_ctl_t *kc;
@@ -51,7 +51,9 @@ static int loop = 0;
 static void *do_flush (void __attribute__((unused)) *arg)
 {
        INFO ("Flushing all data.");
-       plugin_flush (NULL, -1, NULL);
+       plugin_flush (/* plugin = */ NULL,
+                       /* timeout = */ 0,
+                       /* ident = */ NULL);
        INFO ("Finished flushing all data.");
        pthread_exit (NULL);
        return NULL;
@@ -140,15 +142,25 @@ static int init_global_variables (void)
 
        str = global_option_get ("Interval");
        if (str == NULL)
-               str = "10";
-       interval_g = atoi (str);
-       if (interval_g <= 0)
        {
-               fprintf (stderr, "Cannot set the interval to a correct value.\n"
-                               "Please check your settings.\n");
-               return (-1);
+               interval_g = TIME_T_TO_CDTIME_T (10);
+       }
+       else
+       {
+               double tmp;
+
+               tmp = atof (str);
+               if (tmp <= 0.0)
+               {
+                       fprintf (stderr, "Cannot set the interval to a "
+                                       "correct value.\n"
+                                       "Please check your settings.\n");
+                       return (-1);
+               }
+
+               interval_g = DOUBLE_TO_CDTIME_T (tmp);
        }
-       DEBUG ("interval_g = %i;", interval_g);
+       DEBUG ("interval_g = %.3f;", CDTIME_T_TO_DOUBLE (interval_g));
 
        str = global_option_get ("Timeout");
        if (str == NULL)
@@ -315,22 +327,14 @@ static int do_init (void)
 
 static int do_loop (void)
 {
-       struct timeval tv_now;
-       struct timeval tv_next;
-       struct timeval tv_wait;
-       struct timespec ts_wait;
+       cdtime_t wait_until;
+
+       wait_until = cdtime () + interval_g;
 
        while (loop == 0)
        {
-               if (gettimeofday (&tv_next, NULL) < 0)
-               {
-                       char errbuf[1024];
-                       ERROR ("gettimeofday failed: %s",
-                                       sstrerror (errno, errbuf,
-                                               sizeof (errbuf)));
-                       return (-1);
-               }
-               tv_next.tv_sec += interval_g;
+               struct timespec ts_wait = { 0, 0 };
+               cdtime_t now;
 
 #if HAVE_LIBKSTAT
                update_kstat ();
@@ -339,27 +343,20 @@ static int do_loop (void)
                /* Issue all plugins */
                plugin_read_all ();
 
-               if (gettimeofday (&tv_now, NULL) < 0)
-               {
-                       char errbuf[1024];
-                       ERROR ("gettimeofday failed: %s",
-                                       sstrerror (errno, errbuf,
-                                               sizeof (errbuf)));
-                       return (-1);
-               }
-
-               if (timeval_cmp (tv_next, tv_now, &tv_wait) <= 0)
+               now = cdtime ();
+               if (now >= wait_until)
                {
                        WARNING ("Not sleeping because the next interval is "
-                                       "%i.%06i seconds in the past!",
-                                       (int) tv_wait.tv_sec, (int) tv_wait.tv_usec);
+                                       "%.3f seconds in the past!",
+                                       CDTIME_T_TO_DOUBLE (now - wait_until));
+                       wait_until = now + interval_g;
                        continue;
                }
 
-               ts_wait.tv_sec  = tv_wait.tv_sec;
-               ts_wait.tv_nsec = (long) (1000 * tv_wait.tv_usec);
+               CDTIME_T_TO_TIMESPEC (wait_until - now, &ts_wait);
+               wait_until = wait_until + interval_g;
 
-               while ((loop == 0) && (nanosleep (&ts_wait, &ts_wait) == -1))
+               while ((loop == 0) && (nanosleep (&ts_wait, &ts_wait) != 0))
                {
                        if (errno != EINTR)
                        {
@@ -372,7 +369,6 @@ static int do_loop (void)
                }
        } /* while (loop == 0) */
 
-       DEBUG ("return (0);");
        return (0);
 } /* int do_loop */
 
index 21d0eb1..cd65fd2 100644 (file)
@@ -11,7 +11,7 @@
 ##############################################################################
 
 #Hostname    "localhost"
-FQDNLookup   true
+#FQDNLookup   true
 #BaseDir     "@prefix@/var/lib/@PACKAGE_NAME@"
 #PIDFile     "@prefix@/var/run/@PACKAGE_NAME@.pid"
 #PluginDir   "@prefix@/lib/@PACKAGE_NAME@"
@@ -52,6 +52,7 @@ FQDNLookup   true
 # to missing dependencies or because they have been deactivated explicitly.  #
 ##############################################################################
 
+#@BUILD_PLUGIN_AMQP_TRUE@LoadPlugin amqp
 #@BUILD_PLUGIN_APACHE_TRUE@LoadPlugin apache
 #@BUILD_PLUGIN_APCUPS_TRUE@LoadPlugin apcups
 #@BUILD_PLUGIN_APPLE_SENSORS_TRUE@LoadPlugin apple_sensors
@@ -85,6 +86,7 @@ FQDNLookup   true
 #@BUILD_PLUGIN_JAVA_TRUE@LoadPlugin java
 #@BUILD_PLUGIN_LIBVIRT_TRUE@LoadPlugin libvirt
 @BUILD_PLUGIN_LOAD_TRUE@@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
+#@BUILD_PLUGIN_LPAR_TRUE@LoadPlugin lpar
 #@BUILD_PLUGIN_MADWIFI_TRUE@LoadPlugin madwifi
 #@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
 #@BUILD_PLUGIN_MEMCACHEC_TRUE@LoadPlugin memcachec
@@ -118,6 +120,7 @@ FQDNLookup   true
 #@BUILD_PLUGIN_PYTHON_TRUE@<LoadPlugin python>
 #@BUILD_PLUGIN_PYTHON_TRUE@  Globals true
 #@BUILD_PLUGIN_PYTHON_TRUE@</LoadPlugin>
+#@BUILD_PLUGIN_REDIS_TRUE@LoadPlugin redis
 #@BUILD_PLUGIN_ROUTEROS_TRUE@LoadPlugin routeros
 #@BUILD_PLUGIN_RRDCACHED_TRUE@LoadPlugin rrdcached
 @LOAD_PLUGIN_RRDTOOL@LoadPlugin rrdtool
@@ -137,10 +140,12 @@ FQDNLookup   true
 #@BUILD_PLUGIN_UPTIME_TRUE@LoadPlugin uptime
 #@BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
 #@BUILD_PLUGIN_UUID_TRUE@LoadPlugin uuid
+#@BUILD_PLUGIN_VARNISH_TRUE@LoadPlugin varnish
 #@BUILD_PLUGIN_VMEM_TRUE@LoadPlugin vmem
 #@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
 #@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
 #@BUILD_PLUGIN_WRITE_HTTP_TRUE@LoadPlugin write_http
+#@BUILD_PLUGIN_WRITE_REDIS_TRUE@LoadPlugin write_redis
 #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
 #@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc
 
@@ -151,11 +156,27 @@ FQDNLookup   true
 # ription of those options is available in the collectd.conf(5) manual page. #
 ##############################################################################
 
+#<Plugin "amqp">
+#  <Publish "name">
+#    Host "localhost"
+#    Port "5672"
+#    VHost "/"
+#    User "guest"
+#    Password "guest"
+#    Exchange "amq.fanout"
+#    RoutingKey "collectd"
+#    Persistent false
+#    StoreRates false
+#  </Publish>
+#</Plugin>
+
 #<Plugin apache>
-#      URL "http://localhost/status?auto"
-#      User "www-user"
-#      Password "secret"
-#      CACert "/etc/ssl/ca.crt"
+#  <Instance "local">
+#    URL "http://localhost/status?auto"
+#    User "www-user"
+#    Password "secret"
+#    CACert "/etc/ssl/ca.crt"
+#  </Instance>
 #</Plugin>
 
 #<Plugin apcups>
@@ -342,13 +363,6 @@ FQDNLookup   true
 #<Plugin hddtemp>
 #  Host "127.0.0.1"
 #  Port "7634"
-#
-#  #----------------------------------------------------------------#
-#  # `TranslateDevicename' enables backwards compatibility behavior #
-#  # and is enabled by default. Setting this option to `false' is   #
-#  # highly recommended.                                            #
-#  #----------------------------------------------------------------#
-#  TranslateDevicename false
 #</Plugin>
 
 #<Plugin interface>
@@ -394,6 +408,12 @@ FQDNLookup   true
 #      InterfaceDevice "name:device"
 #      IgnoreSelected false
 #      HostnameFormat name
+#      InterfaceFormat name
+#</Plugin>
+
+#<Plugin lpar>
+#      CpuPoolStats   false
+#      ReportBySerial false
 #</Plugin>
 
 #<Plugin madwifi>
@@ -741,6 +761,14 @@ FQDNLookup   true
 #      </Module>
 #</Plugin>
 
+#<Plugin redis>
+#   <Node example>
+#      Host "redis.example.com"
+#      Port "6379"
+#      Timeout 2000
+#   </Node>
+#</Plugin>
+
 #<Plugin routeros>
 #      <Router>
 #              Host "router.example.com"
@@ -888,12 +916,34 @@ FQDNLookup   true
 #      SocketFile "@prefix@/var/run/@PACKAGE_NAME@-unixsock"
 #      SocketGroup "collectd"
 #      SocketPerms "0660"
+#      DeleteSocket false
 #</Plugin>
 
 #<Plugin uuid>
 #      UUIDFile "/etc/uuid"
 #</Plugin>
 
+#<Plugin varnish>
+#   This tag support an argument if you want to
+#   monitor the local instance just use </Instance>
+#   If you prefer defining another instance you can do
+#   so by using <Instance "myinstance">
+#   <Instance>
+#      CollectCache true
+#      CollectBackend true
+#      CollectConnections true
+#      CollectSHM true
+#      CollectESI false
+#      CollectFetch false
+#      CollectHCB false
+#      CollectSMA false
+#      CollectSMS false
+#      CollectSM false
+#      CollectTotals false
+#      CollectWorkers false
+#   </Instance>
+#</Plugin>
+
 #<Plugin vmem>
 #      Verbose false
 #</Plugin>
@@ -910,6 +960,14 @@ FQDNLookup   true
 #      </URL>
 #</Plugin>
 
+#<Plugin write_redis>
+#      <Node "example">
+#              Host "localhost"
+#              Port "6379"
+#              Timeout 1000
+#      </Node>
+#</Plugin>
+
 ##############################################################################
 # Filter configuration                                                       #
 #----------------------------------------------------------------------------#
@@ -930,6 +988,7 @@ FQDNLookup   true
 #@BUILD_PLUGIN_TARGET_REPLACE_TRUE@LoadPlugin target_replace
 #@BUILD_PLUGIN_TARGET_SCALE_TRUE@LoadPlugin target_scale
 #@BUILD_PLUGIN_TARGET_SET_TRUE@LoadPlugin target_set
+#@BUILD_PLUGIN_TARGET_V5UPGRADE_TRUE@LoadPlugin target_v5upgrade
 
 #----------------------------------------------------------------------------#
 # The following block demonstrates the default behavior if no filtering is   #
@@ -939,3 +998,52 @@ FQDNLookup   true
 #<Chain "PostCache">
 #  Target "write"
 #</Chain>
+
+##############################################################################
+# Threshold configuration                                                    #
+#----------------------------------------------------------------------------#
+# The following outlines how to configure collectd's threshold checking      #
+# plugin. The plugin and possible configuration options are documented in    #
+# the collectd-threshold(5) manual page.                                     #
+##############################################################################
+
+#@BUILD_PLUGIN_THRESHOLD_TRUE@LoadPlugin "threshold"
+#<Plugin "threshold">
+#  <Type "foo">
+#    WarningMin    0.00
+#    WarningMax 1000.00
+#    FailureMin    0.00
+#    FailureMax 1200.00
+#    Invert false
+#    Instance "bar"
+#  </Type>
+#
+#  <Plugin "interface">
+#    Instance "eth0"
+#    <Type "if_octets">
+#      FailureMax 10000000
+#      DataSource "rx"
+#    </Type>
+#  </Plugin>
+#
+#  <Host "hostname">
+#    <Type "cpu">
+#      Instance "idle"
+#      FailureMin 10
+#    </Type>
+#
+#    <Plugin "memory">
+#      <Type "memory">
+#        Instance "cached"
+#        WarningMin 100000000
+#      </Type>
+#    </Plugin>
+#
+#    <Type "load">
+#      DataSource "midterm"
+#      FailureMax 4
+#      Hits 3
+#      Hysteresis 3
+#    </Type>
+#  </Host>
+#</Plugin>
index 75f7942..bee566c 100644 (file)
@@ -82,15 +82,19 @@ options are allowed inside a B<LoadPlugin> block:
 If enabled, collectd will export all global symbols of the plugin (and of all
 libraries loaded as dependencies of the plugin) and, thus, makes those symbols
 available for resolving unresolved symbols in subsequently loaded plugins if
-that is supported by your system. By default, this is disabled.
+that is supported by your system.
 
-This is useful (or possibly even required), e.E<nbsp>g., when loading a plugin
-that embeds some scripting language into the daemon (e.E<nbsp>g. the C<perl>
-or C<python> plugins). Scripting languages usually provide means to load
+This is useful (or possibly even required), e.g., when loading a plugin that
+embeds some scripting language into the daemon (e.g. the I<Perl> and
+I<Python plugins>). Scripting languages usually provide means to load
 extensions written in C. Those extensions require symbols provided by the
-interpreter, which is loaded as a dependency of the respective collectd
-plugin. See the documentation of those plugins (e.E<nbsp>g.,
-L<collectd-perl(5)> or L<collectd-python(5)>) for details.
+interpreter, which is loaded as a dependency of the respective collectd plugin.
+See the documentation of those plugins (e.g., L<collectd-perl(5)> or
+L<collectd-python(5)>) for details.
+
+By default, this is disabled. As a special exception, if the plugin name is
+either C<perl> or C<python>, the default is changed to enabled in order to keep
+the average user from ever having to deal with this low level linking stuff.
 
 =back
 
@@ -151,7 +155,7 @@ missing when no update has been received for twice the update interval. Since
 this setting uses iterations, the maximum allowed time without update depends
 on the I<Interval> information contained in each value list. This is used in
 the I<Threshold> configuration to dispatch notifications about missing values,
-see L<"THRESHOLD CONFIGURATION"> below.
+see L<collectd-threshold(5)> for details.
 
 =item B<ReadThreads> I<Num>
 
@@ -169,13 +173,8 @@ hostname will be determined using the L<gethostname(2)> system call.
 
 If B<Hostname> is determined automatically this setting controls whether or not
 the daemon should try to figure out the "fully qualified domain name", FQDN.
-This is done using a lookup of the name returned by C<gethostname>.
-
-Using this feature (i.E<nbsp>e. setting this option to B<true>) is recommended.
-However, to preserve backwards compatibility the default is set to B<false>.
-The sample config file that is installed with C<makeE<nbsp>install> includes a
-line which sets this option, though, so that default installations will have
-this setting enabled.
+This is done using a lookup of the name returned by C<gethostname>. This option
+is enabled by default.
 
 =item B<PreCacheChain> I<ChainName>
 
@@ -200,6 +199,143 @@ A list of all plugins and a short summary for each plugin can be found in the
 F<README> file shipped with the sourcecode and hopefully binary packets as
 well.
 
+=head2 Plugin C<amqp>
+
+The I<AMQMP plugin> can be used to communicate with other instances of
+I<collectd> or third party applications using an AMQP message broker. Values
+are sent to or received from the broker, which handles routing, queueing and
+possibly filtering or messages.
+
+ <Plugin "amqp">
+   # Send values to an AMQP broker
+   <Publish "some_name">
+     Host "localhost"
+     Port "5672"
+     VHost "/"
+     User "guest"
+     Password "guest"
+     Exchange "amq.fanout"
+ #   ExchangeType "fanout"
+ #   RoutingKey "collectd"
+ #   Persistent false
+ #   Format "command"
+ #   StoreRates false
+   </Publish>
+   
+   # Receive values from an AMQP broker
+   <Subscribe "some_name">
+     Host "localhost"
+     Port "5672"
+     VHost "/"
+     User "guest"
+     Password "guest"
+     Exchange "amq.fanout"
+ #   ExchangeType "fanout"
+ #   Queue "queue_name"
+ #   RoutingKey "collectd.#"
+   </Subscribe>
+ </Plugin>
+
+The plugin's configuration consists of a number of I<Publish> and I<Subscribe>
+blocks, which configure sending and receiving of values respectively. The two
+blocks are very similar, so unless otherwise noted, an option can be used in
+either block. The name given in the blocks starting tag is only used for
+reporting messages, but may be used to support I<flushing> of certain
+I<Publish> blocks in the future.
+
+=over 4
+
+=item B<Host> I<Host>
+
+Hostname or IP-address of the AMQP broker. Defaults to the default behavior of
+the underlying communications library, I<rabbitmq-c>, which is "localhost".
+
+=item B<Port> I<Port>
+
+Service name or port number on which the AMQP broker accepts connections. This
+argument must be a string, even if the numeric form is used. Defaults to
+"5672".
+
+=item B<VHost> I<VHost>
+
+Name of the I<virtual host> on the AMQP broker to use. Defaults to "/".
+
+=item B<User> I<User>
+
+=item B<Password> I<Password>
+
+Credentials used to authenticate to the AMQP broker. By default "guest"/"guest"
+is used.
+
+=item B<Exchange> I<Exchange>
+
+In I<Publish> blocks, this option specifies the I<exchange> to send values to.
+By default, "amq.fanout" will be used.
+
+In I<Subscribe> blocks this option is optional. If given, a I<binding> between
+the given exchange and the I<queue> is created, using the I<routing key> if
+configured. See the B<Queue> and B<RoutingKey> options below.
+
+=item B<ExchangeType> I<Type>
+
+If given, the plugin will try to create the configured I<exchange> with this
+I<type> after connecting. When in a I<Subscribe> block, the I<queue> will then
+be bound to this exchange.
+
+=item B<Queue> I<Queue> (Subscribe only)
+
+Configures the I<queue> name to subscribe to. If no queue name was configures
+explicitly, a unique queue name will be created by the broker.
+
+=item B<RoutingKey> I<Key>
+
+In I<Publish> blocks, this configures the routing key to set on all outgoing
+messages. If not given, the routing key will be computed from the I<identifier>
+of the value. The host, plugin, type and the two instances are concatenated
+together using dots as the separator and all containing dots replaced with
+slashes. For example "collectd.host/example/com.cpu.0.cpu.user". This makes it
+possible to receive only specific values using a "topic" exchange.
+
+In I<Subscribe> blocks, configures the I<routing key> used when creating a
+I<binding> between an I<exchange> and the I<queue>. The usual wildcards can be
+used to filter messages when using a "topic" exchange. If you're only
+interested in CPU statistics, you could use the routing key "collectd.*.cpu.#"
+for example.
+
+=item B<Persistent> B<true>|B<false> (Publish only)
+
+Selects the I<delivery method> to use. If set to B<true>, the I<persistent>
+mode will be used, i.e. delivery is guaranteed. If set to B<false> (the
+default), the I<transient> delivery mode will be used, i.e. messages may be
+lost due to high load, overflowing queues or similar issues.
+
+=item B<Format> B<Command>|B<JSON> (Publish only)
+
+Selects the format in which messages are sent to the broker. If set to
+B<Command> (the default), values are sent as C<PUTVAL> commands which are
+identical to the syntax used by the I<Exec> and I<UnixSock plugins>. In this
+case, the C<Content-Type> header field will be set to C<text/collectd>.
+
+If set to B<JSON>, the values are encoded in the I<JavaScript Object Notation>,
+an easy and straight forward exchange format. The C<Content-Type> header field
+will be set to C<application/json>.
+
+A subscribing client I<should> use the C<Content-Type> header field to
+determine how to decode the values. Currently, the I<AMQP plugin> itself can
+only decode the B<Command> format.
+
+=item B<StoreRates> B<true>|B<false> (Publish only)
+
+Determines whether or not C<COUNTER>, C<DERIVE> and C<ABSOLUTE> data sources
+are converted to a I<rate> (i.e. a C<GAUGE> value). If set to B<false> (the
+default), no conversion is performed. Otherwise the conversion is performed
+using the internal value cache.
+
+Please note that currently this option is only used if the B<Format> option has
+been set to B<JSON>.
+
+=back
+
 =head2 Plugin C<apache>
 
 To configure the C<apache>-plugin you first need to configure the Apache
@@ -218,7 +354,25 @@ Since its C<mod_status> module is very similar to Apache's, B<lighttpd> is
 also supported. It introduces a new field, called C<BusyServers>, to count the
 number of currently connected clients. This field is also supported.
 
-The following options are accepted by the C<apache>-plugin:
+The configuration of the I<Apache> plugin consists of one or more
+C<E<lt>InstanceE<nbsp>/E<gt>> blocks. Each block requires one string argument
+as the instance name. For example:
+
+ <Plugin "apache">
+   <Instance "www1">
+     URL "http://www1.example.com/mod_status?auto"
+   </Instance>
+   <Instance "www2">
+     URL "http://www2.example.com/mod_status?auto"
+   </Instance>
+ </Plugin>
+
+The instance name will be used as the I<plugin instance>. To emulate the old
+(versionE<nbsp>4) behavior, you can use an empty string (""). In order for the
+plugin to work correctly, each instance name must be unique. This is not
+enforced by the plugin and it is your responsibility to ensure it.
+
+The following options are accepted within each I<Instance> block:
 
 =over 4
 
@@ -226,7 +380,7 @@ The following options are accepted by the C<apache>-plugin:
 
 Sets the URL of the C<mod_status> output. This needs to be the output generated
 by C<ExtendedStatus on> and it needs to be the machine readable output
-generated by appending the C<?auto> argument.
+generated by appending the C<?auto> argument. This option is I<mandatory>.
 
 =item B<User> I<Username>
 
@@ -595,22 +749,6 @@ runtime statistics module of CouchDB
     </URL>
   </Plugin>
 
-Another CouchDB example:
-The following example will collect the status values from each database:
-
-  <URL "http://localhost:5984/_all_dbs">
-    Instance "dbs"
-    <Key "*/doc_count">
-      Type "gauge"
-    </Key>
-    <Key "*/doc_del_count">
-      Type "counter"
-    </Key>
-    <Key "*/disk_size">
-      Type "bytes"
-    </Key>
-  </URL>
-
 In the B<Plugin> block, there may be one or more B<URL> blocks, each defining
 a URL to be fetched via HTTP (using libcurl) and one or more B<Key> blocks.
 The B<Key> string argument must be in a path format, which is used to collect a
@@ -1040,22 +1178,6 @@ Report using the device name rather than the mountpoint. i.e. with this I<false>
 (the default), it will report a disk as "root", but with it I<true>, it will be
 "sda1" (or whichever).
 
-=item B<ReportReserved> B<true>|B<false>
-
-When enabled, the blocks reserved for root are reported separately. When
-disabled (the default for backwards compatibility reasons) the reserved space
-will be included in the "free" space.
-
-When disabled, the "df" type will be used to store "free" and "used" space. The
-mount point or disk name (see option B<ReportByDevice>) is used as type
-instance in this case (again: backwards compatibility).
-
-When enabled, the type "df_complex" is used and three files are created. The
-mount point or disk name is used as plugin instance and the type instance is
-set to "free", "reserved" and "used" as appropriate.
-
-Enabling this option is recommended.
-
 =item B<ReportInodes> B<true>|B<false>
 
 Enables or disables reporting of free, reserved and used inodes. Defaults to
@@ -1375,13 +1497,6 @@ Hostname to connect to. Defaults to B<127.0.0.1>.
 
 TCP-Port to connect to. Defaults to B<7634>.
 
-=item B<TranslateDevicename> I<true>|I<false>
-
-If enabled, translate the disk names to major/minor device numbers
-(e.E<nbsp>g. "8-0" for /dev/sda). For backwards compatibility this defaults to
-I<true> but it's recommended to disable it as it will probably be removed in
-the next major version.
-
 =back
 
 =head2 Plugin C<interface>
@@ -1609,6 +1724,16 @@ You can also specify combinations of these fields. For example B<name uuid>
 means to concatenate the guest name and UUID (with a literal colon character
 between, thus I<"foo:1234-1234-1234-1234">).
 
+=item B<InterfaceFormat> B<name>|B<address>
+
+When the libvirt plugin logs interface data, it sets the name of the collected
+data according to this setting. The default is to use the path as provided by
+the hypervisor (the "dev" property of the target node), which is equal to
+setting B<name>.
+
+B<address> means use the interface's mac address. This is useful since the
+interface path might change between reboots of a guest or across migrations.
+
 =back
 
 =head2 Plugin C<logfile>
@@ -1627,8 +1752,8 @@ debugging support.
 
 Sets the file to write log messages to. The special strings B<stdout> and
 B<stderr> can be used to write to the standard output and standard error
-channels, respectively. This, of course, only makes much sense when collectd is
-running in foreground- or non-daemon-mode.
+channels, respectively. This, of course, only makes much sense when I<collectd>
+is running in foreground- or non-daemon-mode.
 
 =item B<Timestamp> B<true>|B<false>
 
@@ -1645,6 +1770,33 @@ B<Note>: There is no need to notify the daemon after moving or removing the
 log file (e.E<nbsp>g. when rotating the logs). The plugin reopens the file
 for each line it writes.
 
+=head2 Plugin C<lpar>
+
+The I<LPAR plugin> reads CPU statistics of I<Logical Partitions>, a
+virtualization technique for IBM POWER processors. It takes into account CPU
+time stolen from or donated to a partition, in addition to the usual user,
+system, I/O statistics.
+
+The following configuration options are available:
+
+=over 4
+
+=item B<CpuPoolStats> B<false>|B<true>
+
+When enabled, statistics about the processor pool are read, too. The partition
+needs to have pool authority in order to be able to acquire this information.
+Defaults to false.
+
+=item B<ReportBySerial> B<false>|B<true>
+
+If enabled, the serial of the physical machine the partition is currently
+running on is reported as I<hostname> and the logical hostname of the machine
+is reported in the I<plugin instance>. Otherwise, the logical hostname will be
+used (just like other plugins) and the I<plugin instance> will be empty.
+Defaults to false.
+
+=back
+
 =head2 Plugin C<mbmon>
 
 The C<mbmon plugin> uses mbmon to retrieve temperature, voltage, etc.
@@ -1870,7 +2022,7 @@ B<Collect> option is mandatory.
 The C<mysql plugin> requires B<mysqlclient> to be installed. It connects to
 one or more databases when started and keeps the connection up as long as
 possible. When the connection is interrupted for whatever reason it will try
-to re-connect. The plugin will complaint loudly in case anything goes wrong.
+to re-connect. The plugin will complain loudly in case anything goes wrong.
 
 This plugin issues the MySQL C<SHOW STATUS> / C<SHOW GLOBAL STATUS> command
 and collects information about MySQL network traffic, executed statements,
@@ -2652,7 +2804,18 @@ operating systems.
 =item B<MaxPacketSize> I<1024-65535>
 
 Set the maximum size for datagrams received over the network. Packets larger
-than this will be truncated.
+than this will be truncated. Defaults to 1452E<nbsp>bytes, which is the maximum
+payload size that can be transmitted in one Ethernet frame using IPv6E<nbsp>/
+UDP.
+
+On the server side, this limit should be set to the largest value used on
+I<any> client. Likewise, the value on the client must not be larger than the
+value on the server, or data will be lost.
+
+B<Compatibility:> Versions prior to I<versionE<nbsp>4.8> used a fixed sized
+buffer of 1024E<nbsp>bytes. Versions I<4.8>, I<4.9> and I<4.10> used a default
+value of 1024E<nbsp>bytes to avoid problems when sending data to an older
+server.
 
 =item B<Forward> I<true|false>
 
@@ -2663,16 +2826,6 @@ the same multicast group. While this results in more network traffic than
 necessary it's not a huge problem since the plugin has a duplicate detection,
 so the values will not loop.
 
-=item B<CacheFlush> I<Seconds>
-
-For each host/plugin/type combination the C<network plugin> caches the time of
-the last value being sent or received. Every I<Seconds> seconds the plugin
-searches and removes all entries that are older than I<Seconds> seconds, thus
-freeing the unused memory again. Since this process is somewhat expensive and
-normally doesn't do much, this value should not be too small. The default is
-1800 seconds, but setting this to 86400 seconds (one day) will not do much harm
-either.
-
 =item B<ReportStats> B<true>|B<false>
 
 The network plugin cannot only receive and send statistics, it can also create
@@ -3307,11 +3460,6 @@ allowed as long as a single non-empty command has been specified only.
 
 The returned lines will be handled separately one after another.
 
-=item B<Query> I<sql query statement>
-
-This is a deprecated synonym for B<Statement>. It will be removed in version 5
-of collectd.
-
 =item B<Param> I<hostname>|I<database>|I<username>|I<interval>
 
 Specify the parameters which should be passed to the SQL query. The parameters
@@ -3387,21 +3535,6 @@ This option is required inside a B<Result> block and may be specified multiple
 times. If multiple B<ValuesFrom> options are specified, the columns are read
 in the given order.
 
-=item B<Column> I<type> [I<type instance>]
-
-This is a deprecated alternative to a B<Result> block. It will be removed in
-version 5 of collectd. It is equivalent to the following B<Result> block:
-
-  <Result>
-    Type I<type>
-    InstancePrefix I<type instance>
-    ValuesFrom I<name of the x. column>
-  </Result>
-
-The order of the B<Column> options defines which columns of the query result
-should be used. The first option specifies the data found in the first column,
-the second option that of the second column, and so on.
-
 =item B<MinVersion> I<version>
 
 =item B<MaxVersion> I<version>
@@ -3416,13 +3549,6 @@ The I<version> has to be specified as the concatenation of the major, minor
 and patch-level versions, each represented as two-decimal-digit numbers. For
 example, version 8.2.3 will become 80203.
 
-=item B<MinPGVersion> I<version>
-
-=item B<MaxPGVersion> I<version>
-
-These are deprecated synonyms for B<MinVersion> and B<MaxVersion>
-respectively. They will be removed in version 5 of collectd.
-
 =back
 
 The following predefined queries are available (the definitions can be found
@@ -3833,6 +3959,52 @@ Defaults to B<false>.
 
 =back
 
+=head2 Plugin C<redis>
+
+The I<Redis plugin> connects to one or more Redis servers and gathers
+information about each server's state. For each server there is a I<Node> block
+which configures the connection parameters for this node.
+
+  <Plugin redis>
+    <Node "example">
+        Host "localhost"
+        Port "6379"
+        Timeout 2000
+    </Node>
+  </Plugin>
+
+The information shown in the synopsis above is the I<default configuration>
+which is used by the plugin if no configuration is present.
+
+=over 4
+
+=item B<Node> I<Nodename>
+
+The B<Node> block identifies a new Redis node, that is a new Redis instance
+running in an specified host and port. The name for node is a canonical
+identifier which is used as I<plugin instance>. It is limited to
+64E<nbsp>characters in length.
+
+=item B<Host> I<Hostname>
+
+The B<Host> option is the hostname or IP-address where the Redis instance is
+running on.
+
+=item B<Port> I<Port>
+
+The B<Port> option is the TCP port on which the Redis instance accepts
+connections. Either a service name of a port number may be given. Please note
+that numerical port numbers must be given as a string, too.
+
+=item B<Timeout> I<Timeout in miliseconds>
+
+The B<Timeout> option set the socket timeout for node response. Since the Redis
+read function is blocking, you should keep this value as low as possible. Keep
+in mind that the sum of all B<Timeout> values for all B<Nodes> should be lower
+than B<Interval> defined globally.
+
+=back
+
 =head2 Plugin C<rrdcached>
 
 The C<rrdcached> plugin uses the RRDtool accelerator daemon, L<rrdcached(1)>,
@@ -3996,7 +4168,7 @@ because all values were added to the internal cache at roughly the same time.
 
 =head2 Plugin C<sensors>
 
-The C<sensors plugin> uses B<lm_sensors> to retrieve sensor-values. This means
+The I<Sensors plugin> uses B<lm_sensors> to retrieve sensor-values. This means
 that all the needed modules have to be loaded and lm_sensors has to be
 configured (most likely by editing F</etc/sensors.conf>. Read
 L<sensors.conf(5)> for details.
@@ -4031,6 +4203,25 @@ Since the configuration of the C<snmp plugin> is a little more complicated than
 other plugins, its documentation has been moved to an own manpage,
 L<collectd-snmp(5)>. Please see there for details.
 
+=head2 Plugin C<swap>
+
+The I<Swap plugin> collects information about used and available swap space. On
+I<Solaris>, the following options are available:
+
+=over 4
+
+=item B<ReportByDevice> B<false>|B<true>
+
+Configures how to report physical swap devices. If set to B<false> is used (the
+default), the summary over all swap devices is reported only, i.e. the globally
+used and available space over all devices. If B<true> is configured, the used
+and available space of each device will be reported separately.
+
+This option is only available if the I<Swap plugin> can use the L<swapctl(2)>
+mechanism under I<Solaris>.
+
+=back
+
 =head2 Plugin C<syslog>
 
 =over 4
@@ -4380,7 +4571,7 @@ port in numeric form.
 
 =item B<ForceUseProcfs> I<true>|I<false>
 
-By default, the C<thermal> plugin tries to read the statistics from the Linux
+By default, the I<Thermal plugin> tries to read the statistics from the Linux
 C<sysfs> interface. If that is not available, the plugin falls back to the
 C<procfs> interface. By setting this option to I<true>, you can force the
 plugin to use the latter. This option defaults to I<false>.
@@ -4400,9 +4591,18 @@ selection is configured at all, B<all> devices are selected.
 
 =back
 
+=head2 Plugin C<threshold>
+
+The I<Threshold plugin> checks values collected or received by I<collectd>
+against a configurable I<threshold> and issues I<notifications> if values are
+out of bounds.
+
+Documentation for this plugin is available in the L<collectd-threshold(5)>
+manual page.
+
 =head2 Plugin C<tokyotyrant>
 
-The C<tokyotyrant plugin> connects to a TokyoTyrant server and collects a
+The I<TokyoTyrant plugin> connects to a TokyoTyrant server and collects a
 couple metrics: number of records, and database size on disk.
 
 =over 4
@@ -4439,6 +4639,13 @@ Change the file permissions of the UNIX-socket after it has been created. The
 permissions must be given as a numeric, octal value as you would pass to
 L<chmod(1)>. Defaults to B<0770>.
 
+=item B<DeleteSocket> B<false>|B<true>
+
+If set to B<true>, delete the socket file before calling L<bind(2)>, if a file
+with the given name already exists. If I<collectd> crashes a socket file may be
+left over, preventing the daemon from opening a new socket when restarted.
+Since this is potentially dangerous, this defaults to B<false>.
+
 =back
 
 =head2 Plugin C<uuid>
@@ -4482,6 +4689,68 @@ Take the UUID from the given file (default I</etc/uuid>).
 
 =back
 
+=head2 Plugin C<varnish>
+
+The Varnish plugin collects information about Varnish, an HTTP accelerator.
+
+=over 4
+
+=item B<CollectCache> B<true>|B<false>
+
+Cache hits and misses. True by default.
+
+=item B<CollectConnections> B<true>|B<false>
+
+Number of client connections received, accepted and dropped. True by default.
+
+=item B<CollectBackend> B<true>|B<false>
+
+Back-end connection statistics, such as successful, reused,
+and closed connections. True by default.
+
+=item B<CollectSHM> B<true>|B<false>
+
+Statistics about the shared memory log, a memory region to store
+log messages which is flushed to disk when full. True by default.
+
+=item B<CollectESI> B<true>|B<false>
+
+Edge Side Includes (ESI) parse statistics. False by default.
+
+=item B<CollectFetch> B<true>|B<false>
+
+Statistics about fetches (HTTP requests sent to the backend). False by default.
+
+=item B<CollectHCB> B<true>|B<false>
+
+Inserts and look-ups in the crit bit tree based hash. Look-ups are
+divided into locked and unlocked look-ups. False by default.
+
+=item B<CollectSMA> B<true>|B<false>
+
+malloc or umem (umem_alloc(3MALLOC) based) storage statistics.
+The umem storage component is Solaris specific. False by default.
+
+=item B<CollectSMS> B<true>|B<false>
+
+synth (synthetic content) storage statistics. This storage
+component is used internally only. False by default.
+
+=item B<CollectSM> B<true>|B<false>
+
+file (memory mapped file) storage statistics. False by default.
+
+=item B<CollectTotals> B<true>|B<false>
+
+Collects overview counters, such as the number of sessions created,
+the number of requests and bytes transferred. False by default.
+
+=item B<CollectWorkers> B<true>|B<false>
+
+Collect statistics about worker threads. False by default.
+
+=back
+
 =head2 Plugin C<vmem>
 
 The C<vmem> plugin collects information about the usage of virtual memory.
index e7fc4e3..4079ad1 100644 (file)
 #if HAVE_STDINT_H
 # include <stdint.h>
 #endif
-#if HAVE_STDBOOL_H
-# include <stdbool.h>
-#else
-# ifndef HAVE__BOOL
-#  ifdef __cplusplus
-typedef bool _Bool;
-#  else
-#   define _Bool signed char
-#  endif
-# endif
-# define bool _Bool
-# define false 0
-# define true 1
-# define __bool_true_false_are_defined 1
-#endif
 #if HAVE_UNISTD_H
 # include <unistd.h>
 #endif
@@ -112,6 +97,12 @@ typedef bool _Bool;
 # define assert(...) /* nop */
 #endif
 
+#if !defined(HAVE__BOOL) || !HAVE__BOOL
+typedef int _Bool;
+# undef HAVE__BOOL
+# define HAVE__BOOL 1
+#endif
+
 #if NAN_STATIC_DEFAULT
 # include <math.h>
 /* #endif NAN_STATIC_DEFAULT*/
@@ -294,8 +285,11 @@ typedef bool _Bool;
 # endif
 #endif
 
-extern char hostname_g[];
-extern int  interval_g;
-extern int  timeout_g;
+/* Type for time as used by "utils_time.h" */
+typedef uint64_t cdtime_t;
+
+extern char     hostname_g[];
+extern cdtime_t interval_g;
+extern int      timeout_g;
 
 #endif /* COLLECTD_H */
diff --git a/src/collectdctl.c b/src/collectdctl.c
new file mode 100644 (file)
index 0000000..61b7fc5
--- /dev/null
@@ -0,0 +1,608 @@
+/**
+ * collectd - src/collectdctl.c
+ * Copyright (C) 2010 Håkon J Dugstad Johnsen
+ * Copyright (C) 2010 Sebastian Harl
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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:
+ *   Håkon J Dugstad Johnsen <hakon-dugstad.johnsen at telenor.com>
+ *   Sebastian "tokkee" Harl <sh@tokkee.org>
+ **/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#if NAN_STATIC_DEFAULT
+# include <math.h>
+/* #endif NAN_STATIC_DEFAULT*/
+#elif NAN_STATIC_ISOC
+# ifndef __USE_ISOC99
+#  define DISABLE_ISOC99 1
+#  define __USE_ISOC99 1
+# endif /* !defined(__USE_ISOC99) */
+# include <math.h>
+# if DISABLE_ISOC99
+#  undef DISABLE_ISOC99
+#  undef __USE_ISOC99
+# endif /* DISABLE_ISOC99 */
+/* #endif NAN_STATIC_ISOC */
+#elif NAN_ZERO_ZERO
+# include <math.h>
+# ifdef NAN
+#  undef NAN
+# endif
+# define NAN (0.0 / 0.0)
+# ifndef isnan
+#  define isnan(f) ((f) != (f))
+# endif /* !defined(isnan) */
+# ifndef isfinite
+#  define isfinite(f) (((f) - (f)) == 0.0)
+# endif
+# ifndef isinf
+#  define isinf(f) (!isfinite(f) && !isnan(f))
+# endif
+#endif /* NAN_ZERO_ZERO */
+
+#include "libcollectdclient/client.h"
+
+#define DEFAULT_SOCK LOCALSTATEDIR"/run/"PACKAGE_NAME"-unixsock"
+
+extern char *optarg;
+extern int   optind;
+
+static void exit_usage (const char *name, int status) {
+  fprintf ((status == 0) ? stdout : stderr,
+      "Usage: %s [options] <command> [cmd options]\n\n"
+
+      "Available options:\n"
+      "  -s       Path to collectd's UNIX socket.\n"
+      "           Default: "DEFAULT_SOCK"\n"
+
+      "\n  -h       Display this help and exit.\n"
+
+      "\nAvailable commands:\n\n"
+
+      " * getval <identifier>\n"
+      " * flush [timeout=<seconds>] [plugin=<name>] [identifier=<id>]\n"
+      " * listval\n"
+      " * putval <identifier> [interval=<seconds>] <value-list(s)>\n"
+
+      "\nIdentifiers:\n\n"
+
+      "An identifier has the following format:\n\n"
+
+      "  [<hostname>/]<plugin>[-<plugin_instance>]/<type>[-<type_instance>]\n\n"
+
+      "Hostname defaults to the local hostname if omitted (e.g., uptime/uptime).\n"
+      "No error is returned if the specified identifier does not exist.\n"
+
+      "\n"PACKAGE" "VERSION", http://collectd.org/\n"
+      "by Florian octo Forster <octo@verplant.org>\n"
+      "for contributions see `AUTHORS'\n"
+      , name);
+  exit (status);
+}
+
+/* Count the number of occurrences of the character 'chr'
+ * in the specified string. */
+static int count_chars (const char *str, char chr) {
+  int count = 0;
+
+  while (*str != '\0') {
+    if (*str == chr) {
+      count++;
+    }
+    str++;
+  }
+
+  return count;
+} /* count_chars */
+
+static int array_grow (void **array, int *array_len, size_t elem_size)
+{
+  void *tmp;
+
+  assert ((array != NULL) && (array_len != NULL));
+
+  tmp = realloc (*array, (*array_len + 1) * elem_size);
+  if (tmp == NULL) {
+    fprintf (stderr, "ERROR: Failed to allocate memory.\n");
+    return (-1);
+  }
+
+  *array = tmp;
+  ++(*array_len);
+  return (0);
+} /* array_grow */
+
+static int parse_identifier (lcc_connection_t *c,
+    const char *value, lcc_identifier_t *ident)
+{
+  char hostname[1024];
+  char ident_str[1024] = "";
+  int  n_slashes;
+
+  int status;
+
+  n_slashes = count_chars (value, '/');
+  if (n_slashes == 1) {
+    /* The user has omitted the hostname part of the identifier
+     * (there is only one '/' in the identifier)
+     * Let's add the local hostname */
+    if (gethostname (hostname, sizeof (hostname)) != 0) {
+      fprintf (stderr, "ERROR: Failed to get local hostname: %s",
+          strerror (errno));
+      return (-1);
+    }
+    hostname[sizeof (hostname) - 1] = '\0';
+
+    snprintf (ident_str, sizeof (ident_str), "%s/%s", hostname, value);
+    ident_str[sizeof(ident_str) - 1] = '\0';
+  }
+  else {
+    strncpy (ident_str, value, sizeof (ident_str));
+    ident_str[sizeof (ident_str) - 1] = '\0';
+  }
+
+  status = lcc_string_to_identifier (c, ident, ident_str);
+  if (status != 0) {
+    fprintf (stderr, "ERROR: Failed to parse identifier ``%s'': %s.\n",
+        ident_str, lcc_strerror(c));
+    return (-1);
+  }
+  return (0);
+} /* parse_identifier */
+
+static int getval (lcc_connection_t *c, int argc, char **argv)
+{
+  lcc_identifier_t ident;
+
+  size_t   ret_values_num   = 0;
+  gauge_t *ret_values       = NULL;
+  char   **ret_values_names = NULL;
+
+  int status;
+  size_t i;
+
+  assert (strcasecmp (argv[0], "getval") == 0);
+
+  if (argc != 2) {
+    fprintf (stderr, "ERROR: getval: Missing identifier.\n");
+    return (-1);
+  }
+
+  memset (&ident, 0, sizeof (ident));
+  status = parse_identifier (c, argv[1], &ident);
+  if (status != 0)
+    return (status);
+
+#define BAIL_OUT(s) \
+  do { \
+    if (ret_values != NULL) \
+      free (ret_values); \
+    if (ret_values_names != NULL) { \
+      for (i = 0; i < ret_values_num; ++i) \
+        free (ret_values_names[i]); \
+      free (ret_values_names); \
+    } \
+    ret_values_num = 0; \
+    return (s); \
+  } while (0)
+
+  status = lcc_getval (c, &ident,
+      &ret_values_num, &ret_values, &ret_values_names);
+  if (status != 0) {
+    fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+    BAIL_OUT (-1);
+  }
+
+  for (i = 0; i < ret_values_num; ++i)
+    printf ("%s=%e\n", ret_values_names[i], ret_values[i]);
+  BAIL_OUT (0);
+#undef BAIL_OUT
+} /* getval */
+
+static int flush (lcc_connection_t *c, int argc, char **argv)
+{
+  int timeout = -1;
+
+  lcc_identifier_t *identifiers = NULL;
+  int identifiers_num = 0;
+
+  char **plugins = NULL;
+  int plugins_num = 0;
+
+  int status;
+  int i;
+
+  assert (strcasecmp (argv[0], "flush") == 0);
+
+#define BAIL_OUT(s) \
+  do { \
+    if (identifiers != NULL) \
+      free (identifiers); \
+    identifiers_num = 0; \
+    if (plugins != NULL) \
+      free (plugins); \
+    plugins_num = 0; \
+    return (s); \
+  } while (0)
+
+  for (i = 1; i < argc; ++i) {
+    char *key, *value;
+
+    key   = argv[i];
+    value = strchr (argv[i], (int)'=');
+
+    if (! value) {
+      fprintf (stderr, "ERROR: flush: Invalid option ``%s''.\n", argv[i]);
+      BAIL_OUT (-1);
+    }
+
+    *value = '\0';
+    ++value;
+
+    if (strcasecmp (key, "timeout") == 0) {
+      char *endptr = NULL;
+
+      timeout = (int) strtol (value, &endptr, 0);
+
+      if (endptr == value) {
+        fprintf (stderr, "ERROR: Failed to parse timeout as number: %s.\n",
+            value);
+        BAIL_OUT (-1);
+      }
+      else if ((endptr != NULL) && (*endptr != '\0')) {
+        fprintf (stderr, "WARNING: Ignoring trailing garbage after timeout: "
+            "%s.\n", endptr);
+      }
+    }
+    else if (strcasecmp (key, "plugin") == 0) {
+      status = array_grow ((void *)&plugins, &plugins_num,
+          sizeof (*plugins));
+      if (status != 0)
+        BAIL_OUT (status);
+
+      plugins[plugins_num - 1] = value;
+    }
+    else if (strcasecmp (key, "identifier") == 0) {
+      status = array_grow ((void *)&identifiers, &identifiers_num,
+          sizeof (*identifiers));
+      if (status != 0)
+        BAIL_OUT (status);
+
+      memset (identifiers + (identifiers_num - 1), 0, sizeof (*identifiers));
+      status = parse_identifier (c, value,
+          identifiers + (identifiers_num - 1));
+      if (status != 0)
+        BAIL_OUT (status);
+    }
+    else {
+      fprintf (stderr, "ERROR: flush: Unknown option `%s'.\n", key);
+      BAIL_OUT (-1);
+    }
+  }
+
+  if (plugins_num == 0) {
+    status = array_grow ((void *)&plugins, &plugins_num, sizeof (*plugins));
+    if (status != 0)
+      BAIL_OUT (status);
+
+    assert (plugins_num == 1);
+    plugins[0] = NULL;
+  }
+
+  for (i = 0; i < plugins_num; ++i) {
+    if (identifiers_num == 0) {
+      status = lcc_flush (c, plugins[i], NULL, timeout);
+      if (status != 0)
+        fprintf (stderr, "ERROR: Failed to flush plugin `%s': %s.\n",
+            (plugins[i] == NULL) ? "(all)" : plugins[i], lcc_strerror (c));
+    }
+    else {
+      int j;
+
+      for (j = 0; j < identifiers_num; ++j) {
+        status = lcc_flush (c, plugins[i], identifiers + j, timeout);
+        if (status != 0) {
+          char id[1024];
+
+          lcc_identifier_to_string (c, id, sizeof (id), identifiers + j);
+          fprintf (stderr, "ERROR: Failed to flush plugin `%s', "
+              "identifier `%s': %s.\n",
+              (plugins[i] == NULL) ? "(all)" : plugins[i],
+              id, lcc_strerror (c));
+        }
+      }
+    }
+  }
+
+  BAIL_OUT (0);
+#undef BAIL_OUT
+} /* flush */
+
+static int listval (lcc_connection_t *c, int argc, char **argv)
+{
+  lcc_identifier_t *ret_ident     = NULL;
+  size_t            ret_ident_num = 0;
+
+  int status;
+  size_t i;
+
+  assert (strcasecmp (argv[0], "listval") == 0);
+
+  if (argc != 1) {
+    fprintf (stderr, "ERROR: listval: Does not accept any arguments.\n");
+    return (-1);
+  }
+
+#define BAIL_OUT(s) \
+  do { \
+    if (ret_ident != NULL) \
+      free (ret_ident); \
+    ret_ident_num = 0; \
+    return (s); \
+  } while (0)
+
+  status = lcc_listval (c, &ret_ident, &ret_ident_num);
+  if (status != 0) {
+    fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+    BAIL_OUT (status);
+  }
+
+  for (i = 0; i < ret_ident_num; ++i) {
+    char id[1024];
+
+    status = lcc_identifier_to_string (c, id, sizeof (id), ret_ident + i);
+    if (status != 0) {
+      fprintf (stderr, "ERROR: listval: Failed to convert returned "
+          "identifier to a string: %s\n", lcc_strerror (c));
+      continue;
+    }
+
+    printf ("%s\n", id);
+  }
+  BAIL_OUT (0);
+#undef BAIL_OUT
+} /* listval */
+
+static int putval (lcc_connection_t *c, int argc, char **argv)
+{
+  lcc_value_list_t vl = LCC_VALUE_LIST_INIT;
+
+  /* 64 ought to be enough for anybody ;-) */
+  value_t values[64];
+  int     values_types[64];
+  size_t  values_len = 0;
+
+  int status;
+  int i;
+
+  assert (strcasecmp (argv[0], "putval") == 0);
+
+  if (argc < 3) {
+    fprintf (stderr, "ERROR: putval: Missing identifier "
+        "and/or value list.\n");
+    return (-1);
+  }
+
+  vl.values       = values;
+  vl.values_types = values_types;
+
+  status = parse_identifier (c, argv[1], &vl.identifier);
+  if (status != 0)
+    return (status);
+
+  for (i = 2; i < argc; ++i) {
+    char *tmp;
+
+    tmp = strchr (argv[i], (int)'=');
+
+    if (tmp != NULL) { /* option */
+      char *key   = argv[i];
+      char *value = tmp;
+
+      *value = '\0';
+      ++value;
+
+      if (strcasecmp (key, "interval") == 0) {
+        char *endptr;
+
+        vl.interval = strtol (value, &endptr, 0);
+
+        if (endptr == value) {
+          fprintf (stderr, "ERROR: Failed to parse interval as number: %s.\n",
+              value);
+          return (-1);
+        }
+        else if ((endptr != NULL) && (*endptr != '\0')) {
+          fprintf (stderr, "WARNING: Ignoring trailing garbage after "
+              "interval: %s.\n", endptr);
+        }
+      }
+      else {
+        fprintf (stderr, "ERROR: putval: Unknown option `%s'.\n", key);
+        return (-1);
+      }
+    }
+    else { /* value list */
+      char *value;
+
+      tmp = strchr (argv[i], (int)':');
+
+      if (tmp == NULL) {
+        fprintf (stderr, "ERROR: putval: Invalid value list: %s.\n",
+            argv[i]);
+        return (-1);
+      }
+
+      *tmp = '\0';
+      ++tmp;
+
+      if (strcasecmp (argv[i], "N") == 0) {
+        vl.time = 0;
+      }
+      else {
+        char *endptr;
+
+        vl.time = strtol (argv[i], &endptr, 0);
+
+        if (endptr == argv[i]) {
+          fprintf (stderr, "ERROR: Failed to parse time as number: %s.\n",
+              argv[i]);
+          return (-1);
+        }
+        else if ((endptr != NULL) && (*endptr != '\0')) {
+          fprintf (stderr, "ERROR: Garbage after time: %s.\n", endptr);
+          return (-1);
+        }
+      }
+
+      values_len = 0;
+      value = tmp;
+      while (value != 0) {
+        char *dot, *endptr;
+
+        tmp = strchr (value, (int)':');
+
+        if (tmp != NULL) {
+          *tmp = '\0';
+          ++tmp;
+        }
+
+        /* This is a bit of a hack, but parsing types.db just does not make
+         * much sense imho -- the server might have different types defined
+         * anyway. Also, lcc uses the type information for formatting the
+         * number only, so the real meaning does not matter. -tokkee */
+        dot = strchr (value, (int)'.');
+        endptr = NULL;
+        if (strcasecmp (value, "U") == 0) {
+          values[values_len].gauge = NAN;
+          values_types[values_len] = LCC_TYPE_GAUGE;
+        }
+        else if (dot) { /* floating point value */
+          values[values_len].gauge = strtod (value, &endptr);
+          values_types[values_len] = LCC_TYPE_GAUGE;
+        }
+        else { /* integer */
+          values[values_len].counter = strtol (value, &endptr, 0);
+          values_types[values_len] = LCC_TYPE_COUNTER;
+        }
+        ++values_len;
+
+        if (endptr == value) {
+          fprintf (stderr, "ERROR: Failed to parse value as number: %s.\n",
+              argv[i]);
+          return (-1);
+        }
+        else if ((endptr != NULL) && (*endptr != '\0')) {
+          fprintf (stderr, "ERROR: Garbage after value: %s.\n", endptr);
+          return (-1);
+        }
+
+        value = tmp;
+      }
+
+      assert (values_len >= 1);
+      vl.values_len = values_len;
+
+      status = lcc_putval (c, &vl);
+      if (status != 0) {
+        fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+        return (-1);
+      }
+    }
+  }
+
+  if (values_len == 0) {
+    fprintf (stderr, "ERROR: putval: Missing value list(s).\n");
+    return (-1);
+  }
+  return (0);
+} /* putval */
+
+int main (int argc, char **argv) {
+  char address[1024] = "unix:"DEFAULT_SOCK;
+
+  lcc_connection_t *c;
+
+  int status;
+
+  while (42) {
+    int c;
+
+    c = getopt (argc, argv, "s:h");
+
+    if (c == -1)
+      break;
+
+    switch (c) {
+      case 's':
+        snprintf (address, sizeof (address), "unix:%s", optarg);
+        address[sizeof (address) - 1] = '\0';
+        break;
+      case 'h':
+        exit_usage (argv[0], 0);
+        break;
+      default:
+        exit_usage (argv[0], 1);
+    }
+  }
+
+  if (optind >= argc) {
+    fprintf (stderr, "%s: missing command\n", argv[0]);
+    exit_usage (argv[0], 1);
+  }
+
+  c = NULL;
+  status = lcc_connect (address, &c);
+  if (status != 0) {
+    fprintf (stderr, "ERROR: Failed to connect to daemon at %s: %s.\n",
+        address, strerror (errno));
+    return (1);
+  }
+
+  if (strcasecmp (argv[optind], "getval") == 0)
+    status = getval (c, argc - optind, argv + optind);
+  else if (strcasecmp (argv[optind], "flush") == 0)
+    status = flush (c, argc - optind, argv + optind);
+  else if (strcasecmp (argv[optind], "listval") == 0)
+    status = listval (c, argc - optind, argv + optind);
+  else if (strcasecmp (argv[optind], "putval") == 0)
+    status = putval (c, argc - optind, argv + optind);
+  else {
+    fprintf (stderr, "%s: invalid command: %s\n", argv[0], argv[optind]);
+    return (1);
+  }
+
+  LCC_DESTROY (c);
+
+  if (status != 0)
+    return (status);
+  return (0);
+} /* main */
+
+/* vim: set sw=2 ts=2 tw=78 expandtab : */
+
diff --git a/src/collectdctl.pod b/src/collectdctl.pod
new file mode 100644 (file)
index 0000000..21c0b50
--- /dev/null
@@ -0,0 +1,160 @@
+=head1 NAME
+
+collectdctl - Control interface for collectd
+
+=head1 SYNOPSIS
+
+collectdctl I<[options]> I<E<lt>commandE<gt>> I<[command options]>
+
+=head1 DESCRIPTION
+
+collectdctl provides a control interface for collectd, which may be used to
+interact with the daemon using the C<unixsock plugin>.
+
+=head1 OPTIONS
+
+collectdctl supports the following options:
+
+=over 4
+
+=item B<-s> I<socket>
+
+Path to the UNIX socket opened by collectd's C<unixsock plugin>.
+Default: /var/run/collectd-unixsock
+
+=item B<-h>
+
+Display usage information and exit.
+
+=back
+
+=head1 AVAILABLE COMMANDS
+
+The following commands are supported:
+
+=over 4
+
+=item B<getval> I<E<lt>identifierE<gt>>
+
+Query the latest collected value identified by the specified
+I<E<lt>identifierE<gt>> (see below). The value-list associated with that
+data-set is returned as a list of key-value-pairs, each on its own line. Keys
+and values are separated by the equal sign (C<=>).
+
+=item B<flush> [B<timeout=>I<E<lt>secondsE<gt>>] [B<plugin=>I<E<lt>nameE<gt>>]
+[B<identifier=>I<E<lt>idE<gt>>]
+
+Flush the daemon. This is useful, e.E<nbsp>g., to make sure that the latest
+values have been written to the respective RRD file before graphing them or
+copying them to somewhere else.
+
+The following options are supported by the flush command:
+
+=over 4
+
+=item B<timeout=>I<E<lt>secondsE<gt>>
+
+Flush values older than the specified timeout (in seconds) only.
+
+=item B<plugin=>I<E<lt>nameE<gt>>
+
+Flush the specified plugin only. I.E<nbsp>e., data cached by the specified
+plugin is written to disk (or network or whatever), if the plugin supports
+that operation.
+
+Example: B<rrdtool>.
+
+=item B<identifier=>I<E<lt>idE<gt>>
+
+If this option is present, only the data specified by the specified identifier
+(see below) will be flushed. Note that this option is not supported by all
+plugins (e.E<nbsp>g., the C<network> plugin does not support this).
+
+=back
+
+The B<plugin> and B<identifier> options may be specified more than once. In
+that case, all combinations of specified plugins and identifiers will be
+flushed only.
+
+=item B<listval>
+
+Returns a list of all values (by their identifier) available to the
+C<unixsock> plugin. Each value is printed on its own line. I.E<nbsp>e., this
+command returns a list of valid identifiers that may be used with the other
+commands.
+
+=item B<putval> I<E<lt>identifierE<gt>> [B<interval=>I<E<lt>secondsE<gt>>]
+I<E<lt>value-list(s)E<gt>>
+
+Submit one or more values (identified by I<E<lt>identifierE<gt>>, see below)
+to the daemon which will then dispatch them to the write plugins. B<interval>
+specifies the interval (in seconds) used to collect the values following that
+option. It defaults to the default of the running collectd instance receiving
+the data. Multiple I<E<lt>value-list(s)E<gt>> (see below) may be specified.
+Each of them will be submitted to the daemon. The values have to match the
+data-set definition specified by the type as given in the identifier (see
+L<types.db(5)> for details).
+
+=back
+
+=head1 IDENTIFIERS
+
+An identifier has the following format:
+
+[I<hostname>/]I<plugin>[-I<plugin_instance>]/I<type>[-I<type_instance>]
+
+Examples:
+ somehost/cpu-0/cpu-idle
+ uptime/uptime
+ otherhost/memory/memory-used
+
+Hostname defaults to the local (non-fully qualified) hostname if omitted. No
+error is returned if the specified identifier does not exist (this is a
+limitation in the C<libcollectdclient> library).
+
+=head1 VALUE-LIST
+
+A value list describes one data-set as handled by collectd. It is a colon
+(C<:>) separated list of the time and the values. Each value is either given
+as an integer if the data-type is a counter, or as a double if the data-type
+is a gauge value. A literal C<U> is interpreted as an undefined gauge value.
+The number of values and the data-types have to match the type specified in
+the identifier (see L<types.db(5)> for details). The time is specified as
+epoch (i.E<nbsp>e., standard UNIX time) or as a literal C<N> which will be
+interpreted as now.
+
+=head1 EXAMPLES
+
+=over 4
+
+=item C<collectdctl flush plugin=rrdtool identifier=somehost/cpu-0/cpu-wait>
+
+Flushes all CPU wait RRD values of the first CPU of the local host.
+I.E<nbsp>e., writes all pending RRD updates of that data-source to disk.
+
+=item C<for ident in `collectdctl listval | grep users/users`; do
+      collectdctl getval $ident;
+  done>
+
+Query the latest number of logged in users on all hosts known to the local
+collectd instance.
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>,
+L<collectd.conf(5)>,
+L<collectd-unixsock(5)>,
+L<types.db(5)>
+
+=head1 AUTHOR
+
+collectd has been written by Florian Forster E<lt>octo at verplant.orgE<gt>
+and many contributors (see `AUTHORS').
+
+collectdctl has been written by
+Håkon J Dugstad Johnsen E<lt>hakon-dugstad.johnsenE<nbsp>atE<nbsp>telenor.comE<gt>
+and Sebastian Harl E<lt>sh at tokkee.orgE<gt>.
+
+=cut
index 35e006a..0bd9f68 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/common.c
- * Copyright (C) 2005-2009  Florian octo Forster
+ * Copyright (C) 2005-2010  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Niki W. Waibel <niki.waibel@gmx.net>
  *   Sebastian Harl <sh at tokkee.org>
  *   Michał Mirosław <mirq-linux at rere.qmqm.pl>
@@ -29,6 +29,7 @@
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
+#include "utils_cache.h"
 
 #if HAVE_PTHREAD_H
 # include <pthread.h>
 # include <math.h>
 #endif
 
-/* for ntohl and htonl */
-#if HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
-
 /* for getaddrinfo */
 #include <sys/types.h>
 #include <sys/socket.h>
 # include <netinet/in.h>
 #endif
 
+/* for ntohl and htonl */
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
 #ifdef HAVE_LIBKSTAT
 extern kstat_ctl_t *kc;
 #endif
@@ -802,6 +803,75 @@ int format_name (char *ret, int ret_len,
        return (0);
 } /* int format_name */
 
+int format_values (char *ret, size_t ret_len, /* {{{ */
+               const data_set_t *ds, const value_list_t *vl,
+               _Bool store_rates)
+{
+        size_t offset = 0;
+        int status;
+        int i;
+        gauge_t *rates = NULL;
+
+        assert (0 == strcmp (ds->type, vl->type));
+
+        memset (ret, 0, ret_len);
+
+#define BUFFER_ADD(...) do { \
+        status = ssnprintf (ret + offset, ret_len - offset, \
+                        __VA_ARGS__); \
+        if (status < 1) \
+        { \
+                sfree (rates); \
+                return (-1); \
+        } \
+        else if (((size_t) status) >= (ret_len - offset)) \
+        { \
+                sfree (rates); \
+                return (-1); \
+        } \
+        else \
+                offset += ((size_t) status); \
+} while (0)
+
+        BUFFER_ADD ("%.3f", CDTIME_T_TO_DOUBLE (vl->time));
+
+        for (i = 0; i < ds->ds_num; i++)
+        {
+                if (ds->ds[i].type == DS_TYPE_GAUGE)
+                        BUFFER_ADD (":%f", vl->values[i].gauge);
+                else if (store_rates)
+                {
+                        if (rates == NULL)
+                                rates = uc_get_rate (ds, vl);
+                        if (rates == NULL)
+                        {
+                                WARNING ("format_values: "
+                                               "uc_get_rate failed.");
+                                return (-1);
+                        }
+                        BUFFER_ADD (":%g", rates[i]);
+                }
+                else if (ds->ds[i].type == DS_TYPE_COUNTER)
+                        BUFFER_ADD (":%llu", vl->values[i].counter);
+                else if (ds->ds[i].type == DS_TYPE_DERIVE)
+                        BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
+                else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+                        BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
+                else
+                {
+                        ERROR ("format_values plugin: Unknown data source type: %i",
+                                        ds->ds[i].type);
+                        sfree (rates);
+                        return (-1);
+                }
+        } /* for ds->ds_num */
+
+#undef BUFFER_ADD
+
+        sfree (rates);
+        return (0);
+} /* }}} int format_values */
+
 int parse_identifier (char *str, char **ret_host,
                char **ret_plugin, char **ret_plugin_instance,
                char **ret_type, char **ret_type_instance)
@@ -848,6 +918,40 @@ int parse_identifier (char *str, char **ret_host,
        return (0);
 } /* int parse_identifier */
 
+int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
+{
+       char str_copy[6 * DATA_MAX_NAME_LEN];
+       char *host = NULL;
+       char *plugin = NULL;
+       char *plugin_instance = NULL;
+       char *type = NULL;
+       char *type_instance = NULL;
+       int status;
+
+       if ((str == NULL) || (vl == NULL))
+               return (EINVAL);
+
+       sstrncpy (str_copy, str, sizeof (str_copy));
+
+       status = parse_identifier (str_copy, &host,
+                       &plugin, &plugin_instance,
+                       &type, &type_instance);
+       if (status != 0)
+               return (status);
+
+       sstrncpy (vl->host, host, sizeof (vl->host));
+       sstrncpy (vl->plugin, plugin, sizeof (vl->plugin));
+       sstrncpy (vl->plugin_instance,
+                       (plugin_instance != NULL) ? plugin_instance : "",
+                       sizeof (vl->plugin_instance));
+       sstrncpy (vl->type, type, sizeof (vl->type));
+       sstrncpy (vl->type_instance,
+                       (type_instance != NULL) ? type_instance : "",
+                       sizeof (vl->type_instance));
+
+       return (0);
+} /* }}} int parse_identifier_vl */
+
 int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
 {
   char *value;
@@ -931,9 +1035,22 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
                if (i == -1)
                {
                        if (strcmp ("N", ptr) == 0)
-                               vl->time = time (NULL);
+                               vl->time = cdtime ();
                        else
-                               vl->time = (time_t) atoi (ptr);
+                       {
+                               char *endptr = NULL;
+                               double tmp;
+
+                               errno = 0;
+                               tmp = strtod (ptr, &endptr);
+                               if ((errno != 0)                    /* Overflow */
+                                               || (endptr == ptr)  /* Invalid string */
+                                               || (endptr == NULL) /* This should not happen */
+                                               || (*endptr != 0))  /* Trailing chars */
+                                       return (-1);
+
+                               vl->time = DOUBLE_TO_CDTIME_T (tmp);
+                       }
                }
                else
                {
index c292abf..6b11b53 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/common.h
- * Copyright (C) 2005-2009  Florian octo Forster
+ * Copyright (C) 2005-2010  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Niki W. Waibel <niki.waibel@gmx.net>
 **/
 
@@ -258,10 +258,14 @@ int format_name (char *ret, int ret_len,
 #define FORMAT_VL(ret, ret_len, vl) \
        format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
                        (vl)->type, (vl)->type_instance)
+int format_values (char *ret, size_t ret_len,
+               const data_set_t *ds, const value_list_t *vl,
+               _Bool store_rates);
 
 int parse_identifier (char *str, char **ret_host,
                char **ret_plugin, char **ret_plugin_instance,
                char **ret_type, char **ret_type_instance);
+int parse_identifier_vl (const char *str, value_list_t *vl);
 int parse_value (const char *value, value_t *ret_value, int ds_type);
 int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds);
 
@@ -274,10 +278,10 @@ int notification_init (notification_t *n, int severity, const char *message,
                const char *host,
                const char *plugin, const char *plugin_instance,
                const char *type, const char *type_instance);
-#define NOTIFICATION_INIT_VL(n, vl, ds) \
+#define NOTIFICATION_INIT_VL(n, vl) \
        notification_init (n, NOTIF_FAILURE, NULL, \
                        (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
-                       (ds)->type, (vl)->type_instance)
+                       (vl)->type, (vl)->type_instance)
 
 typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
                void *user_data);
index 0b7786f..7c8347b 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/configfile.c
- * Copyright (C) 2005-2009  Florian octo Forster
+ * Copyright (C) 2005-2011  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
@@ -17,7 +17,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Sebastian tokkee Harl <sh at tokkee.org>
  **/
 
@@ -29,7 +29,6 @@
 #include "plugin.h"
 #include "configfile.h"
 #include "types_list.h"
-#include "utils_threshold.h"
 #include "filter_chain.h"
 
 #if HAVE_WORDEXP_H
@@ -96,7 +95,7 @@ static cf_global_option_t cf_global_options[] =
        {"BaseDir",     NULL, PKGLOCALSTATEDIR},
        {"PIDFile",     NULL, PIDFILE},
        {"Hostname",    NULL, NULL},
-       {"FQDNLookup",  NULL, "false"},
+       {"FQDNLookup",  NULL, "true"},
        {"Interval",    NULL, "10"},
        {"ReadThreads", NULL, "5"},
        {"Timeout",     NULL, "2"},
@@ -243,7 +242,8 @@ static int dispatch_value_plugindir (const oconfig_item_t *ci)
 static int dispatch_loadplugin (const oconfig_item_t *ci)
 {
        int i;
-       uint32_t flags = 0;
+       const char *name;
+       unsigned int flags = 0;
        assert (strcasecmp (ci->key, "LoadPlugin") == 0);
 
        if (ci->values_num != 1)
@@ -251,19 +251,34 @@ static int dispatch_loadplugin (const oconfig_item_t *ci)
        if (ci->values[0].type != OCONFIG_TYPE_STRING)
                return (-1);
 
+       name = ci->values[0].value.string;
+
+       /*
+        * XXX: Magic at work:
+        *
+        * Some of the language bindings, for example the Python and Perl
+        * plugins, need to be able to export symbols to the scripts they run.
+        * For this to happen, the "Globals" flag needs to be set.
+        * Unfortunately, this technical detail is hard to explain to the
+        * average user and she shouldn't have to worry about this, ideally.
+        * So in order to save everyone's sanity use a different default for a
+        * handful of special plugins. --octo
+        */
+       if ((strcasecmp ("Perl", name) == 0)
+                       || (strcasecmp ("Python", name) == 0))
+               flags |= PLUGIN_FLAGS_GLOBAL;
+
        for (i = 0; i < ci->children_num; ++i) {
-               if (ci->children[i].values_num != 1 ||
-                               ci->children[i].values[0].type != OCONFIG_TYPE_BOOLEAN) {
-                       WARNING("Ignoring unknown LoadPlugin option %s for plugin %s", ci->children[i].key, ci->values[0].value.string);
-                       continue;
-               }
-               if (strcasecmp(ci->children[i].key, "globals") == 0) {
-                       flags |= PLUGIN_FLAGS_GLOBAL;
-               } else {
-                       WARNING("Ignoring unknown LoadPlugin option %s for plugin %s", ci->children[i].key, ci->values[0].value.string);
+               if (strcasecmp("Globals", ci->children[i].key) == 0)
+                       cf_util_get_flag (ci->children + i, &flags, PLUGIN_FLAGS_GLOBAL);
+               else {
+                       WARNING("Ignoring unknown LoadPlugin option \"%s\" "
+                                       "for plugin \"%s\"",
+                                       ci->children[i].key, ci->values[0].value.string);
                }
        }
-       return (plugin_load (ci->values[0].value.string, flags));
+
+       return (plugin_load (name, (uint32_t) flags));
 } /* int dispatch_value_loadplugin */
 
 static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci)
@@ -372,8 +387,6 @@ static int dispatch_block (oconfig_item_t *ci)
                return (dispatch_loadplugin (ci));
        else if (strcasecmp (ci->key, "Plugin") == 0)
                return (dispatch_block_plugin (ci));
-       else if (strcasecmp (ci->key, "Threshold") == 0)
-               return (ut_config (ci));
        else if (strcasecmp (ci->key, "Chain") == 0)
                return (fc_configure (ci));
 
@@ -1014,22 +1027,94 @@ int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
                return (-1);
        }
 
-       *ret_bool = ci->values[0].value.boolean ? true : false;
+       *ret_bool = ci->values[0].value.boolean ? 1 : 0;
 
        return (0);
 } /* }}} int cf_util_get_boolean */
 
-/* Assures that the config option is a string. The string is then converted to
- * a port number using `service_name_to_port_number' and returned. Returns the
- * port number in the range [1-65535] or less than zero upon failure. */
+int cf_util_get_flag (const oconfig_item_t *ci, /* {{{ */
+               unsigned int *ret_value, unsigned int flag)
+{
+       int status;
+       _Bool b;
+
+       if (ret_value == NULL)
+               return (EINVAL);
+
+       b = 0;
+       status = cf_util_get_boolean (ci, &b);
+       if (status != 0)
+               return (status);
+
+       if (b)
+       {
+               *ret_value |= flag;
+       }
+       else
+       {
+               *ret_value &= ~flag;
+       }
+
+       return (0);
+} /* }}} int cf_util_get_flag */
+
+/* Assures that the config option is a string or a number if the correct range
+ * of 1-65535. The string is then converted to a port number using
+ * `service_name_to_port_number' and returned.
+ * Returns the port number in the range [1-65535] or less than zero upon
+ * failure. */
 int cf_util_get_port_number (const oconfig_item_t *ci) /* {{{ */
 {
-       if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+       int tmp;
+
+       if ((ci->values_num != 1)
+                       || ((ci->values[0].type != OCONFIG_TYPE_STRING)
+                               && (ci->values[0].type != OCONFIG_TYPE_NUMBER)))
        {
-               ERROR ("cf_util_get_port_number: The %s option requires "
+               ERROR ("cf_util_get_port_number: The \"%s\" option requires "
                                "exactly one string argument.", ci->key);
                return (-1);
        }
 
-       return (service_name_to_port_number (ci->values[0].value.string));
+       if (ci->values[0].type == OCONFIG_TYPE_STRING)
+               return (service_name_to_port_number (ci->values[0].value.string));
+
+       assert (ci->values[0].type == OCONFIG_TYPE_NUMBER);
+       tmp = (int) (ci->values[0].value.number + 0.5);
+       if ((tmp < 1) || (tmp > 65535))
+       {
+               ERROR ("cf_util_get_port_number: The \"%s\" option requires "
+                               "a service name or a port number. The number "
+                               "you specified, %i, is not in the valid "
+                               "range of 1-65535.",
+                               ci->key, tmp);
+               return (-1);
+       }
+
+       return (tmp);
 } /* }}} int cf_util_get_port_number */
+
+int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value) /* {{{ */
+{
+       if ((ci == NULL) || (ret_value == NULL))
+               return (EINVAL);
+
+       if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+       {
+               ERROR ("cf_util_get_cdtime: The %s option requires "
+                               "exactly one numeric argument.", ci->key);
+               return (-1);
+       }
+
+       if (ci->values[0].value.number < 0.0)
+       {
+               ERROR ("cf_util_get_cdtime: The numeric argument of the %s "
+                               "option must not be negative.", ci->key);
+               return (-1);
+       }
+
+       *ret_value = DOUBLE_TO_CDTIME_T (ci->values[0].value.number);
+
+       return (0);
+} /* }}} int cf_util_get_cdtime */
+
index 432e09f..e63a0ea 100644 (file)
@@ -2,7 +2,7 @@
 #define CONFIGFILE_H
 /**
  * collectd - src/configfile.h
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2011  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
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
+#include "utils_time.h"
 #include "liboconfig/oconfig.h"
 
 /*
@@ -103,9 +104,18 @@ int cf_util_get_int (const oconfig_item_t *ci, int *ret_value);
  * Otherwise, `ret_bool' is not changed and non-zero is returned. */
 int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool);
 
-/* Assures that the config option is a string. The string is then converted to
- * a port number using `service_name_to_port_number' and returned. Returns the
- * port number in the range [1-65535] or less than zero upon failure. */
+/* Assures the config option is a boolean and set or unset the given flag in
+ * `ret_value' as appropriate. Returns non-zero on error. */
+int cf_util_get_flag (const oconfig_item_t *ci,
+               unsigned int *ret_value, unsigned int flag);
+
+/* Assures that the config option is a string or a number if the correct range
+ * of 1-65535. The string is then converted to a port number using
+ * `service_name_to_port_number' and returned.
+ * Returns the port number in the range [1-65535] or less than zero upon
+ * failure. */
 int cf_util_get_port_number (const oconfig_item_t *ci);
 
+int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value);
+
 #endif /* defined(CONFIGFILE_H) */
index 06055ca..c207318 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/contextswitch.c
  * Copyright (C) 2009  Patrik Weiskircher
+ * Copyright (C) 2010  Kimo Rosenbaum
  *
  * 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
  *
  * Authors:
  *   Patrik Weiskircher <weiskircher at inqnet.at>
+ *   Kimo Rosenbaum <http://github.com/kimor79>
  **/
 
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
 
-#if !KERNEL_LINUX
+#ifdef HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+#endif
+
+#if HAVE_SYSCTLBYNAME
+/* no global variables */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif KERNEL_LINUX
+/* no global variables */
+/* #endif KERNEL_LINUX */
+
+#else
 # error "No applicable input method."
 #endif
 
@@ -45,6 +59,25 @@ static void cs_submit (derive_t context_switches)
 
 static int cs_read (void)
 {
+#if HAVE_SYSCTLBYNAME
+       int value = 0;
+       size_t value_len = sizeof (value);
+       int status;
+
+       status = sysctlbyname ("vm.stats.sys.v_swtch",
+                       &value, &value_len,
+                       /* new pointer = */ NULL, /* new length = */ 0);
+       if (status != 0)
+       {
+               ERROR("contextswitch plugin: sysctlbyname "
+                               "(vm.stats.sys.v_swtch) failed");
+               return (-1);
+       }
+
+       cs_submit (value);
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif KERNEL_LINUX
        FILE *fh;
        char buffer[64];
        int numfields;
@@ -88,6 +121,7 @@ static int cs_read (void)
 
        if (status == -2)
                ERROR ("contextswitch plugin: Unable to find context switch value.");
+#endif /* KERNEL_LINUX */
 
        return status;
 }
index 7aa6361..12071a2 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -1,6 +1,6 @@
 /**
  * collectd - src/cpu.c
- * Copyright (C) 2005-2009  Florian octo Forster
+ * Copyright (C) 2005-2010  Florian octo Forster
  * Copyright (C) 2008       Oleg King
  * Copyright (C) 2009       Simon Kuhnle
  * Copyright (C) 2009       Manuel Sanmartin
@@ -163,7 +163,7 @@ static int init (void)
        DEBUG ("host_processors returned %i %s", (int) cpu_list_len, cpu_list_len == 1 ? "processor" : "processors");
        INFO ("cpu plugin: Found %i processor%s.", (int) cpu_list_len, cpu_list_len == 1 ? "" : "s");
 
-       cpu_temp_retry_max = 86400 / interval_g;
+       cpu_temp_retry_max = 86400 / CDTIME_T_TO_TIME_T (interval_g);
 /* #endif PROCESSOR_CPU_LOAD_INFO */
 
 #elif defined(HAVE_LIBKSTAT)
@@ -241,12 +241,12 @@ static int init (void)
        return (0);
 } /* int init */
 
-static void submit (int cpu_num, const char *type_instance, counter_t value)
+static void submit (int cpu_num, const char *type_instance, derive_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = value;
+       values[0].derive = value;
 
        vl.values = values;
        vl.values_len = 1;
@@ -298,10 +298,10 @@ static int cpu_read (void)
                        continue;
                }
 
-               submit (cpu, "user", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
-               submit (cpu, "nice", (counter_t) cpu_info.cpu_ticks[CPU_STATE_NICE]);
-               submit (cpu, "system", (counter_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM]);
-               submit (cpu, "idle", (counter_t) cpu_info.cpu_ticks[CPU_STATE_IDLE]);
+               submit (cpu, "user", (derive_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
+               submit (cpu, "nice", (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE]);
+               submit (cpu, "system", (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM]);
+               submit (cpu, "idle", (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE]);
 #endif /* PROCESSOR_CPU_LOAD_INFO */
 #if PROCESSOR_TEMPERATURE
                /*
@@ -352,8 +352,8 @@ static int cpu_read (void)
 
 #elif defined(KERNEL_LINUX)
        int cpu;
-       counter_t user, nice, syst, idle;
-       counter_t wait, intr, sitr; /* sitr == soft interrupt */
+       derive_t user, nice, syst, idle;
+       derive_t wait, intr, sitr; /* sitr == soft interrupt */
        FILE *fh;
        char buf[1024];
 
@@ -410,7 +410,7 @@ static int cpu_read (void)
 
 #elif defined(HAVE_LIBKSTAT)
        int cpu;
-       counter_t user, syst, idle, wait;
+       derive_t user, syst, idle, wait;
        static cpu_stat_t cs;
 
        if (kc == NULL)
@@ -421,10 +421,10 @@ static int cpu_read (void)
                if (kstat_read (kc, ksp[cpu], &cs) == -1)
                        continue; /* error message? */
 
-               idle = (counter_t) cs.cpu_sysinfo.cpu[CPU_IDLE];
-               user = (counter_t) cs.cpu_sysinfo.cpu[CPU_USER];
-               syst = (counter_t) cs.cpu_sysinfo.cpu[CPU_KERNEL];
-               wait = (counter_t) cs.cpu_sysinfo.cpu[CPU_WAIT];
+               idle = (derive_t) cs.cpu_sysinfo.cpu[CPU_IDLE];
+               user = (derive_t) cs.cpu_sysinfo.cpu[CPU_USER];
+               syst = (derive_t) cs.cpu_sysinfo.cpu[CPU_KERNEL];
+               wait = (derive_t) cs.cpu_sysinfo.cpu[CPU_WAIT];
 
                submit (ksp[cpu]->ks_instance, "user", user);
                submit (ksp[cpu]->ks_instance, "system", syst);
@@ -551,12 +551,12 @@ static int cpu_read (void)
                return (-1);
        }
 
-       submit (0, "idle",   (counter_t) cs->idle);
-       submit (0, "nice",   (counter_t) cs->nice);
-       submit (0, "swap",   (counter_t) cs->swap);
-       submit (0, "system", (counter_t) cs->kernel);
-       submit (0, "user",   (counter_t) cs->user);
-       submit (0, "wait",   (counter_t) cs->iowait);
+       submit (0, "idle",   (derive_t) cs->idle);
+       submit (0, "nice",   (derive_t) cs->nice);
+       submit (0, "swap",   (derive_t) cs->swap);
+       submit (0, "system", (derive_t) cs->kernel);
+       submit (0, "user",   (derive_t) cs->user);
+       submit (0, "wait",   (derive_t) cs->iowait);
 /* #endif HAVE_LIBSTATGRAB */
 
 #elif defined(HAVE_PERFSTAT)
@@ -591,10 +591,10 @@ static int cpu_read (void)
 
        for (i = 0; i < cpus; i++) 
        {
-               submit (i, "idle",   (counter_t) perfcpu[i].idle);
-               submit (i, "system", (counter_t) perfcpu[i].sys);
-               submit (i, "user",   (counter_t) perfcpu[i].user);
-               submit (i, "wait",   (counter_t) perfcpu[i].wait);
+               submit (i, "idle",   (derive_t) perfcpu[i].idle);
+               submit (i, "system", (derive_t) perfcpu[i].sys);
+               submit (i, "user",   (derive_t) perfcpu[i].user);
+               submit (i, "wait",   (derive_t) perfcpu[i].wait);
        }
 #endif /* HAVE_PERFSTAT */
 
index 46e2301..4b8aa72 100644 (file)
@@ -188,7 +188,7 @@ typedef struct {
        PluginData data;
        PyObject *values;    /* Sequence */
        PyObject *meta;      /* dict */
-       int interval;
+       double interval;
 } Values;
 PyTypeObject ValuesType;
 #define Values_New() PyObject_CallFunctionObjArgs((PyObject *) &ValuesType, (void *) 0)
index f149edc..02d62c1 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
@@ -53,7 +53,8 @@ static int value_list_to_string (char *buffer, int buffer_len,
 
        memset (buffer, '\0', buffer_len);
 
-       status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+       status = ssnprintf (buffer, buffer_len, "%.3f",
+                       CDTIME_T_TO_DOUBLE (vl->time));
        if ((status < 1) || (status >= buffer_len))
                return (-1);
        offset = status;
@@ -298,8 +299,10 @@ static int csv_write (const data_set_t *ds, const value_list_t *vl,
                }
 
                fprintf (use_stdio == 1 ? stdout : stderr,
-                        "PUTVAL %s interval=%i %s\n",
-                        filename, vl->interval, values);
+                        "PUTVAL %s interval=%.3f %s\n",
+                        filename,
+                        CDTIME_T_TO_DOUBLE (vl->interval),
+                        values);
                return (0);
        }
 
index 31cda39..2160b98 100644 (file)
@@ -578,7 +578,6 @@ static void cc_submit (const web_page_t *wp, const web_match_t *wm, /* {{{ */
 
   vl.values = values;
   vl.values_len = 1;
-  vl.time = time (NULL);
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
@@ -597,7 +596,6 @@ static void cc_submit_response_time (const web_page_t *wp, double seconds) /* {{
 
   vl.values = values;
   vl.values_len = 1;
-  vl.time = time (NULL);
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
index 968fc93..cc8b4ad 100644 (file)
@@ -40,7 +40,7 @@
 
 #define CJ_DEFAULT_HOST "localhost"
 #define CJ_KEY_MAGIC 0x43484b59UL /* CHKY */
-#define CJ_IS_KEY(key) (key)->magic == CJ_KEY_MAGIC
+#define CJ_IS_KEY(key) ((key)->magic == CJ_KEY_MAGIC)
 #define CJ_ANY "*"
 #define COUCH_MIN(x,y) ((x) < (y) ? (x) : (y))
 
@@ -64,8 +64,8 @@ struct cj_s /* {{{ */
   char *user;
   char *pass;
   char *credentials;
-  int   verify_peer;
-  int   verify_host;
+  _Bool verify_peer;
+  _Bool verify_host;
   char *cacert;
 
   CURL *curl;
@@ -111,7 +111,7 @@ static size_t cj_curl_callback (void *buf, /* {{{ */
   if (db == NULL)
     return (0);
 
-  status = yajl_parse(db->yajl, (unsigned char *)buf, len);
+  status = yajl_parse(db->yajl, (unsigned char *) buf, len);
   if (status == yajl_status_ok)
   {
 #if HAVE_YAJL_V2
@@ -129,7 +129,8 @@ static size_t cj_curl_callback (void *buf, /* {{{ */
   if (status != yajl_status_ok)
   {
     unsigned char *msg =
-      yajl_get_error(db->yajl, 1, (unsigned char *)buf, len);
+      yajl_get_error(db->yajl, /* verbose = */ 1,
+          /* jsonText = */ (unsigned char *) buf, (unsigned int) len);
     ERROR ("curl_json plugin: yajl_parse failed: %s", msg);
     yajl_free_error(db->yajl, msg);
     return (0); /* abort write callback */
@@ -184,41 +185,21 @@ static int cj_cb_number (void *ctx,
 
   cj_t *db = (cj_t *)ctx;
   cj_key_t *key = db->state[db->depth].key;
-  char *endptr;
   value_t vt;
   int type;
+  int status;
 
-  if (key == NULL)
+  if ((key == NULL) || !CJ_IS_KEY (key))
     return (CJ_CB_CONTINUE);
 
   memcpy (buffer, number, number_len);
   buffer[sizeof (buffer) - 1] = 0;
 
   type = cj_get_type (key);
-  if (type < 0)
-    return (CJ_CB_CONTINUE);
-
-  endptr = NULL;
-  errno = 0;
-
-  if (type == DS_TYPE_COUNTER)
-    vt.counter = (counter_t) strtoull (buffer, &endptr, /* base = */ 0);
-  else if (type == DS_TYPE_GAUGE)
-    vt.gauge = (gauge_t) strtod (buffer, &endptr);
-  else if (type == DS_TYPE_DERIVE)
-    vt.derive = (derive_t) strtoll (buffer, &endptr, /* base = */ 0);
-  else if (type == DS_TYPE_ABSOLUTE)
-    vt.absolute = (absolute_t) strtoull (buffer, &endptr, /* base = */ 0);
-  else
-  {
-    ERROR ("curl_json plugin: Unknown data source type: \"%s\"", key->type);
-    return (CJ_CB_ABORT);
-  }
-
-  if ((endptr == &buffer[0]) || (errno != 0))
+  status = parse_value (buffer, &vt, type);
+  if (status != 0)
   {
-    NOTICE ("curl_json plugin: Overflow while parsing number. "
-        "Ignoring this value.");
+    NOTICE ("curl_json plugin: Unable to parse number: \"%s\"", buffer);
     return (CJ_CB_CONTINUE);
   }
 
@@ -258,34 +239,26 @@ static int cj_cb_string (void *ctx, const unsigned char *val,
     yajl_len_t len)
 {
   cj_t *db = (cj_t *)ctx;
-  c_avl_tree_t *tree;
-  char *ptr;
-
-  if (db->depth != 1) /* e.g. _all_dbs */
-    return (CJ_CB_CONTINUE);
+  char str[len + 1];
 
-  cj_cb_map_key (ctx, val, len); /* same logic */
+  /* Create a null-terminated version of the string. */
+  memcpy (str, val, len);
+  str[len] = 0;
 
-  tree = db->state[db->depth].tree;
+  /* No configuration for this string -> simply return. */
+  if (db->state[db->depth].key == NULL)
+    return (CJ_CB_CONTINUE);
 
-  if ((tree != NULL) && (ptr = rindex (db->url, '/')))
+  if (!CJ_IS_KEY (db->state[db->depth].key))
   {
-    char url[PATH_MAX];
-    CURL *curl;
-
-    /* url =~ s,[^/]+$,$name, */
-    len = (ptr - db->url) + 1;
-    ptr = url;
-    sstrncpy (ptr, db->url, sizeof (url));
-    sstrncpy (ptr + len, db->state[db->depth].name, sizeof (url) - len);
-
-    curl = curl_easy_duphandle (db->curl);
-    curl_easy_setopt (curl, CURLOPT_URL, url);
-    cj_curl_perform (db, curl);
-    curl_easy_cleanup (curl);
+    NOTICE ("curl_json plugin: Found string \"%s\", but the configuration "
+        "expects a map here.", str);
+    return (CJ_CB_CONTINUE);
   }
-  return (CJ_CB_CONTINUE);
-}
+
+  /* Handle the string as if it was a number. */
+  return (cj_cb_number (ctx, (const char *) val, len));
+} /* int cj_cb_string */
 
 static int cj_cb_start (void *ctx)
 {
@@ -407,37 +380,6 @@ static void cj_free (void *arg) /* {{{ */
 
 /* Configuration handling functions {{{ */
 
-static int cj_config_add_string (const char *name, char **dest, /* {{{ */
-                                      oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("curl_json plugin: `%s' needs exactly one string argument.", name);
-    return (-1);
-  }
-
-  sfree (*dest);
-  *dest = strdup (ci->values[0].value.string);
-  if (*dest == NULL)
-    return (-1);
-
-  return (0);
-} /* }}} int cj_config_add_string */
-
-static int cj_config_set_boolean (const char *name, int *dest, /* {{{ */
-                                       oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
-  {
-    WARNING ("curl_json plugin: `%s' needs exactly one boolean argument.", name);
-    return (-1);
-  }
-
-  *dest = ci->values[0].value.boolean ? 1 : 0;
-
-  return (0);
-} /* }}} int cj_config_set_boolean */
-
 static c_avl_tree_t *cj_avl_create(void)
 {
   return c_avl_create ((int (*) (const void *, const void *)) strcmp);
@@ -469,7 +411,7 @@ static int cj_config_add_key (cj_t *db, /* {{{ */
 
   if (strcasecmp ("Key", ci->key) == 0)
   {
-    status = cj_config_add_string ("Key", &key->path, ci);
+    status = cf_util_get_string (ci, &key->path);
     if (status != 0)
     {
       sfree (key);
@@ -489,9 +431,9 @@ static int cj_config_add_key (cj_t *db, /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp ("Type", child->key) == 0)
-      status = cj_config_add_string ("Type", &key->type, child);
+      status = cf_util_get_string (child, &key->type);
     else if (strcasecmp ("Instance", child->key) == 0)
-      status = cj_config_add_string ("Instance", &key->instance, child);
+      status = cf_util_get_string (child, &key->instance);
     else
     {
       WARNING ("curl_json plugin: Option `%s' not allowed here.", child->key);
@@ -607,9 +549,9 @@ static int cj_init_curl (cj_t *db) /* {{{ */
     curl_easy_setopt (db->curl, CURLOPT_USERPWD, db->credentials);
   }
 
-  curl_easy_setopt (db->curl, CURLOPT_SSL_VERIFYPEER, db->verify_peer);
+  curl_easy_setopt (db->curl, CURLOPT_SSL_VERIFYPEER, (int) db->verify_peer);
   curl_easy_setopt (db->curl, CURLOPT_SSL_VERIFYHOST,
-                    db->verify_host ? 2 : 0);
+                    (int) (db->verify_host ? 2 : 0));
   if (db->cacert != NULL)
     curl_easy_setopt (db->curl, CURLOPT_CAINFO, db->cacert);
 
@@ -640,7 +582,7 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
 
   if (strcasecmp ("URL", ci->key) == 0)
   {
-    status = cj_config_add_string ("URL", &db->url, ci);
+    status = cf_util_get_string (ci, &db->url);
     if (status != 0)
     {
       sfree (db);
@@ -660,19 +602,19 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp ("Instance", child->key) == 0)
-      status = cj_config_add_string ("Instance", &db->instance, child);
+      status = cf_util_get_string (child, &db->instance);
     else if (strcasecmp ("Host", child->key) == 0)
-      status = cj_config_add_string ("Host", &db->host, child);
+      status = cf_util_get_string (child, &db->host);
     else if (strcasecmp ("User", child->key) == 0)
-      status = cj_config_add_string ("User", &db->user, child);
+      status = cf_util_get_string (child, &db->user);
     else if (strcasecmp ("Password", child->key) == 0)
-      status = cj_config_add_string ("Password", &db->pass, child);
+      status = cf_util_get_string (child, &db->pass);
     else if (strcasecmp ("VerifyPeer", child->key) == 0)
-      status = cj_config_set_boolean ("VerifyPeer", &db->verify_peer, child);
+      status = cf_util_get_boolean (child, &db->verify_peer);
     else if (strcasecmp ("VerifyHost", child->key) == 0)
-      status = cj_config_set_boolean ("VerifyHost", &db->verify_host, child);
+      status = cf_util_get_boolean (child, &db->verify_host);
     else if (strcasecmp ("CACert", child->key) == 0)
-      status = cj_config_add_string ("CACert", &db->cacert, child);
+      status = cf_util_get_string (child, &db->cacert);
     else if (strcasecmp ("Key", child->key) == 0)
       status = cj_config_add_key (db, child);
     else
@@ -824,29 +766,52 @@ static int cj_curl_perform (cj_t *db, CURL *curl) /* {{{ */
     return (-1);
   }
 
-  status = curl_easy_perform (curl);
+  url = NULL;
+  curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
 
-  yajl_free (db->yajl);
-  db->yajl = yprev;
+  status = curl_easy_perform (curl);
+  if (status != 0)
+  {
+    ERROR ("curl_json plugin: curl_easy_perform failed with status %i: %s (%s)",
+           status, db->curl_errbuf, (url != NULL) ? url : "<null>");
+    yajl_free (db->yajl);
+    db->yajl = yprev;
+    return (-1);
+  }
 
-  curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
   curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc);
 
   /* The response code is zero if a non-HTTP transport was used. */
   if ((rc != 0) && (rc != 200))
   {
-    ERROR ("curl_json plugin: curl_easy_perform failed with response code %ld (%s)",
-           rc, url);
+    ERROR ("curl_json plugin: curl_easy_perform failed with "
+        "response code %ld (%s)", rc, url);
+    yajl_free (db->yajl);
+    db->yajl = yprev;
     return (-1);
   }
 
-  if (status != 0)
+#if HAVE_YAJL_V2
+    status = yajl_complete_parse(db->yajl);
+#else
+    status = yajl_parse_complete(db->yajl);
+#endif
+  if (status != yajl_status_ok)
   {
-    ERROR ("curl_json plugin: curl_easy_perform failed with status %i: %s (%s)",
-           status, db->curl_errbuf, url);
+    unsigned char *errmsg;
+
+    errmsg = yajl_get_error (db->yajl, /* verbose = */ 0,
+        /* jsonText = */ NULL, /* jsonTextLen = */ 0);
+    ERROR ("curl_json plugin: yajl_parse_complete failed: %s",
+        (char *) errmsg);
+    yajl_free_error (db->yajl, errmsg);
+    yajl_free (db->yajl);
+    db->yajl = yprev;
     return (-1);
   }
 
+  yajl_free (db->yajl);
+  db->yajl = yprev;
   return (0);
 } /* }}} int cj_curl_perform */
 
index 77f393f..caa41ef 100644 (file)
--- a/src/dbi.c
+++ b/src/dbi.c
@@ -400,7 +400,7 @@ static int cdbi_config (oconfig_item_t *ci) /* {{{ */
     oconfig_item_t *child = ci->children + i;
     if (strcasecmp ("Query", child->key) == 0)
       udb_query_create (&queries, &queries_num, child,
-          /* callback = */ NULL, /* legacy mode = */ 0);
+          /* callback = */ NULL);
     else if (strcasecmp ("Database", child->key) == 0)
       cdbi_config_add_database (child);
     else
@@ -566,7 +566,7 @@ static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */
 
   udb_query_prepare_result (q, prep_area, hostname_g,
       /* plugin = */ "dbi", db->name,
-      column_names, column_num, /* interval = */ -1);
+      column_names, column_num, /* interval = */ 0);
 
   /* 0 = error; 1 = success; */
   status = dbi_result_first_row (res); /* {{{ */
index dc7be1e..ded374b 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -62,9 +62,8 @@ static ignorelist_t *il_device = NULL;
 static ignorelist_t *il_mountpoint = NULL;
 static ignorelist_t *il_fstype = NULL;
 
-static _Bool by_device = false;
-static _Bool report_reserved = false;
-static _Bool report_inodes = false;
+static _Bool by_device = 0;
+static _Bool report_inodes = 0;
 
 static int df_init (void)
 {
@@ -119,25 +118,16 @@ static int df_config (const char *key, const char *value)
        else if (strcasecmp (key, "ReportByDevice") == 0)
        {
                if (IS_TRUE (value))
-                       by_device = true;
-
-               return (0);
-       }
-       else if (strcasecmp (key, "ReportReserved") == 0)
-       {
-               if (IS_TRUE (value))
-                       report_reserved = true;
-               else
-                       report_reserved = false;
+                       by_device = 1;
 
                return (0);
        }
        else if (strcasecmp (key, "ReportInodes") == 0)
        {
                if (IS_TRUE (value))
-                       report_inodes = true;
+                       report_inodes = 1;
                else
-                       report_inodes = false;
+                       report_inodes = 0;
 
                return (0);
        }
@@ -146,28 +136,6 @@ static int df_config (const char *key, const char *value)
        return (-1);
 }
 
-static void df_submit_two (char *df_name,
-               const char *type,
-               gauge_t df_used,
-               gauge_t df_free)
-{
-       value_t values[2];
-       value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].gauge = df_used;
-       values[1].gauge = df_free;
-
-       vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-       sstrncpy (vl.plugin, "df", sizeof (vl.plugin));
-       sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       sstrncpy (vl.type, type, sizeof (vl.type));
-       sstrncpy (vl.type_instance, df_name, sizeof (vl.type_instance));
-
-       plugin_dispatch_values (&vl);
-} /* void df_submit_two */
-
 __attribute__ ((nonnull(2)))
 static void df_submit_one (char *plugin_instance,
                const char *type, const char *type_instance,
@@ -215,6 +183,9 @@ static int df_read (void)
        {
                unsigned long long blocksize;
                char disk_name[256];
+               uint64_t blk_free;
+               uint64_t blk_reserved;
+               uint64_t blk_used;
 
                if (ignorelist_match (il_device,
                                        (mnt_ptr->spec_device != NULL)
@@ -276,56 +247,39 @@ static int df_read (void)
 
                blocksize = BLOCKSIZE(statbuf);
 
-               if (report_reserved)
-               {
-                       uint64_t blk_free;
-                       uint64_t blk_reserved;
-                       uint64_t blk_used;
-
-                       /*
-                        * Sanity-check for the values in the struct
-                        */
-                       /* Check for negative "available" byes. For example UFS can
-                        * report negative free space for user. Notice. blk_reserved
-                        * will start to diminish after this. */
+               /*
+                * Sanity-check for the values in the struct
+                */
+               /* Check for negative "available" byes. For example UFS can
+                * report negative free space for user. Notice. blk_reserved
+                * will start to diminish after this. */
 #if HAVE_STATVFS
-                       /* Cast and temporary variable are needed to avoid
-                        * compiler warnings.
-                        * ((struct statvfs).f_bavail is unsigned (POSIX)) */
-                       int64_t signed_bavail = (int64_t) statbuf.f_bavail;
-                       if (signed_bavail < 0)
-                               statbuf.f_bavail = 0;
+               /* Cast and temporary variable are needed to avoid
+                * compiler warnings.
+                * ((struct statvfs).f_bavail is unsigned (POSIX)) */
+               int64_t signed_bavail = (int64_t) statbuf.f_bavail;
+               if (signed_bavail < 0)
+                       statbuf.f_bavail = 0;
 #elif HAVE_STATFS
-                       if (statbuf.f_bavail < 0)
-                               statbuf.f_bavail = 0;
+               if (statbuf.f_bavail < 0)
+                       statbuf.f_bavail = 0;
 #endif
-                       /* Make sure that f_blocks >= f_bfree >= f_bavail */
-                       if (statbuf.f_bfree < statbuf.f_bavail)
-                               statbuf.f_bfree = statbuf.f_bavail;
-                       if (statbuf.f_blocks < statbuf.f_bfree)
-                               statbuf.f_blocks = statbuf.f_bfree;
-
-                       blk_free = (uint64_t) statbuf.f_bavail;
-                       blk_reserved = (uint64_t) (statbuf.f_bfree - statbuf.f_bavail);
-                       blk_used = (uint64_t) (statbuf.f_blocks - statbuf.f_bfree);
-                       
-                       df_submit_one (disk_name, "df_complex", "free",
-                                       (gauge_t) (blk_free * blocksize));
-                       df_submit_one (disk_name, "df_complex", "reserved",
-                                       (gauge_t) (blk_reserved * blocksize));
-                       df_submit_one (disk_name, "df_complex", "used",
-                                       (gauge_t) (blk_used * blocksize));
-               }
-               else /* compatibility code */
-               {
-                       gauge_t df_free;
-                       gauge_t df_used;
-
-                       df_free = statbuf.f_bfree * blocksize;
-                       df_used = (statbuf.f_blocks - statbuf.f_bfree) * blocksize;
-
-                       df_submit_two (disk_name, "df", df_used, df_free);
-               }
+               /* Make sure that f_blocks >= f_bfree >= f_bavail */
+               if (statbuf.f_bfree < statbuf.f_bavail)
+                       statbuf.f_bfree = statbuf.f_bavail;
+               if (statbuf.f_blocks < statbuf.f_bfree)
+                       statbuf.f_blocks = statbuf.f_bfree;
+
+               blk_free     = (uint64_t) statbuf.f_bavail;
+               blk_reserved = (uint64_t) (statbuf.f_bfree - statbuf.f_bavail);
+               blk_used     = (uint64_t) (statbuf.f_blocks - statbuf.f_bfree);
+
+               df_submit_one (disk_name, "df_complex", "free",
+                               (gauge_t) (blk_free * blocksize));
+               df_submit_one (disk_name, "df_complex", "reserved",
+                               (gauge_t) (blk_reserved * blocksize));
+               df_submit_one (disk_name, "df_complex", "used",
+                               (gauge_t) (blk_used * blocksize));
 
                /* inode handling */
                if (report_inodes)
index 4a78f1b..7411c22 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/disk.c
- * Copyright (C) 2005-2008  Florian octo Forster
+ * Copyright (C) 2005-2010  Florian octo Forster
  * Copyright (C) 2009       Manuel Sanmartin
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -85,19 +85,19 @@ typedef struct diskstats
        /* This overflows in roughly 1361 years */
        unsigned int poll_count;
 
-       counter_t read_sectors;
-       counter_t write_sectors;
+       derive_t read_sectors;
+       derive_t write_sectors;
 
-       counter_t read_bytes;
-       counter_t write_bytes;
+       derive_t read_bytes;
+       derive_t write_bytes;
 
-       counter_t read_ops;
-       counter_t write_ops;
-       counter_t read_time;
-       counter_t write_time;
+       derive_t read_ops;
+       derive_t write_ops;
+       derive_t read_time;
+       derive_t write_time;
 
-       counter_t avg_read_time;
-       counter_t avg_write_time;
+       derive_t avg_read_time;
+       derive_t avg_write_time;
 
        struct diskstats *next;
 } diskstats_t;
@@ -212,7 +212,7 @@ static int disk_init (void)
 
 static void disk_submit (const char *plugin_instance,
                const char *type,
-               counter_t read, counter_t write)
+               derive_t read, derive_t write)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
@@ -221,8 +221,8 @@ static void disk_submit (const char *plugin_instance,
        if (ignorelist_match (ignorelist, plugin_instance) != 0)
          return;
 
-       values[0].counter = read;
-       values[1].counter = write;
+       values[0].derive = read;
+       values[1].derive = write;
 
        vl.values = values;
        vl.values_len = 2;
@@ -239,7 +239,7 @@ static void disk_submit (const char *plugin_instance,
 static counter_t disk_calc_time_incr (counter_t delta_time, counter_t delta_ops)
 {
        double avg_time = ((double) delta_time) / ((double) delta_ops);
-       double avg_time_incr = ((double) interval_g) * avg_time;
+       double avg_time_incr = CDTIME_T_TO_DOUBLE (interval_g) * avg_time;
 
        return ((counter_t) (avg_time_incr + .5));
 }
@@ -438,15 +438,15 @@ static int disk_read (void)
 
        int minor = 0;
 
-       counter_t read_sectors  = 0;
-       counter_t write_sectors = 0;
+       derive_t read_sectors  = 0;
+       derive_t write_sectors = 0;
 
-       counter_t read_ops      = 0;
-       counter_t read_merged   = 0;
-       counter_t read_time     = 0;
-       counter_t write_ops     = 0;
-       counter_t write_merged  = 0;
-       counter_t write_time    = 0;
+       derive_t read_ops      = 0;
+       derive_t read_merged   = 0;
+       derive_t read_time     = 0;
+       derive_t write_ops     = 0;
+       derive_t write_merged  = 0;
+       derive_t write_time    = 0;
        int is_disk = 0;
 
        diskstats_t *ds, *pre_ds;
@@ -531,8 +531,8 @@ static int disk_read (void)
                }
 
                {
-                       counter_t diff_read_sectors;
-                       counter_t diff_write_sectors;
+                       derive_t diff_read_sectors;
+                       derive_t diff_write_sectors;
 
                /* If the counter wraps around, it's only 32 bits.. */
                        if (read_sectors < ds->read_sectors)
@@ -555,18 +555,18 @@ static int disk_read (void)
                /* Calculate the average time an io-op needs to complete */
                if (is_disk)
                {
-                       counter_t diff_read_ops;
-                       counter_t diff_write_ops;
-                       counter_t diff_read_time;
-                       counter_t diff_write_time;
+                       derive_t diff_read_ops;
+                       derive_t diff_write_ops;
+                       derive_t diff_read_time;
+                       derive_t diff_write_time;
 
                        if (read_ops < ds->read_ops)
                                diff_read_ops = 1 + read_ops
                                        + (UINT_MAX - ds->read_ops);
                        else
                                diff_read_ops = read_ops - ds->read_ops;
-                       DEBUG ("disk plugin: disk_name = %s; read_ops = %llu; "
-                                       "ds->read_ops = %llu; diff_read_ops = %llu;",
+                       DEBUG ("disk plugin: disk_name = %s; read_ops = %"PRIi64"; "
+                                       "ds->read_ops = %"PRIi64"; diff_read_ops = %"PRIi64";",
                                        disk_name,
                                        read_ops, ds->read_ops, diff_read_ops);
 
@@ -706,12 +706,12 @@ static int disk_read (void)
 /* #endif defined(HAVE_LIBSTATGRAB) */
 
 #elif defined(HAVE_PERFSTAT)
-       counter_t read_sectors;
-       counter_t write_sectors;
-       counter_t read_time;
-       counter_t write_time;
-       counter_t read_ops;
-       counter_t write_ops;
+       derive_t read_sectors;
+       derive_t write_sectors;
+       derive_t read_time;
+       derive_t write_time;
+       derive_t read_ops;
+       derive_t write_ops;
        perfstat_id_t firstpath;
        int rnumdisk;
        int i;
index 364b958..95797f5 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -33,9 +33,7 @@
 #include <poll.h>
 
 #include <pcap.h>
-#if HAVE_PCAP_BPF_H
-# include <pcap-bpf.h>
-#endif
+#include <pcap-bpf.h>
 
 /*
  * Private data types
@@ -63,8 +61,8 @@ static int select_numeric_qtype = 1;
 #define PCAP_SNAPLEN 1460
 static char   *pcap_device = NULL;
 
-static counter_t       tr_queries;
-static counter_t       tr_responses;
+static derive_t       tr_queries;
+static derive_t       tr_responses;
 static counter_list_t *qtype_list;
 static counter_list_t *opcode_list;
 static counter_list_t *rcode_list;
@@ -84,14 +82,10 @@ static counter_list_t *counter_list_search (counter_list_t **list, unsigned int
 {
        counter_list_t *entry;
 
-       DEBUG ("counter_list_search (list = %p, key = %u)",
-                       (void *) *list, key);
-
        for (entry = *list; entry != NULL; entry = entry->next)
                if (entry->key == key)
                        break;
 
-       DEBUG ("return (%p)", (void *) entry);
        return (entry);
 }
 
@@ -100,9 +94,6 @@ static counter_list_t *counter_list_create (counter_list_t **list,
 {
        counter_list_t *entry;
 
-       DEBUG ("counter_list_create (list = %p, key = %u, value = %u)",
-                       (void *) *list, key, value);
-
        entry = (counter_list_t *) malloc (sizeof (counter_list_t));
        if (entry == NULL)
                return (NULL);
@@ -126,7 +117,6 @@ static counter_list_t *counter_list_create (counter_list_t **list,
                last->next = entry;
        }
 
-       DEBUG ("return (%p)", (void *) entry);
        return (entry);
 }
 
@@ -135,9 +125,6 @@ static void counter_list_add (counter_list_t **list,
 {
        counter_list_t *entry;
 
-       DEBUG ("counter_list_add (list = %p, key = %u, increment = %u)",
-                       (void *) *list, key, increment);
-
        entry = counter_list_search (list, key);
 
        if (entry != NULL)
@@ -148,7 +135,6 @@ static void counter_list_add (counter_list_t **list,
        {
                counter_list_create (list, key, increment);
        }
-       DEBUG ("return ()");
 }
 
 static int dns_config (const char *key, const char *value)
@@ -242,7 +228,7 @@ static void *dns_child_loop (__attribute__((unused)) void *dummy)
        pcap_obj = pcap_open_live ((pcap_device != NULL) ? pcap_device : "any",
                        PCAP_SNAPLEN,
                        0 /* Not promiscuous */,
-                       interval_g,
+                       (int) CDTIME_T_TO_MS (interval_g / 2),
                        pcap_error);
        if (pcap_obj == NULL)
        {
@@ -265,7 +251,7 @@ static void *dns_child_loop (__attribute__((unused)) void *dummy)
                return (NULL);
        }
 
-       DEBUG ("PCAP object created.");
+       DEBUG ("dns plugin: PCAP object created.");
 
        dnstop_set_pcap_obj (pcap_obj);
        dnstop_set_callback (dns_child_callback);
@@ -278,7 +264,7 @@ static void *dns_child_loop (__attribute__((unused)) void *dummy)
                ERROR ("dns plugin: Listener thread is exiting "
                                "abnormally: %s", pcap_geterr (pcap_obj));
 
-       DEBUG ("child is exiting");
+       DEBUG ("dns plugin: Child is exiting.");
 
        pcap_close (pcap_obj);
        listen_thread_init = 0;
@@ -315,13 +301,13 @@ static int dns_init (void)
        return (0);
 } /* int dns_init */
 
-static void submit_counter (const char *type, const char *type_instance,
-               counter_t value)
+static void submit_derive (const char *type, const char *type_instance,
+               derive_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = value;
+       values[0].derive = value;
 
        vl.values = values;
        vl.values_len = 1;
@@ -331,15 +317,15 @@ static void submit_counter (const char *type, const char *type_instance,
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
        plugin_dispatch_values (&vl);
-} /* void submit_counter */
+} /* void submit_derive */
 
-static void submit_octets (counter_t queries, counter_t responses)
+static void submit_octets (derive_t queries, derive_t responses)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = queries;
-       values[1].counter = responses;
+       values[0].derive = queries;
+       values[1].derive = responses;
 
        vl.values = values;
        vl.values_len = 2;
@@ -348,7 +334,7 @@ static void submit_octets (counter_t queries, counter_t responses)
        sstrncpy (vl.type, "dns_octets", sizeof (vl.type));
 
        plugin_dispatch_values (&vl);
-} /* void submit_counter */
+} /* void submit_octets */
 
 static int dns_read (void)
 {
@@ -379,8 +365,8 @@ static int dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DEBUG ("qtype = %u; counter = %u;", keys[i], values[i]);
-               submit_counter ("dns_qtype", qtype_str (keys[i]), values[i]);
+               DEBUG ("dns plugin: qtype = %u; counter = %u;", keys[i], values[i]);
+               submit_derive ("dns_qtype", qtype_str (keys[i]), values[i]);
        }
 
        pthread_mutex_lock (&opcode_mutex);
@@ -395,8 +381,8 @@ static int dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DEBUG ("opcode = %u; counter = %u;", keys[i], values[i]);
-               submit_counter ("dns_opcode", opcode_str (keys[i]), values[i]);
+               DEBUG ("dns plugin: opcode = %u; counter = %u;", keys[i], values[i]);
+               submit_derive ("dns_opcode", opcode_str (keys[i]), values[i]);
        }
 
        pthread_mutex_lock (&rcode_mutex);
@@ -411,8 +397,8 @@ static int dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DEBUG ("rcode = %u; counter = %u;", keys[i], values[i]);
-               submit_counter ("dns_rcode", rcode_str (keys[i]), values[i]);
+               DEBUG ("dns plugin: rcode = %u; counter = %u;", keys[i], values[i]);
+               submit_derive ("dns_rcode", rcode_str (keys[i]), values[i]);
        }
 
        return (0);
index 8fc5509..5870ab1 100644 (file)
@@ -376,6 +376,7 @@ static void *collect (void *arg)
        } /* while (1) */
 
        pthread_exit ((void *)0);
+       return ((void *) 0);
 } /* static void *collect (void *) */
 
 static void *open_connection (void __attribute__((unused)) *arg)
@@ -548,7 +549,9 @@ static void *open_connection (void __attribute__((unused)) *arg)
 
                pthread_cond_signal (&conn_available);
        }
-       pthread_exit ((void *)0);
+
+       pthread_exit ((void *) 0);
+       return ((void *) 0);
 } /* static void *open_connection (void *) */
 
 static int email_init (void)
index 5274797..0e807c7 100644 (file)
@@ -270,13 +270,14 @@ static void set_environment (void) /* {{{ */
   char buffer[1024];
 
 #ifdef HAVE_SETENV
-  ssnprintf (buffer, sizeof (buffer), "%i", interval_g);
+  ssnprintf (buffer, sizeof (buffer), "%.3f", CDTIME_T_TO_DOUBLE (interval_g));
   setenv ("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1);
 
   ssnprintf (buffer, sizeof (buffer), "%s", hostname_g);
   setenv ("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1);
 #else
-  ssnprintf (buffer, sizeof (buffer), "COLLECTD_INTERVAL=%i", interval_g);
+  ssnprintf (buffer, sizeof (buffer), "COLLECTD_INTERVAL=%.3f",
+      CDTIME_T_TO_DOUBLE (interval_g));
   putenv (buffer);
 
   ssnprintf (buffer, sizeof (buffer), "COLLECTD_HOSTNAME=%s", hostname_g);
@@ -537,12 +538,9 @@ static int parse_line (char *buffer) /* {{{ */
     return (handle_putnotif (stdout, buffer));
   else
   {
-    /* For backwards compatibility */
-    char tmp[1220];
-    /* Let's annoy the user a bit.. */
-    INFO ("exec plugin: Prepending `PUTVAL' to this line: %s", buffer);
-    ssnprintf (tmp, sizeof (tmp), "PUTVAL %s", buffer);
-    return (handle_putval (stdout, tmp));
+    ERROR ("exec plugin: Unable to parse command, ignoring line: \"%s\"",
+       buffer);
+    return (-1);
   }
 } /* int parse_line }}} */
 
@@ -744,8 +742,8 @@ static void *exec_notification_one (void *arg) /* {{{ */
 
   fprintf (fh,
       "Severity: %s\n"
-      "Time: %u\n",
-      severity, (unsigned int) n->time);
+      "Time: %.3f\n",
+      severity, CDTIME_T_TO_DOUBLE (n->time));
 
   /* Print the optional fields */
   if (strlen (n->host) > 0)
index dc0eb11..8fbd271 100644 (file)
@@ -107,16 +107,13 @@ Ops pend=N  Number of times async ops added to pending queues
 63 events to collect in 13 groups
 */
 static void fscache_submit (const char *section, const char *name,
-        counter_t counter_value)
+        value_t value)
 {
-    value_t values[1];
     value_list_t vl = VALUE_LIST_INIT;
 
-    vl.values = values;
+    vl.values = &value;
     vl.values_len = 1;
 
-    vl.values[0].counter = counter_value;
-
     sstrncpy(vl.host, hostname_g, sizeof (vl.host));
     sstrncpy(vl.plugin, "fscache", sizeof (vl.plugin));
     sstrncpy(vl.plugin_instance, section, sizeof (vl.plugin_instance));
@@ -189,8 +186,8 @@ static void fscache_read_stats_file (FILE *fh)
         {
             char *field_name;
             char *field_value_str;
-            char *endptr;
-            counter_t field_value_cnt;
+            value_t field_value_cnt;
+            int status;
 
             field_name = fields[i];
             assert (field_name != NULL);
@@ -201,11 +198,9 @@ static void fscache_read_stats_file (FILE *fh)
             *field_value_str = 0;
             field_value_str++;
 
-            errno = 0;
-            endptr = NULL;
-            field_value_cnt = (counter_t) strtoull (field_value_str,
-                    &endptr, /* base = */ 10);
-            if ((errno != 0) || (endptr == field_value_str))
+            status = parse_value (field_value_str, &field_value_cnt,
+                    DS_TYPE_DERIVE);
+            if (status != 0)
                 continue;
 
             fscache_submit (section, field_name, field_value_cnt);
index 2ffc42a..3c746c4 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/gmond.c
- * Copyright (C) 2009  Florian octo Forster
+ * Copyright (C) 2009,2010  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
@@ -545,6 +545,8 @@ static int staging_entry_update (const char *host, const char *name, /* {{{ */
     se->vl.values[ds_index].derive += value.derive;
   else if (ds_type == DS_TYPE_ABSOLUTE)
     se->vl.values[ds_index].absolute = value.absolute;
+  else
+    assert (23 == 42);
 
   se->flags |= (0x01 << ds_index);
 
@@ -593,32 +595,24 @@ static int mc_handle_value_msg (Ganglia_value_msg *msg) /* {{{ */
     case gmetric_string:
     {
       Ganglia_gmetric_string msg_string;
-      char *endptr;
+      int status;
 
       msg_string = msg->Ganglia_value_msg_u.gstr;
 
       host = msg_string.metric_id.host;
       name = msg_string.metric_id.name;
 
-      endptr = NULL;
-      errno = 0;
-      value_counter.counter = (counter_t) strtoull (msg_string.str,
-          &endptr, /* base = */ 0);
-      if ((endptr == msg_string.str) || (errno != 0))
-        value_counter.counter = -1;
-
-      endptr = NULL;
-      errno = 0;
-      value_gauge.gauge = (gauge_t) strtod (msg_string.str, &endptr);
-      if ((endptr == msg_string.str) || (errno != 0))
+      status = parse_value (msg_string.str, &value_derive, DS_TYPE_DERIVE);
+      if (status != 0)
+        value_derive.derive = -1;
+
+      status = parse_value (msg_string.str, &value_gauge, DS_TYPE_GAUGE);
+      if (status != 0)
         value_gauge.gauge = NAN;
 
-      endptr = NULL;
-      errno = 0;
-      value_derive.derive = (derive_t) strtoll (msg_string.str,
-          &endptr, /* base = */ 0);
-      if ((endptr == msg_string.str) || (errno != 0))
-        value_derive.derive = 0;
+      status = parse_value (msg_string.str, &value_counter, DS_TYPE_COUNTER);
+      if (status != 0)
+        value_counter.counter = 0;
 
       break;
     }
@@ -663,11 +657,15 @@ static int mc_handle_value_msg (Ganglia_value_msg *msg) /* {{{ */
   {
     value_t val_copy;
 
-    val_copy = value_counter;
+    if ((map->ds_type == DS_TYPE_COUNTER)
+        || (map->ds_type == DS_TYPE_ABSOLUTE))
+      val_copy = value_counter;
     if (map->ds_type == DS_TYPE_GAUGE)
       val_copy = value_gauge;
     else if (map->ds_type == DS_TYPE_DERIVE)
       val_copy = value_derive;
+    else
+      assert (23 == 42);
 
     return (staging_entry_update (host, name,
           map->type, map->type_instance,
@@ -719,7 +717,7 @@ static int mc_handle_metadata_msg (Ganglia_metadata_msg *msg) /* {{{ */
           map->type, map->type_instance,
           ds->ds_num);
       if (se != NULL)
-        se->vl.interval = (int) msg_meta.metric.tmax;
+        se->vl.interval = TIME_T_TO_CDTIME_T (msg_meta.metric.tmax);
       pthread_mutex_unlock (&staging_lock);
 
       if (se == NULL)
index 4e08375..4428b75 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * collectd - src/hddtemp.c
  * Copyright (C) 2005,2006  Vincent Stehlé
- * Copyright (C) 2006,2007  Florian octo Forster
+ * Copyright (C) 2006-2010  Florian octo Forster
  * Copyright (C) 2008       Sebastian Harl
  *
  * This program is free software; you can redistribute it and/or modify it
 static const char *config_keys[] =
 {
        "Host",
-       "Port",
-       "TranslateDevicename"
+       "Port"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
-typedef struct hddname
-{
-       int major;
-       int minor;
-       char *name;
-       struct hddname *next;
-} hddname_t;
-
-static hddname_t *first_hddname = NULL;
 static char *hddtemp_host = NULL;
 static char hddtemp_port[16];
-static int translate_devicename = 1;
 
 /*
  * NAME
@@ -231,13 +220,6 @@ static int hddtemp_config (const char *key, const char *value)
                else
                        sstrncpy (hddtemp_port, value, sizeof (hddtemp_port));
        }
-       else if (strcasecmp (key, "TranslateDevicename") == 0)
-       {
-               if (IS_TRUE (value))
-                       translate_devicename = 1;
-               else
-                       translate_devicename = 0;
-       }
        else
        {
                return (-1);
@@ -246,199 +228,6 @@ static int hddtemp_config (const char *key, const char *value)
        return (0);
 }
 
-/* In the init-function we initialize the `hddname_t' list used to translate
- * disk-names. Under Linux that's done using `/proc/partitions'. Under other
- * operating-systems, it's not done at all. */
-static int hddtemp_init (void)
-{
-#if KERNEL_LINUX
-       FILE *fh;
-       char buf[1024];
-       int buflen;
-
-       char *fields[16];
-       int num_fields;
-
-       int major;
-       int minor;
-       char *name;
-       hddname_t *next;
-       hddname_t *entry;
-
-       next = first_hddname;
-       while (next != NULL)
-       {
-               entry = next;
-               next = entry->next;
-
-               free (entry->name);
-               free (entry);
-       }
-       first_hddname = NULL;
-
-       if ((fh = fopen ("/proc/partitions", "r")) != NULL)
-       {
-               DEBUG ("hddtemp plugin: Looking at /proc/partitions...");
-
-               while (fgets (buf, sizeof (buf), fh) != NULL)
-               {
-                       /* Delete trailing newlines */
-                       buflen = strlen (buf);
-
-                       while ((buflen > 0) && ((buf[buflen-1] == '\n') || (buf[buflen-1] == '\r')))
-                               buf[--buflen] = '\0';
-
-                       /* We want lines of the form:
-                        *
-                        *     3     1   77842926 hda1
-                        *
-                        * ...so, skip everything else. */
-                       if (buflen == 0)
-                               continue;
-                       
-                       num_fields = strsplit (buf, fields, 16);
-
-                       if (num_fields != 4)
-                               continue;
-
-                       major = atoi (fields[0]);
-                       minor = atoi (fields[1]);
-
-                       /* We try to keep only entries, which may correspond to
-                        * physical disks and that may have a corresponding
-                        * entry in the hddtemp daemon. Basically, this means
-                        * IDE and SCSI. */
-                       switch (major)
-                       {
-                               /* SCSI. */
-                               case SCSI_DISK0_MAJOR:
-                               case SCSI_DISK1_MAJOR:
-                               case SCSI_DISK2_MAJOR:
-                               case SCSI_DISK3_MAJOR:
-                               case SCSI_DISK4_MAJOR:
-                               case SCSI_DISK5_MAJOR:
-                               case SCSI_DISK6_MAJOR:
-                               case SCSI_DISK7_MAJOR:
-#ifdef SCSI_DISK8_MAJOR
-                               case SCSI_DISK8_MAJOR:
-                               case SCSI_DISK9_MAJOR:
-                               case SCSI_DISK10_MAJOR:
-                               case SCSI_DISK11_MAJOR:
-                               case SCSI_DISK12_MAJOR:
-                               case SCSI_DISK13_MAJOR:
-                               case SCSI_DISK14_MAJOR:
-                               case SCSI_DISK15_MAJOR:
-#endif /* SCSI_DISK8_MAJOR */
-                                       /* SCSI disks minors are multiples of 16.
-                                        * Keep only those. */
-                                       if (minor % 16)
-                                               continue;
-                                       break;
-
-                               /* IDE. */
-                               case IDE0_MAJOR:
-                               case IDE1_MAJOR:
-                               case IDE2_MAJOR:
-                               case IDE3_MAJOR:
-                               case IDE4_MAJOR:
-                               case IDE5_MAJOR:
-                               case IDE6_MAJOR:
-                               case IDE7_MAJOR:
-                               case IDE8_MAJOR:
-                               case IDE9_MAJOR:
-                                       /* IDE disks minors can only be 0 or 64.
-                                        * Keep only those. */
-                                       if(minor != 0 && minor != 64)
-                                               continue;
-                                       break;
-
-                               /* Skip all other majors. */
-                               default:
-                                       DEBUG ("hddtemp plugin: Skipping unknown major %i", major);
-                                       continue;
-                       } /* switch (major) */
-
-                       if ((name = strdup (fields[3])) == NULL)
-                       {
-                               ERROR ("hddtemp plugin: strdup(%s) == NULL", fields[3]);
-                               continue;
-                       }
-
-                       if ((entry = (hddname_t *) malloc (sizeof (hddname_t))) == NULL)
-                       {
-                               ERROR ("hddtemp plugin: malloc (%u) == NULL",
-                                               (unsigned int) sizeof (hddname_t));
-                               free (name);
-                               continue;
-                       }
-
-                       DEBUG ("hddtemp plugin: Found disk: %s (%u:%u).", name, major, minor);
-
-                       entry->major = major;
-                       entry->minor = minor;
-                       entry->name  = name;
-                       entry->next  = NULL;
-
-                       if (first_hddname == NULL)
-                       {
-                               first_hddname = entry;
-                       }
-                       else
-                       {
-                               entry->next = first_hddname;
-                               first_hddname = entry;
-                       }
-               }
-               fclose (fh);
-       }
-#if COLLECT_DEBUG
-       else
-       {
-               char errbuf[1024];
-               DEBUG ("hddtemp plugin: Could not open /proc/partitions: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
-       }
-#endif /* COLLECT_DEBUG */
-#endif /* KERNEL_LINUX */
-
-       return (0);
-} /* int hddtemp_init */
-
-/*
- * hddtemp_get_major_minor
- *
- * Description:
- *   Try to "cook" a bit the drive name as returned
- *   by the hddtemp daemon. The intend is to transform disk
- *   names into <major>-<minor> when possible.
- */
-static char *hddtemp_get_major_minor (char *drive)
-{
-       hddname_t *list;
-       char *ret;
-
-       for (list = first_hddname; list != NULL; list = list->next)
-               if (strcmp (drive, list->name) == 0)
-                       break;
-
-       if (list == NULL)
-       {
-               DEBUG ("hddtemp plugin: Don't know %s, keeping name as-is.", drive);
-               return (strdup (drive));
-       }
-
-       if ((ret = (char *) malloc (128 * sizeof (char))) == NULL)
-               return (NULL);
-
-       if (ssnprintf (ret, 128, "%i-%i", list->major, list->minor) >= 128)
-       {
-               free (ret);
-               return (NULL);
-       }
-
-       return (ret);
-}
-
 static void hddtemp_submit (char *type_instance, double value)
 {
        value_t values[1];
@@ -487,7 +276,7 @@ static int hddtemp_read (void)
 
        for (i = 0; i < num_disks; i++)
        {
-               char *name, *major_minor;
+               char *name;
                double temperature;
                char *mode;
 
@@ -504,16 +293,7 @@ static int hddtemp_read (void)
                if (mode[0] == 'F')
                        temperature = (temperature - 32.0) * 5.0 / 9.0;
 
-               if (translate_devicename
-                               && (major_minor = hddtemp_get_major_minor (name)) != NULL)
-               {
-                       hddtemp_submit (major_minor, temperature);
-                       free (major_minor);
-               }
-               else
-               {
-                       hddtemp_submit (name, temperature);
-               }
+               hddtemp_submit (name, temperature);
        }
        
        return (0);
@@ -525,6 +305,5 @@ void module_register (void)
 {
        plugin_register_config ("hddtemp", hddtemp_config,
                        config_keys, config_keys_num);
-       plugin_register_init ("hddtemp", hddtemp_init);
        plugin_register_read ("hddtemp", hddtemp_read);
 }
index db998a3..ea82039 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/interface.c
- * Copyright (C) 2005-2008  Florian octo Forster
+ * Copyright (C) 2005-2010  Florian octo Forster
  * Copyright (C) 2009       Manuel Sanmartin
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -128,7 +128,7 @@ static int interface_config (const char *key, const char *value)
 static int interface_init (void)
 {
        kstat_t *ksp_chain;
-       unsigned long long val;
+       derive_t val;
 
        numif = 0;
 
@@ -155,8 +155,8 @@ static int interface_init (void)
 #endif /* HAVE_LIBKSTAT */
 
 static void if_submit (const char *dev, const char *type,
-               unsigned long long rx,
-               unsigned long long tx)
+               derive_t rx,
+               derive_t tx)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
@@ -164,15 +164,15 @@ static void if_submit (const char *dev, const char *type,
        if (ignorelist_match (ignorelist, dev) != 0)
                return;
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        vl.values = values;
        vl.values_len = 2;
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "interface", sizeof (vl.plugin));
+       sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
-       sstrncpy (vl.type_instance, dev, sizeof (vl.type_instance));
 
        plugin_dispatch_values (&vl);
 } /* void if_submit */
@@ -233,7 +233,7 @@ static int interface_read (void)
 #elif KERNEL_LINUX
        FILE *fh;
        char buffer[1024];
-       unsigned long long incoming, outgoing;
+       derive_t incoming, outgoing;
        char *device;
 
        char *dummy;
@@ -285,8 +285,8 @@ static int interface_read (void)
 
 #elif HAVE_LIBKSTAT
        int i;
-       unsigned long long rx;
-       unsigned long long tx;
+       derive_t rx;
+       derive_t tx;
 
        if (kc == NULL)
                return (-1);
index 95b3dbf..f341320 100644 (file)
@@ -136,7 +136,7 @@ static void sensor_read_handler (ipmi_sensor_t *sensor,
 
         if (c_ipmi_nofiy_notpresent)
         {
-          notification_t n = { NOTIF_WARNING, time(NULL), "", "", "ipmi",
+          notification_t n = { NOTIF_WARNING, cdtime (), "", "", "ipmi",
             "", "", "", NULL };
 
           sstrncpy (n.host, hostname_g, sizeof (n.host));
@@ -190,7 +190,7 @@ static void sensor_read_handler (ipmi_sensor_t *sensor,
 
     if (c_ipmi_nofiy_notpresent)
     {
-      notification_t n = { NOTIF_OKAY, time(NULL), "", "", "ipmi",
+      notification_t n = { NOTIF_OKAY, cdtime (), "", "", "ipmi",
         "", "", "", NULL };
 
       sstrncpy (n.host, hostname_g, sizeof (n.host));
@@ -363,7 +363,7 @@ static int sensor_list_add (ipmi_sensor_t *sensor)
 
   if (c_ipmi_nofiy_add && (c_ipmi_init_in_progress == 0))
   {
-    notification_t n = { NOTIF_OKAY, time(NULL), "", "", "ipmi",
+    notification_t n = { NOTIF_OKAY, cdtime (), "", "", "ipmi",
                          "", "", "", NULL };
 
     sstrncpy (n.host, hostname_g, sizeof (n.host));
@@ -417,7 +417,7 @@ static int sensor_list_remove (ipmi_sensor_t *sensor)
 
   if (c_ipmi_nofiy_remove && c_ipmi_active)
   {
-    notification_t n = { NOTIF_WARNING, time(NULL), "", "",
+    notification_t n = { NOTIF_WARNING, cdtime (), "", "",
                          "ipmi", "", "", "", NULL };
 
     sstrncpy (n.host, hostname_g, sizeof (n.host));
@@ -664,7 +664,8 @@ static int c_ipmi_init (void)
   int status;
 
   /* Don't send `ADD' notifications during startup (~ 1 minute) */
-  c_ipmi_init_in_progress = 1 + (60 / interval_g);
+  time_t iv = CDTIME_T_TO_TIME_T (interval_g);
+  c_ipmi_init_in_progress = 1 + (60 / iv);
 
   c_ipmi_active = 1;
 
index aa53074..c39aff8 100644 (file)
@@ -1,8 +1,8 @@
 /**
  * collectd - src/iptables.c
- * Copyright (C) 2007 Sjoerd van der Berg
- * Copyright (C) 2007 Florian octo Forster
- * Copyright (C) 2009 Marco Chiappero
+ * Copyright (C) 2007       Sjoerd van der Berg
+ * Copyright (C) 2007-2010  Florian octo Forster
+ * Copyright (C) 2009       Marco Chiappero
  *
  * 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
@@ -20,7 +20,7 @@
  *
  * Authors:
  *  Sjoerd van der Berg <harekiet at users.sourceforge.net>
- *  Florian Forster <octo at verplant.org>
+ *  Florian Forster <octo at collectd.org>
  *  Marco Chiappero <marco at absence.it>
  **/
 
@@ -297,11 +297,11 @@ static int submit6_match (const struct ip6t_entry_match *match,
     }
 
     sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
-    values[0].counter = (counter_t) entry->counters.bcnt;
+    values[0].derive = (derive_t) entry->counters.bcnt;
     plugin_dispatch_values (&vl);
 
     sstrncpy (vl.type, "ipt_packets", sizeof (vl.type));
-    values[0].counter = (counter_t) entry->counters.pcnt;
+    values[0].derive = (derive_t) entry->counters.pcnt;
     plugin_dispatch_values (&vl);
 
     return (0);
@@ -358,11 +358,11 @@ static int submit_match (const struct ipt_entry_match *match,
     }
 
     sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
-    values[0].counter = (counter_t) entry->counters.bcnt;
+    values[0].derive = (derive_t) entry->counters.bcnt;
     plugin_dispatch_values (&vl);
 
     sstrncpy (vl.type, "ipt_packets", sizeof (vl.type));
-    values[0].counter = (counter_t) entry->counters.pcnt;
+    values[0].derive = (derive_t) entry->counters.pcnt;
     plugin_dispatch_values (&vl);
 
     return (0);
index 7bd8c69..fa89489 100644 (file)
@@ -227,18 +227,16 @@ static int get_ti (struct ip_vs_dest_entry *de, char *ti, size_t size)
        return 0;
 } /* get_ti */
 
-static void cipvs_submit_connections (char *pi, char *ti, counter_t value)
+static void cipvs_submit_connections (char *pi, char *ti, derive_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = value;
+       values[0].derive = value;
 
        vl.values     = values;
        vl.values_len = 1;
 
-       vl.interval = interval_g;
-
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
@@ -251,19 +249,17 @@ static void cipvs_submit_connections (char *pi, char *ti, counter_t value)
 } /* cipvs_submit_connections */
 
 static void cipvs_submit_if (char *pi, char *t, char *ti,
-               counter_t rx, counter_t tx)
+               derive_t rx, derive_t tx)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        vl.values     = values;
        vl.values_len = 2;
 
-       vl.interval = interval_g;
-
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
index 70d6b5a..7e73829 100644 (file)
--- a/src/irq.c
+++ b/src/irq.c
@@ -106,7 +106,7 @@ static int check_ignore_irq (const char *irq)
        return (1 - irq_list_action);
 }
 
-static void irq_submit (const char *irq_name, counter_t value)
+static void irq_submit (const char *irq_name, derive_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
@@ -114,7 +114,7 @@ static void irq_submit (const char *irq_name, counter_t value)
        if (check_ignore_irq (irq_name))
                return;
 
-       values[0].counter = value;
+       values[0].derive = value;
 
        vl.values = values;
        vl.values_len = 1;
@@ -130,25 +130,25 @@ static int irq_read (void)
 {
        FILE *fh;
        char buffer[1024];
-       unsigned long long irq_value;
-       unsigned long long value;
-       char *endptr;
-       int i;
 
-       char *fields[64];
-       int fields_num;
-
-       if ((fh = fopen ("/proc/interrupts", "r")) == NULL)
+       fh = fopen ("/proc/interrupts", "r");
+       if (fh == NULL)
        {
                char errbuf[1024];
-               WARNING ("irq plugin: fopen (/proc/interrupts): %s",
+               ERROR ("irq plugin: fopen (/proc/interrupts): %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
+
        while (fgets (buffer, sizeof (buffer), fh) != NULL)
        {
                char *irq_name;
                size_t irq_name_len;
+               derive_t irq_value;
+               int i;
+
+               char *fields[64];
+               int fields_num;
 
                fields_num = strsplit (buffer, fields, 64);
                if (fields_num < 2)
@@ -170,23 +170,22 @@ static int irq_read (void)
                irq_value = 0;
                for (i = 1; i < fields_num; i++)
                {
-                       errno = 0;
-                       endptr = NULL;
-                       value = strtoull (fields[i], &endptr, 10);
+                       /* Per-CPU value */
+                       value_t v;
+                       int status;
 
-                       /* Ignore all fields following a non-numeric field. */
-                       if ((errno != 0) || (endptr == NULL) || (*endptr != 0))
+                       status = parse_value (fields[i], &v, DS_TYPE_DERIVE);
+                       if (status != 0)
                                break;
 
-                       irq_value += value;
+                       irq_value += v.derive;
                } /* for (i) */
 
                /* No valid fields -> do not submit anything. */
                if (i <= 1)
                        continue;
 
-               /* Force 32bit wrap-around */
-               irq_submit (irq_name, irq_value % 4294967296ULL);
+               irq_submit (irq_name, irq_value);
        }
 
        fclose (fh);
index a8ffd8e..b69ca94 100644 (file)
@@ -109,7 +109,7 @@ static int cjni_callback_register (JNIEnv *jvm_env, jobject o_name,
 static int cjni_read (user_data_t *user_data);
 static int cjni_write (const data_set_t *ds, const value_list_t *vl,
     user_data_t *ud);
-static int cjni_flush (int timeout, const char *identifier, user_data_t *ud);
+static int cjni_flush (cdtime_t timeout, const char *identifier, user_data_t *ud);
 static void cjni_log (int severity, const char *message, user_data_t *ud);
 static int cjni_notification (const notification_t *n, user_data_t *ud);
 
@@ -809,7 +809,7 @@ static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */
 #undef SET_STRING
 
   /* Set the `time' member. Java stores time in milliseconds. */
-  status = ctoj_long (jvm_env, ((jlong) vl->time) * ((jlong) 1000),
+  status = ctoj_long (jvm_env, (jlong) CDTIME_T_TO_MS (vl->time),
       c_valuelist, o_valuelist, "setTime");
   if (status != 0)
   {
@@ -819,7 +819,8 @@ static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */
   }
 
   /* Set the `interval' member.. */
-  status = ctoj_long (jvm_env, (jlong) vl->interval,
+  status = ctoj_long (jvm_env,
+      (jlong) CDTIME_T_TO_MS (vl->interval),
       c_valuelist, o_valuelist, "setInterval");
   if (status != 0)
   {
@@ -914,7 +915,7 @@ static jobject ctoj_notification (JNIEnv *jvm_env, /* {{{ */
     return (NULL);
   }
 
-  /* Set the `interval' member.. */
+  /* Set the `severity' member.. */
   status = ctoj_int (jvm_env, (jint) n->severity,
       c_notification, o_notification, "setSeverity");
   if (status != 0)
@@ -1242,7 +1243,7 @@ static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */
     return (-1);
   }
   /* Java measures time in milliseconds. */
-  vl->time = (time_t) (tmp_long / ((jlong) 1000));
+  vl->time = MS_TO_CDTIME_T (tmp_long);
 
   status = jtoc_long (jvm_env, &tmp_long,
       class_ptr, object_ptr, "getInterval");
@@ -1251,7 +1252,7 @@ static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */
     ERROR ("java plugin: jtoc_value_list: jtoc_long (getInterval) failed.");
     return (-1);
   }
-  vl->interval = (int) tmp_long;
+  vl->interval = MS_TO_CDTIME_T (tmp_long);
 
   status = jtoc_values_array (jvm_env, ds, vl, class_ptr, object_ptr);
   if (status != 0)
@@ -1729,7 +1730,7 @@ static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{
 
     case CB_TYPE_FLUSH:
       method_name = "flush";
-      method_signature = "(ILjava/lang/String;)I";
+      method_signature = "(Ljava/lang/Number;Ljava/lang/String;)I";
       break;
 
     case CB_TYPE_SHUTDOWN:
@@ -2552,11 +2553,12 @@ static int cjni_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
 } /* }}} int cjni_write */
 
 /* Call the CB_TYPE_FLUSH callback pointed to by the `user_data_t' pointer. */
-static int cjni_flush (int timeout, const char *identifier, /* {{{ */
+static int cjni_flush (cdtime_t timeout, const char *identifier, /* {{{ */
     user_data_t *ud)
 {
   JNIEnv *jvm_env;
   cjni_callback_info_t *cbi;
+  jobject o_timeout;
   jobject o_identifier;
   int status;
   int ret_status;
@@ -2579,21 +2581,32 @@ static int cjni_flush (int timeout, const char *identifier, /* {{{ */
 
   cbi = (cjni_callback_info_t *) ud->data;
 
+  o_timeout = ctoj_jdouble_to_number (jvm_env,
+      (jdouble) CDTIME_T_TO_DOUBLE (timeout));
+  if (o_timeout == NULL)
+  {
+    ERROR ("java plugin: cjni_flush: Converting double "
+        "to Number object failed.");
+    return (-1);
+  }
+
   o_identifier = NULL;
   if (identifier != NULL)
   {
     o_identifier = (*jvm_env)->NewStringUTF (jvm_env, identifier);
     if (o_identifier == NULL)
     {
+      (*jvm_env)->DeleteLocalRef (jvm_env, o_timeout);
       ERROR ("java plugin: cjni_flush: NewStringUTF failed.");
       return (-1);
     }
   }
 
   ret_status = (*jvm_env)->CallIntMethod (jvm_env,
-      cbi->object, cbi->method, (jint) timeout, o_identifier);
+      cbi->object, cbi->method, o_timeout, o_identifier);
 
   (*jvm_env)->DeleteLocalRef (jvm_env, o_identifier);
+  (*jvm_env)->DeleteLocalRef (jvm_env, o_timeout);
 
   status = cjni_thread_detach ();
   if (status != 0)
index 2f427a8..f5fe204 100644 (file)
@@ -164,27 +164,14 @@ static int lcc_set_errno (lcc_connection_t *c, int err) /* {{{ */
   return (0);
 } /* }}} int lcc_set_errno */
 
-/* lcc_strdup: Since `strdup' is an XSI extension, we provide our own version
- * here. */
-__attribute__((malloc, nonnull (1)))
-static char *lcc_strdup (const char *str) /* {{{ */
-{
-  size_t strsize;
-  char *ret;
-
-  strsize = strlen (str) + 1;
-  ret = (char *) malloc (strsize);
-  if (ret != NULL)
-    memcpy (ret, str, strsize);
-  return (ret);
-} /* }}} char *lcc_strdup */
-
-__attribute__((nonnull (1, 2)))
 static char *lcc_strescape (char *dest, const char *src, size_t dest_size) /* {{{ */
 {
   size_t dest_pos;
   size_t src_pos;
 
+  if ((dest == NULL) || (src == NULL))
+    return (NULL);
+
   dest_pos = 0;
   src_pos = 0;
 
@@ -338,7 +325,7 @@ static int lcc_receive (lcc_connection_t *c, /* {{{ */
     lcc_chomp (buffer);
     LCC_DEBUG ("receive: <-- %s\n", buffer);
 
-    res.lines[i] = lcc_strdup (buffer);
+    res.lines[i] = strdup (buffer);
     if (res.lines[i] == NULL)
     {
       lcc_set_errno (c, ENOMEM);
@@ -733,7 +720,7 @@ int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */
 
     if (values_names != NULL)
     {
-      values_names[i] = lcc_strdup (key);
+      values_names[i] = strdup (key);
       if (values_names[i] == NULL)
         BAIL_OUT (ENOMEM);
     }
@@ -790,7 +777,7 @@ int lcc_putval (lcc_connection_t *c, const lcc_value_list_t *vl) /* {{{ */
     else if (vl->values_types[i] == LCC_TYPE_GAUGE)
     {
       if (isnan (vl->values[i].gauge))
-        SSTRCPY (command, ":U");
+        SSTRCATF (command, ":U");
       else
         SSTRCATF (command, ":%g", vl->values[i].gauge);
     }
@@ -1015,7 +1002,7 @@ int lcc_string_to_identifier (lcc_connection_t *c, /* {{{ */
   char *type;
   char *type_instance;
 
-  string_copy = lcc_strdup (string);
+  string_copy = strdup (string);
   if (string_copy == NULL)
   {
     lcc_set_errno (c, ENOMEM);
index 11e7b13..9900353 100644 (file)
@@ -84,7 +84,7 @@ struct lcc_value_list_s
   lcc_identifier_t identifier;
 };
 typedef struct lcc_value_list_s lcc_value_list_t;
-#define LCC_VALUE_LIST_INIT { NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
+#define LCC_VALUE_LIST_INIT { NULL, NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
 
 struct lcc_connection_s;
 typedef struct lcc_connection_s lcc_connection_t;
index 1f62879..774067c 100644 (file)
@@ -43,6 +43,7 @@ static const char *config_keys[] = {
     "IgnoreSelected",
 
     "HostnameFormat",
+    "InterfaceFormat",
 
     NULL
 };
@@ -89,13 +90,14 @@ static int add_block_device (virDomainPtr dom, const char *path);
 struct interface_device {
     virDomainPtr dom;           /* domain */
     char *path;                 /* name of interface device */
+    char *address;              /* mac address of interface device */
 };
 
 static struct interface_device *interface_devices = NULL;
 static int nr_interface_devices = 0;
 
 static void free_interface_devices (void);
-static int add_interface_device (virDomainPtr dom, const char *path);
+static int add_interface_device (virDomainPtr dom, const char *path, const char *address);
 
 /* HostnameFormat. */
 #define HF_MAX_FIELDS 3
@@ -110,22 +112,19 @@ enum hf_field {
 static enum hf_field hostname_format[HF_MAX_FIELDS] =
     { hf_name };
 
+/* InterfaceFormat. */
+enum if_field {
+    if_address,
+    if_name
+};
+
+static enum if_field interface_format = if_name;
+
 /* Time that we last refreshed. */
 static time_t last_refresh = (time_t) 0;
 
 static int refresh_lists (void);
 
-/* Submit functions. */
-static void cpu_submit (unsigned long long cpu_time,
-                        time_t t,
-                        virDomainPtr dom, const char *type);
-static void vcpu_submit (unsigned long long cpu_time,
-                         time_t t,
-                         virDomainPtr dom, int vcpu_nr, const char *type);
-static void submit_counter2 (const char *type, counter_t v0, counter_t v1,
-             time_t t,
-             virDomainPtr dom, const char *devname);
-
 /* ERROR(...) macro for virterrors. */
 #define VIRT_ERROR(conn,s) do {                 \
         virErrorPtr err;                        \
@@ -133,6 +132,109 @@ static void submit_counter2 (const char *type, counter_t v0, counter_t v1,
         if (err) ERROR ("%s: %s", (s), err->message);                   \
     } while(0)
 
+static void
+init_value_list (value_list_t *vl, virDomainPtr dom)
+{
+    int i, n;
+    const char *name;
+    char uuid[VIR_UUID_STRING_BUFLEN];
+
+    vl->interval = interval_g;
+
+    sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
+
+    vl->host[0] = '\0';
+
+    /* Construct the hostname field according to HostnameFormat. */
+    for (i = 0; i < HF_MAX_FIELDS; ++i) {
+        if (hostname_format[i] == hf_none)
+            continue;
+
+        n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
+
+        if (i > 0 && n >= 1) {
+            strncat (vl->host, ":", 1);
+            n--;
+        }
+
+        switch (hostname_format[i]) {
+        case hf_none: break;
+        case hf_hostname:
+            strncat (vl->host, hostname_g, n);
+            break;
+        case hf_name:
+            name = virDomainGetName (dom);
+            if (name)
+                strncat (vl->host, name, n);
+            break;
+        case hf_uuid:
+            if (virDomainGetUUIDString (dom, uuid) == 0)
+                strncat (vl->host, uuid, n);
+            break;
+        }
+    }
+
+    vl->host[sizeof (vl->host) - 1] = '\0';
+} /* void init_value_list */
+
+static void
+cpu_submit (unsigned long long cpu_time,
+            virDomainPtr dom, const char *type)
+{
+    value_t values[1];
+    value_list_t vl = VALUE_LIST_INIT;
+
+    init_value_list (&vl, dom);
+
+    values[0].derive = cpu_time;
+
+    vl.values = values;
+    vl.values_len = 1;
+
+    sstrncpy (vl.type, type, sizeof (vl.type));
+
+    plugin_dispatch_values (&vl);
+}
+
+static void
+vcpu_submit (derive_t cpu_time,
+             virDomainPtr dom, int vcpu_nr, const char *type)
+{
+    value_t values[1];
+    value_list_t vl = VALUE_LIST_INIT;
+
+    init_value_list (&vl, dom);
+
+    values[0].derive = cpu_time;
+    vl.values = values;
+    vl.values_len = 1;
+
+    sstrncpy (vl.type, type, sizeof (vl.type));
+    ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
+
+    plugin_dispatch_values (&vl);
+}
+
+static void
+submit_derive2 (const char *type, derive_t v0, derive_t v1,
+             virDomainPtr dom, const char *devname)
+{
+    value_t values[2];
+    value_list_t vl = VALUE_LIST_INIT;
+
+    init_value_list (&vl, dom);
+
+    values[0].derive = v0;
+    values[1].derive = v1;
+    vl.values = values;
+    vl.values_len = 2;
+
+    sstrncpy (vl.type, type, sizeof (vl.type));
+    sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
+
+    plugin_dispatch_values (&vl);
+} /* void submit_derive2 */
+
 static int
 lv_init (void)
 {
@@ -215,7 +317,7 @@ lv_config (const char *key, const char *value)
 
         n = strsplit (value_copy, fields, HF_MAX_FIELDS);
         if (n < 1) {
-            free (value_copy);
+            sfree (value_copy);
             ERROR ("HostnameFormat: no fields");
             return -1;
         }
@@ -228,12 +330,12 @@ lv_config (const char *key, const char *value)
             else if (strcasecmp (fields[i], "uuid") == 0)
                 hostname_format[i] = hf_uuid;
             else {
-                free (value_copy);
+                sfree (value_copy);
                 ERROR ("unknown HostnameFormat field: %s", fields[i]);
                 return -1;
             }
         }
-        free (value_copy);
+        sfree (value_copy);
 
         for (i = n; i < HF_MAX_FIELDS; ++i)
             hostname_format[i] = hf_none;
@@ -241,6 +343,18 @@ lv_config (const char *key, const char *value)
         return 0;
     }
 
+    if (strcasecmp (key, "InterfaceFormat") == 0) {
+        if (strcasecmp (value, "name") == 0)
+            interface_format = if_name;
+        else if (strcasecmp (value, "address") == 0)
+            interface_format = if_address;
+        else {
+            ERROR ("unknown InterfaceFormat: %s", value);
+            return -1;
+        }
+        return 0;
+    }
+
     /* Unrecognised option. */
     return -1;
 }
@@ -306,7 +420,7 @@ lv_read (void)
             continue;
         }
 
-        cpu_submit (info.cpuTime, t, domains[i], "virt_cpu_total");
+        cpu_submit (info.cpuTime, domains[i], "virt_cpu_total");
 
         vinfo = malloc (info.nrVirtCpu * sizeof (vinfo[0]));
         if (vinfo == NULL) {
@@ -326,9 +440,9 @@ lv_read (void)
 
         for (j = 0; j < info.nrVirtCpu; ++j)
             vcpu_submit (vinfo[j].cpuTime,
-                    t, domains[i], vinfo[j].number, "virt_vcpu");
+                    domains[i], vinfo[j].number, "virt_vcpu");
 
-        free (vinfo);
+        sfree (vinfo);
     }
 
     /* Get block device stats for each domain. */
@@ -340,19 +454,23 @@ lv_read (void)
             continue;
 
         if ((stats.rd_req != -1) && (stats.wr_req != -1))
-            submit_counter2 ("disk_ops",
-                    (counter_t) stats.rd_req, (counter_t) stats.wr_req,
-                    t, block_devices[i].dom, block_devices[i].path);
+            submit_derive2 ("disk_ops",
+                    (derive_t) stats.rd_req, (derive_t) stats.wr_req,
+                    block_devices[i].dom, block_devices[i].path);
 
         if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1))
-            submit_counter2 ("disk_octets",
-                    (counter_t) stats.rd_bytes, (counter_t) stats.wr_bytes,
-                    t, block_devices[i].dom, block_devices[i].path);
+            submit_derive2 ("disk_octets",
+                    (derive_t) stats.rd_bytes, (derive_t) stats.wr_bytes,
+                    block_devices[i].dom, block_devices[i].path);
     } /* for (nr_block_devices) */
 
     /* Get interface stats for each domain. */
     for (i = 0; i < nr_interface_devices; ++i) {
         struct _virDomainInterfaceStats stats;
+        char *display_name = interface_devices[i].path;
+
+        if (interface_format == if_address)
+            display_name = interface_devices[i].address;
 
         if (virDomainInterfaceStats (interface_devices[i].dom,
                     interface_devices[i].path,
@@ -360,24 +478,24 @@ lv_read (void)
             continue;
 
        if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
-           submit_counter2 ("if_octets",
-                   (counter_t) stats.rx_bytes, (counter_t) stats.tx_bytes,
-                   t, interface_devices[i].dom, interface_devices[i].path);
+           submit_derive2 ("if_octets",
+                   (derive_t) stats.rx_bytes, (derive_t) stats.tx_bytes,
+                   interface_devices[i].dom, display_name);
 
        if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
-           submit_counter2 ("if_packets",
-                   (counter_t) stats.rx_packets, (counter_t) stats.tx_packets,
-                   t, interface_devices[i].dom, interface_devices[i].path);
+           submit_derive2 ("if_packets",
+                   (derive_t) stats.rx_packets, (derive_t) stats.tx_packets,
+                   interface_devices[i].dom, display_name);
 
        if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
-           submit_counter2 ("if_errors",
-                   (counter_t) stats.rx_errs, (counter_t) stats.tx_errs,
-                   t, interface_devices[i].dom, interface_devices[i].path);
+           submit_derive2 ("if_errors",
+                   (derive_t) stats.rx_errs, (derive_t) stats.tx_errs,
+                   interface_devices[i].dom, display_name);
 
        if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
-           submit_counter2 ("if_dropped",
-                   (counter_t) stats.rx_drop, (counter_t) stats.tx_drop,
-                   t, interface_devices[i].dom, interface_devices[i].path);
+           submit_derive2 ("if_dropped",
+                   (derive_t) stats.rx_drop, (derive_t) stats.tx_drop,
+                   interface_devices[i].dom, display_name);
     } /* for (nr_interface_devices) */
 
     return 0;
@@ -408,7 +526,7 @@ refresh_lists (void)
         n = virConnectListDomains (conn, domids, n);
         if (n < 0) {
             VIRT_ERROR (conn, "reading list of domains");
-            free (domids);
+            sfree (domids);
             return -1;
         }
 
@@ -492,38 +610,54 @@ refresh_lists (void)
 
             /* Network interfaces. */
             xpath_obj = xmlXPathEval
-                ((xmlChar *) "/domain/devices/interface/target[@dev]",
+                ((xmlChar *) "/domain/devices/interface[target[@dev]]",
                  xpath_ctx);
             if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
                 xpath_obj->nodesetval == NULL)
                 goto cont;
 
-            for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
-                xmlNodePtr node;
+            xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
+
+            for (j = 0; j < xml_interfaces->nodeNr; ++j) {
                 char *path = NULL;
+                char *address = NULL;
+                xmlNodePtr xml_interface;
 
-                node = xpath_obj->nodesetval->nodeTab[j];
-                if (!node) continue;
-                path = (char *) xmlGetProp (node, (xmlChar *) "dev");
-                if (!path) continue;
+                xml_interface = xml_interfaces->nodeTab[j];
+                if (!xml_interface) continue;
+                xmlNodePtr child = NULL;
+
+                for (child = xml_interface->children; child; child = child->next) {
+                    if (child->type != XML_ELEMENT_NODE) continue;
+
+                    if (xmlStrEqual(child->name, (const xmlChar *) "target")) {
+                        path = (char *) xmlGetProp (child, (const xmlChar *) "dev");
+                        if (!path) continue;
+                    } else if (xmlStrEqual(child->name, (const xmlChar *) "mac")) {
+                        address = (char *) xmlGetProp (child, (const xmlChar *) "address");
+                        if (!address) continue;
+                    }
+                }
 
                 if (il_interface_devices &&
-                    ignore_device_match (il_interface_devices, name, path) != 0)
+                    (ignore_device_match (il_interface_devices, name, path) != 0 ||
+                     ignore_device_match (il_interface_devices, name, address) != 0))
                     goto cont3;
 
-                add_interface_device (dom, path);
-            cont3:
-                if (path) xmlFree (path);
+                add_interface_device (dom, path, address);
+                cont3:
+                    if (path) xmlFree (path);
+                    if (address) xmlFree (address);
             }
 
         cont:
             if (xpath_obj) xmlXPathFreeObject (xpath_obj);
             if (xpath_ctx) xmlXPathFreeContext (xpath_ctx);
             if (xml_doc) xmlFreeDoc (xml_doc);
-            if (xml) free (xml);
+            sfree (xml);
         }
 
-        free (domids);
+        sfree (domids);
     }
 
     return 0;
@@ -537,7 +671,7 @@ free_domains ()
     if (domains) {
         for (i = 0; i < nr_domains; ++i)
             virDomainFree (domains[i]);
-        free (domains);
+        sfree (domains);
     }
     domains = NULL;
     nr_domains = 0;
@@ -569,8 +703,8 @@ free_block_devices ()
 
     if (block_devices) {
         for (i = 0; i < nr_block_devices; ++i)
-            free (block_devices[i].path);
-        free (block_devices);
+            sfree (block_devices[i].path);
+        sfree (block_devices);
     }
     block_devices = NULL;
     nr_block_devices = 0;
@@ -593,7 +727,7 @@ add_block_device (virDomainPtr dom, const char *path)
         new_ptr = malloc (new_size);
 
     if (new_ptr == NULL) {
-        free (path_copy);
+        sfree (path_copy);
         return -1;
     }
     block_devices = new_ptr;
@@ -608,36 +742,43 @@ free_interface_devices ()
     int i;
 
     if (interface_devices) {
-        for (i = 0; i < nr_interface_devices; ++i)
-            free (interface_devices[i].path);
-        free (interface_devices);
+        for (i = 0; i < nr_interface_devices; ++i) {
+            sfree (interface_devices[i].path);
+            sfree (interface_devices[i].address);
+        }
+        sfree (interface_devices);
     }
     interface_devices = NULL;
     nr_interface_devices = 0;
 }
 
 static int
-add_interface_device (virDomainPtr dom, const char *path)
+add_interface_device (virDomainPtr dom, const char *path, const char *address)
 {
     struct interface_device *new_ptr;
     int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
-    char *path_copy;
+    char *path_copy, *address_copy;
 
     path_copy = strdup (path);
     if (!path_copy) return -1;
 
+    address_copy = strdup (address);
+    if (!address_copy) return -1;
+
     if (interface_devices)
         new_ptr = realloc (interface_devices, new_size);
     else
         new_ptr = malloc (new_size);
 
     if (new_ptr == NULL) {
-        free (path_copy);
+        sfree (path_copy);
+        sfree (address_copy);
         return -1;
     }
     interface_devices = new_ptr;
     interface_devices[nr_interface_devices].dom = dom;
     interface_devices[nr_interface_devices].path = path_copy;
+    interface_devices[nr_interface_devices].address = address_copy;
     return nr_interface_devices++;
 }
 
@@ -655,117 +796,10 @@ ignore_device_match (ignorelist_t *il, const char *domname, const char *devpath)
     }
     ssnprintf (name, n, "%s:%s", domname, devpath);
     r = ignorelist_match (il, name);
-    free (name);
+    sfree (name);
     return r;
 }
 
-static void
-init_value_list (value_list_t *vl, time_t t, virDomainPtr dom)
-{
-    int i, n;
-    const char *name;
-    char uuid[VIR_UUID_STRING_BUFLEN];
-
-    vl->time = t;
-    vl->interval = interval_g;
-
-    sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
-
-    vl->host[0] = '\0';
-
-    /* Construct the hostname field according to HostnameFormat. */
-    for (i = 0; i < HF_MAX_FIELDS; ++i) {
-        if (hostname_format[i] == hf_none)
-            continue;
-
-        n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
-
-        if (i > 0 && n >= 1) {
-            strncat (vl->host, ":", 1);
-            n--;
-        }
-
-        switch (hostname_format[i]) {
-        case hf_none: break;
-        case hf_hostname:
-            strncat (vl->host, hostname_g, n);
-            break;
-        case hf_name:
-            name = virDomainGetName (dom);
-            if (name)
-                strncat (vl->host, name, n);
-            break;
-        case hf_uuid:
-            if (virDomainGetUUIDString (dom, uuid) == 0)
-                strncat (vl->host, uuid, n);
-            break;
-        }
-    }
-
-    vl->host[sizeof (vl->host) - 1] = '\0';
-} /* void init_value_list */
-
-static void
-cpu_submit (unsigned long long cpu_time,
-            time_t t,
-            virDomainPtr dom, const char *type)
-{
-    value_t values[1];
-    value_list_t vl = VALUE_LIST_INIT;
-
-    init_value_list (&vl, t, dom);
-
-    values[0].counter = cpu_time;
-
-    vl.values = values;
-    vl.values_len = 1;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-
-    plugin_dispatch_values (&vl);
-}
-
-static void
-vcpu_submit (counter_t cpu_time,
-             time_t t,
-             virDomainPtr dom, int vcpu_nr, const char *type)
-{
-    value_t values[1];
-    value_list_t vl = VALUE_LIST_INIT;
-
-    init_value_list (&vl, t, dom);
-
-    values[0].counter = cpu_time;
-    vl.values = values;
-    vl.values_len = 1;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-    ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
-
-    plugin_dispatch_values (&vl);
-}
-
-static void
-submit_counter2 (const char *type, counter_t v0, counter_t v1,
-             time_t t,
-             virDomainPtr dom, const char *devname)
-{
-    value_t values[2];
-    value_list_t vl = VALUE_LIST_INIT;
-
-    init_value_list (&vl, t, dom);
-
-    values[0].counter = v0;
-    values[1].counter = v1;
-    vl.values = values;
-    vl.values_len = 2;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-    sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
-
-    plugin_dispatch_values (&vl);
-} /* void submit_counter2 */
-
 static int
 lv_shutdown (void)
 {
index 6d0f6e0..60fb5d9 100644 (file)
@@ -92,7 +92,8 @@ static int logfile_config (const char *key, const char *value)
        return 0;
 } /* int logfile_config (const char *, const char *) */
 
-static void logfile_print (const char *msg, int severity, time_t timestamp_time)
+static void logfile_print (const char *msg, int severity,
+               cdtime_t timestamp_time)
 {
        FILE *fh;
        int do_close = 0;
@@ -126,7 +127,8 @@ static void logfile_print (const char *msg, int severity, time_t timestamp_time)
 
        if (print_timestamp)
        {
-               localtime_r (&timestamp_time, &timestamp_tm);
+               time_t tt = CDTIME_T_TO_TIME_T (timestamp_time);
+               localtime_r (&tt, &timestamp_tm);
 
                strftime (timestamp_str, sizeof (timestamp_str), "%Y-%m-%d %H:%M:%S",
                                &timestamp_tm);
@@ -179,7 +181,7 @@ static void logfile_log (int severity, const char *msg,
        if (severity > log_level)
                return;
 
-       logfile_print (msg, severity, time (NULL));
+       logfile_print (msg, severity, cdtime ());
 } /* void logfile_log (int, const char *) */
 
 static int logfile_notification (const notification_t *n,
@@ -218,7 +220,7 @@ static int logfile_notification (const notification_t *n,
        buf[sizeof (buf) - 1] = '\0';
 
        logfile_print (buf, LOG_INFO,
-                       (n->time > 0) ? n->time : time (NULL));
+                       (n->time != 0) ? n->time : cdtime ());
 
        return (0);
 } /* int logfile_notification */
diff --git a/src/lpar.c b/src/lpar.c
new file mode 100644 (file)
index 0000000..4d53447
--- /dev/null
@@ -0,0 +1,273 @@
+/**
+ * collectd - src/lpar.c
+ * Copyright (C) 2010  Aurélien Reynaud
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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:
+ *   Aurélien Reynaud <collectd at wattapower.net>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <sys/protosw.h>
+#include <libperfstat.h>
+#include <sys/utsname.h>
+
+/* XINTFRAC was defined in libperfstat.h somewhere between AIX 5.3 and 6.1 */
+#ifndef XINTFRAC
+# include <sys/systemcfg.h>
+# define XINTFRAC ((double)(_system_configuration.Xint) / \
+                   (double)(_system_configuration.Xfrac))
+#endif
+
+#define CLOCKTICKS_TO_TICKS(cticks) ((cticks) / XINTFRAC)
+
+static const char *config_keys[] =
+{
+  "CpuPoolStats",
+  "ReportBySerial"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static _Bool pool_stats = 0;
+static _Bool report_by_serial = 0;
+#if PERFSTAT_SUPPORTS_DONATION
+static _Bool donate_flag = 0;
+#endif
+static char serial[SYS_NMLN];
+
+static perfstat_partition_total_t lparstats_old;
+
+static int lpar_config (const char *key, const char *value)
+{
+       if (strcasecmp ("CpuPoolStats", key) == 0)
+       {
+               if (IS_TRUE (value))
+                       pool_stats = 1;
+               else
+                       pool_stats = 0;
+       }
+       else if (strcasecmp ("ReportBySerial", key) == 0)
+       {
+               if (IS_TRUE (value))
+                       report_by_serial = 1;
+               else
+                       report_by_serial = 0;
+       }
+       else
+       {
+               return (-1);
+       }
+
+       return (0);
+} /* int lpar_config */
+
+static int lpar_init (void)
+{
+       int status;
+
+       /* Retrieve the initial metrics. Returns the number of structures filled. */
+       status = perfstat_partition_total (/* name = */ NULL, /* (must be NULL) */
+                       &lparstats_old, sizeof (perfstat_partition_total_t),
+                       /* number = */ 1 /* (must be 1) */);
+       if (status != 1)
+       {
+               char errbuf[1024];
+               ERROR ("lpar plugin: perfstat_partition_total failed: %s (%i)",
+                               sstrerror (errno, errbuf, sizeof (errbuf)),
+                               status);
+               return (-1);
+       }
+
+#if PERFSTAT_SUPPORTS_DONATION
+       if (!lparstats_old.type.b.shared_enabled
+                       && lparstats_old.type.b.donate_enabled)
+       {
+               donate_flag = 1;
+       }
+#endif
+
+       if (pool_stats && !lparstats_old.type.b.pool_util_authority)
+       {
+               WARNING ("lpar plugin: This partition does not have pool authority. "
+                               "Disabling CPU pool statistics collection.");
+               pool_stats = 0;
+       }
+
+       return (0);
+} /* int lpar_init */
+
+static void lpar_submit (const char *type_instance, double value)
+{
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].gauge = (gauge_t)value;
+
+       vl.values = values;
+       vl.values_len = 1;
+       if (report_by_serial)
+       {
+               sstrncpy (vl.host, serial, sizeof (vl.host));
+               sstrncpy (vl.plugin_instance, hostname_g, sizeof (vl.plugin));
+       }
+       else
+       {
+               sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       }
+       sstrncpy (vl.plugin, "lpar", sizeof (vl.plugin));
+       sstrncpy (vl.type, "vcpu", sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+       plugin_dispatch_values (&vl);
+} /* void lpar_submit */
+
+static int lpar_read (void)
+{
+       perfstat_partition_total_t lparstats;
+       int status;
+       struct utsname name;
+       u_longlong_t ticks;
+       u_longlong_t user_ticks, syst_ticks, wait_ticks, idle_ticks;
+       u_longlong_t consumed_ticks;
+       double entitled_proc_capacity;
+
+       /* An LPAR has the same serial number as the physical system it is currently
+          running on. It is a convenient way of tracking LPARs as they are moved
+          from chassis to chassis through Live Partition Mobility (LPM). */
+       if (uname (&name) != 0)
+       {
+               ERROR ("lpar plugin: uname failed.");
+               return (-1);
+       }
+       sstrncpy (serial, name.machine, sizeof (serial));
+
+       /* Retrieve the current metrics. Returns the number of structures filled. */
+       status = perfstat_partition_total (/* name = */ NULL, /* (must be NULL) */
+                       &lparstats, sizeof (perfstat_partition_total_t),
+                       /* number = */ 1 /* (must be 1) */);
+       if (status != 1)
+       {
+               char errbuf[1024];
+               ERROR ("lpar plugin: perfstat_partition_total failed: %s (%i)",
+                               sstrerror (errno, errbuf, sizeof (errbuf)),
+                               status);
+               return (-1);
+       }
+
+       /* Number of ticks since we last run. */
+       ticks = lparstats.timebase_last - lparstats_old.timebase_last;
+       if (ticks == 0)
+       {
+               /* The stats have not been updated. Return now to avoid
+                * dividing by zero */
+               return (0);
+       }
+
+       /*
+        * On a shared partition, we're "entitled" to a certain amount of
+        * processing power, for example 250/100 of a physical CPU. Processing
+        * capacity not used by the partition may be assigned to a different
+        * partition by the hypervisor, so "idle" is hopefully a very small
+        * number.
+        *
+        * A dedicated partition may donate its CPUs to another partition and
+        * may steal ticks from somewhere else (another partition or maybe the
+        * shared pool, I don't know --octo).
+        */
+
+       /* entitled_proc_capacity is in 1/100th of a CPU */
+       entitled_proc_capacity = 0.01 * ((double) lparstats.entitled_proc_capacity);
+       lpar_submit ("entitled", entitled_proc_capacity);
+
+       /* The number of ticks actually spent in the various states */
+       user_ticks = lparstats.puser - lparstats_old.puser;
+       syst_ticks = lparstats.psys  - lparstats_old.psys;
+       wait_ticks = lparstats.pwait - lparstats_old.pwait;
+       idle_ticks = lparstats.pidle - lparstats_old.pidle;
+       consumed_ticks = user_ticks + syst_ticks + wait_ticks + idle_ticks;
+
+       lpar_submit ("user", (double) user_ticks / (double) ticks);
+       lpar_submit ("system", (double) syst_ticks / (double) ticks);
+       lpar_submit ("wait", (double) wait_ticks / (double) ticks);
+       lpar_submit ("idle", (double) idle_ticks / (double) ticks);
+
+#if PERFSTAT_SUPPORTS_DONATION
+       if (donate_flag)
+       {
+               /* donated => ticks given to another partition
+                * stolen  => ticks received from another partition */
+               u_longlong_t idle_donated_ticks, busy_donated_ticks;
+               u_longlong_t idle_stolen_ticks, busy_stolen_ticks;
+
+               /* FYI:  PURR == Processor Utilization of Resources Register
+                *      SPURR == Scaled PURR */
+               idle_donated_ticks = lparstats.idle_donated_purr - lparstats_old.idle_donated_purr;
+               busy_donated_ticks = lparstats.busy_donated_purr - lparstats_old.busy_donated_purr;
+               idle_stolen_ticks  = lparstats.idle_stolen_purr  - lparstats_old.idle_stolen_purr;
+               busy_stolen_ticks  = lparstats.busy_stolen_purr  - lparstats_old.busy_stolen_purr;
+
+               lpar_submit ("idle_donated", (double) idle_donated_ticks / (double) ticks);
+               lpar_submit ("busy_donated", (double) busy_donated_ticks / (double) ticks);
+               lpar_submit ("idle_stolen",  (double) idle_stolen_ticks  / (double) ticks);
+               lpar_submit ("busy_stolen",  (double) busy_stolen_ticks  / (double) ticks);
+
+               /* Donated ticks will be accounted for as stolen ticks in other LPARs */
+               consumed_ticks += idle_stolen_ticks + busy_stolen_ticks;
+       }
+#endif
+
+       lpar_submit ("consumed", (double) consumed_ticks / (double) ticks);
+
+       if (pool_stats)
+       {
+               char typinst[DATA_MAX_NAME_LEN];
+               u_longlong_t pool_idle_cticks;
+               double pool_idle_cpus;
+               double pool_busy_cpus;
+
+               /* We're calculating "busy" from "idle" and the total number of
+                * CPUs, because the "busy" member didn't exist in early versions
+                * of libperfstat. It was added somewhere between AIX 5.3 ML5 and ML9. */
+               pool_idle_cticks = lparstats.pool_idle_time - lparstats_old.pool_idle_time;
+               pool_idle_cpus = CLOCKTICKS_TO_TICKS ((double) pool_idle_cticks) / (double) ticks;
+               pool_busy_cpus = ((double) lparstats.phys_cpus_pool) - pool_idle_cpus;
+               if (pool_busy_cpus < 0.0)
+                       pool_busy_cpus = 0.0;
+
+               ssnprintf (typinst, sizeof (typinst), "pool-%X-busy", lparstats.pool_id);
+               lpar_submit (typinst, pool_busy_cpus);
+
+               ssnprintf (typinst, sizeof (typinst), "pool-%X-idle", lparstats.pool_id);
+               lpar_submit (typinst, pool_idle_cpus);
+       }
+
+       memcpy (&lparstats_old, &lparstats, sizeof (lparstats_old));
+
+       return (0);
+} /* int lpar_read */
+
+void module_register (void)
+{
+       plugin_register_config ("lpar", lpar_config,
+                               config_keys, config_keys_num);
+       plugin_register_init ("lpar", lpar_init);
+       plugin_register_read ("lpar", lpar_read);
+} /* void module_register */
+
+/* vim: set sw=8 noet : */
+
index 8b3266d..13301ff 100644 (file)
@@ -561,20 +561,20 @@ static void submit (const char *dev, const char *type, const char *ti1,
        plugin_dispatch_values (&vl);
 }
 
-static void submit_counter (const char *dev, const char *type, const char *ti1,
-                               const char *ti2, counter_t val)
+static void submit_derive (const char *dev, const char *type, const char *ti1,
+                               const char *ti2, derive_t val)
 {
        value_t item;
-       item.counter = val;
+       item.derive = val;
        submit (dev, type, ti1, ti2, &item, 1);
 }
 
-static void submit_counter2 (const char *dev, const char *type, const char *ti1,
-                               const char *ti2, counter_t val1, counter_t val2)
+static void submit_derive2 (const char *dev, const char *type, const char *ti1,
+                               const char *ti2, derive_t val1, derive_t val2)
 {
        value_t items[2];
-       items[0].counter = val1;
-       items[1].counter = val2;
+       items[0].derive = val1;
+       items[1].derive = val2;
        submit (dev, type, ti1, ti2, items, 2);
 }
 
@@ -598,8 +598,8 @@ static void submit_antx (const char *dev, const char *name,
                        continue;
 
                ssnprintf (ti2, sizeof (ti2), "%i", i);
-               submit_counter (dev, "ath_stat", name, ti2,
-                               (counter_t) vals[i]);
+               submit_derive (dev, "ath_stat", name, ti2,
+                               (derive_t) vals[i]);
        }
 }
 
@@ -625,14 +625,14 @@ process_stat_struct (int which, const void *ptr, const char *dev, const char *ma
                uint32_t val = *(uint32_t *)(((char *) ptr) + specs[i].offset) ;
 
                if (item_watched (i) && (val != 0))
-                       submit_counter (dev, type_name, specs[i].name, mac, val);
+                       submit_derive (dev, type_name, specs[i].name, mac, val);
 
                if (item_summed (i))
                        misc += val;
        }
        
        if (misc != 0)
-               submit_counter (dev, type_name, misc_name, mac, misc);
+               submit_derive (dev, type_name, misc_name, mac, misc);
 
 }
 
@@ -734,13 +734,13 @@ process_station (int sk, const char *dev, struct ieee80211req_sta_info *si)
        /* These two stats are handled as a special case as they are
           a pair of 64bit values */
        if (item_watched (STAT_NODE_OCTETS))
-               submit_counter2 (dev, "node_octets", mac, NULL,
+               submit_derive2 (dev, "node_octets", mac, NULL,
                        ns->ns_rx_bytes, ns->ns_tx_bytes);
 
        /* This stat is handled as a special case, because it is stored
           as uin64_t, but we will ignore upper half */
        if (item_watched (STAT_NS_RX_BEACONS))
-               submit_counter (dev, "node_stat", "ns_rx_beacons", mac,
+               submit_derive (dev, "node_stat", "ns_rx_beacons", mac,
                        (ns->ns_rx_beacons & 0xFFFFFFFF));
 
        /* All other node statistics */
index 4ac944a..2e27415 100644 (file)
@@ -34,29 +34,13 @@ struct mt_match_s;
 typedef struct mt_match_s mt_match_t;
 struct mt_match_s
 {
-  time_t future;
-  time_t past;
+  cdtime_t future;
+  cdtime_t past;
 };
 
 /*
  * internal helper functions
  */
-static int mt_config_add_time_t (time_t *ret_value, /* {{{ */
-    oconfig_item_t *ci)
-{
-
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    ERROR ("timediff match: `%s' needs exactly one numeric argument.",
-        ci->key);
-    return (-1);
-  }
-
-  *ret_value = (time_t) ci->values[0].value.number;
-
-  return (0);
-} /* }}} int mt_config_add_time_t */
-
 static int mt_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
 {
   mt_match_t *m;
@@ -80,9 +64,9 @@ static int mt_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp ("Future", child->key) == 0)
-      status = mt_config_add_time_t (&m->future, child);
+      status = cf_util_get_cdtime (child, &m->future);
     else if (strcasecmp ("Past", child->key) == 0)
-      status = mt_config_add_time_t (&m->past, child);
+      status = cf_util_get_cdtime (child, &m->past);
     else
     {
       ERROR ("timediff match: The `%s' configuration option is not "
@@ -132,13 +116,13 @@ static int mt_match (const data_set_t __attribute__((unused)) *ds, /* {{{ */
     notification_meta_t __attribute__((unused)) **meta, void **user_data)
 {
   mt_match_t *m;
-  time_t now;
+  cdtime_t now;
 
   if ((user_data == NULL) || (*user_data == NULL))
     return (-1);
 
   m = *user_data;
-  now = time (NULL);
+  now = cdtime ();
 
   if (m->future != 0)
   {
index 73faa50..c57a831 100644 (file)
@@ -452,7 +452,6 @@ static void cmc_submit (const web_page_t *wp, const web_match_t *wm, /* {{{ */
 
   vl.values = values;
   vl.values_len = 1;
-  vl.time = time (NULL);
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "memcachec", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
index 4c9e6ad..48fa713 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * collectd - src/memcached.c, based on src/hddtemp.c
  * Copyright (C) 2007       Antony Dovgal
- * Copyright (C) 2007-2009  Florian Forster
+ * Copyright (C) 2007-2010  Florian Forster
  * Copyright (C) 2009       Doug MacEachern
  * Copyright (C) 2009       Franck Lombardi
  *
@@ -21,7 +21,7 @@
  *
  * Authors:
  *   Antony Dovgal <tony at daylessday dot org>
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Doug MacEachern <dougm at hyperic.com>
  *   Franck Lombardi
  **/
@@ -176,12 +176,14 @@ static int memcached_query_daemon (char *buffer, int buffer_size) /* {{{ */
                p.events = POLLIN | POLLERR | POLLHUP;
                p.revents = 0;
 
-               status = poll (&p, /* nfds = */ 1, /* timeout = */ 1000 * interval_g);
+               status = poll (&p, /* nfds = */ 1,
+                               /* timeout = */ CDTIME_T_TO_MS (interval_g));
                if (status <= 0)
                {
                        if (status == 0)
                        {
-                               ERROR ("memcached: poll(2) timed out after %i seconds.", interval_g);
+                               ERROR ("memcached: poll(2) timed out after %.3f seconds.",
+                                               CDTIME_T_TO_DOUBLE (interval_g));
                        }
                        else
                        {
@@ -271,13 +273,13 @@ static int memcached_config (const char *key, const char *value) /* {{{ */
 }
 /* }}} */
 
-static void submit_counter (const char *type, const char *type_inst,
-               counter_t value) /* {{{ */
+static void submit_derive (const char *type, const char *type_inst,
+               derive_t value) /* {{{ */
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = value;
+       values[0].derive = value;
 
        vl.values = values;
        vl.values_len = 1;
@@ -291,18 +293,17 @@ static void submit_counter (const char *type, const char *type_inst,
 } /* void memcached_submit_cmd */
 /* }}} */
 
-static void submit_counter2 (const char *type, const char *type_inst,
-               counter_t value0, counter_t value1) /* {{{ */
+static void submit_derive2 (const char *type, const char *type_inst,
+               derive_t value0, derive_t value1) /* {{{ */
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = value0;
-       values[1].counter = value1;
+       values[0].derive = value0;
+       values[1].derive = value1;
 
        vl.values = values;
        vl.values_len = 2;
-       vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@ -323,7 +324,6 @@ static void submit_gauge (const char *type, const char *type_inst,
 
        vl.values = values;
        vl.values_len = 1;
-       vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@ -345,7 +345,6 @@ static void submit_gauge2 (const char *type, const char *type_inst,
 
        vl.values = values;
        vl.values_len = 2;
-       vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@ -369,10 +368,10 @@ static int memcached_read (void) /* {{{ */
        gauge_t bytes_total = NAN;
        gauge_t hits = NAN;
        gauge_t gets = NAN;
-       counter_t rusage_user = 0;
-       counter_t rusage_syst = 0;
-       counter_t octets_rx = 0;
-       counter_t octets_tx = 0;
+       derive_t rusage_user = 0;
+       derive_t rusage_syst = 0;
+       derive_t octets_rx = 0;
+       derive_t octets_tx = 0;
 
        /* get data from daemon */
        if (memcached_query_daemon (buf, sizeof (buf)) < 0) {
@@ -457,7 +456,7 @@ static int memcached_read (void) /* {{{ */
                else if ((name_len > 4) && (strncmp (fields[1], "cmd_", 4) == 0))
                {
                        const char *name = fields[1] + 4;
-                       submit_counter ("memcached_command", name, atoll (fields[2]));
+                       submit_derive ("memcached_command", name, atoll (fields[2]));
                        if (strcmp (name, "get") == 0)
                                gets = atof (fields[2]);
                }
@@ -467,16 +466,16 @@ static int memcached_read (void) /* {{{ */
                 */
                else if (FIELD_IS ("get_hits"))
                {
-                       submit_counter ("memcached_ops", "hits", atoll (fields[2]));
+                       submit_derive ("memcached_ops", "hits", atoll (fields[2]));
                        hits = atof (fields[2]);
                }
                else if (FIELD_IS ("get_misses"))
                {
-                       submit_counter ("memcached_ops", "misses", atoll (fields[2]));
+                       submit_derive ("memcached_ops", "misses", atoll (fields[2]));
                }
                else if (FIELD_IS ("evictions"))
                {
-                       submit_counter ("memcached_ops", "evictions", atoll (fields[2]));
+                       submit_derive ("memcached_ops", "evictions", atoll (fields[2]));
                }
 
                /*
@@ -496,10 +495,10 @@ static int memcached_read (void) /* {{{ */
                submit_gauge2 ("df", "cache", bytes_used, bytes_total - bytes_used);
 
        if ((rusage_user != 0) || (rusage_syst != 0))
-               submit_counter2 ("ps_cputime", NULL, rusage_user, rusage_syst);
+               submit_derive2 ("ps_cputime", NULL, rusage_user, rusage_syst);
 
        if ((octets_rx != 0) || (octets_tx != 0))
-               submit_counter2 ("memcached_octets", NULL, octets_rx, octets_tx);
+               submit_derive2 ("memcached_octets", NULL, octets_rx, octets_tx);
 
        if (!isnan (gets) && !isnan (hits))
        {
index 40b6c57..cad4b2c 100644 (file)
@@ -3,17 +3,18 @@
  * Copyright (C) 2010  noris network AG
  *
  * 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; only version 2 of the License is applicable.
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; only version 2.1 of the License is
+ * applicable.
  *
  * 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.
+ * Lesser 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
+ * You should have received a copy of the GNU Lesser 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 Forster <octo at noris.net>
 
 #include <modbus/modbus.h>
 
+#ifndef LIBMODBUS_VERSION_CHECK
+/* Assume version 2.0.3 */
+# define LEGACY_LIBMODBUS 1
+#else
+/* Assume version 2.9.2 */
+#endif
+
 #ifndef MODBUS_TCP_DEFAULT_PORT
 # ifdef MODBUS_TCP_PORT
 #  define MODBUS_TCP_DEFAULT_PORT MODBUS_TCP_PORT
@@ -94,12 +102,16 @@ struct mb_host_s /* {{{ */
   char node[NI_MAXHOST];
   /* char service[NI_MAXSERV]; */
   int port;
-  int interval;
+  cdtime_t interval;
 
   mb_slave_t *slaves;
   size_t slaves_num;
 
+#if LEGACY_LIBMODBUS
   modbus_param_t connection;
+#else
+  modbus_t *connection;
+#endif
   _Bool is_connected;
   _Bool have_reconnected;
 }; /* }}} */
@@ -265,6 +277,8 @@ static float mb_register_to_float (uint16_t hi, uint16_t lo) /* {{{ */
   return (conv.f);
 } /* }}} float mb_register_to_float */
 
+#if LEGACY_LIBMODBUS
+/* Version 2.0.3 */
 static int mb_init_connection (mb_host_t *host) /* {{{ */
 {
   int status;
@@ -306,6 +320,57 @@ static int mb_init_connection (mb_host_t *host) /* {{{ */
   host->have_reconnected = 1;
   return (0);
 } /* }}} int mb_init_connection */
+/* #endif LEGACY_LIBMODBUS */
+
+#else /* if !LEGACY_LIBMODBUS */
+/* Version 2.9.2 */
+static int mb_init_connection (mb_host_t *host) /* {{{ */
+{
+  int status;
+
+  if (host == NULL)
+    return (EINVAL);
+
+  if (host->connection != NULL)
+    return (0);
+
+  /* Only reconnect once per interval. */
+  if (host->have_reconnected)
+    return (-1);
+
+  if ((host->port < 1) || (host->port > 65535))
+    host->port = MODBUS_TCP_DEFAULT_PORT;
+
+  DEBUG ("Modbus plugin: Trying to connect to \"%s\", port %i.",
+      host->node, host->port);
+
+  host->connection = modbus_new_tcp (host->node, host->port);
+  if (host->connection == NULL)
+  {
+    host->have_reconnected = 1;
+    ERROR ("Modbus plugin: Creating new Modbus/TCP object failed.");
+    return (-1);
+  }
+
+  modbus_set_debug (host->connection, 1);
+
+  /* We'll do the error handling ourselves. */
+  modbus_set_error_recovery (host->connection, 0);
+
+  status = modbus_connect (host->connection);
+  if (status != 0)
+  {
+    ERROR ("Modbus plugin: modbus_connect (%s, %i) failed with status %i.",
+        host->node, host->port, status);
+    modbus_free (host->connection);
+    host->connection = NULL;
+    return (status);
+  }
+
+  host->have_reconnected = 1;
+  return (0);
+} /* }}} int mb_init_connection */
+#endif /* !LEGACY_LIBMODBUS */
 
 #define CAST_TO_VALUE_T(ds,vt,raw) do { \
   if ((ds)->ds[0].type == DS_TYPE_COUNTER) \
@@ -360,22 +425,46 @@ static int mb_read_data (mb_host_t *host, mb_slave_t *slave, /* {{{ */
   else
     values_num = 1;
 
+#if LEGACY_LIBMODBUS
+  /* Version 2.0.3: Pass the connection struct as a pointer and pass the slave
+   * id to each call of "read_holding_registers". */
+# define modbus_read_registers(ctx, addr, nb, dest) \
+  read_holding_registers (&(ctx), slave->id, (addr), (nb), (dest))
+#else /* if !LEGACY_LIBMODBUS */
+  /* Version 2.9.2: Set the slave id once before querying the registers. */
+  status = modbus_set_slave (host->connection, slave->id);
+  if (status != 0)
+  {
+    ERROR ("Modbus plugin: modbus_set_slave (%i) failed with status %i.",
+        slave->id, status);
+    return (-1);
+  }
+#endif
+
   for (i = 0; i < 2; i++)
   {
-    status = read_holding_registers (&host->connection,
-        /* slave = */ slave->id, /* start_addr = */ data->register_base,
+    status = modbus_read_registers (host->connection,
+        /* start_addr = */ data->register_base,
         /* num_registers = */ values_num, /* buffer = */ values);
     if (status > 0)
       break;
 
     if (host->is_connected)
+    {
+#if LEGACY_LIBMODBUS
       modbus_close (&host->connection);
-    host->is_connected = 0;
+      host->is_connected = 0;
+#else
+      modbus_close (host->connection);
+      modbus_free (host->connection);
+      host->connection = NULL;
+#endif
+    }
 
     /* If we already tried reconnecting this round, give up. */
     if (host->have_reconnected)
     {
-      ERROR ("Modbus plugin: read_holding_registers (%s) failed. "
+      ERROR ("Modbus plugin: modbus_read_registers (%s) failed. "
           "Reconnecting has already been tried. Giving up.", host->host);
       return (-1);
     }
@@ -385,7 +474,7 @@ static int mb_read_data (mb_host_t *host, mb_slave_t *slave, /* {{{ */
     status = mb_init_connection (host);
     if (status != 0)
     {
-      ERROR ("Modbus plugin: read_holding_registers (%s) failed. "
+      ERROR ("Modbus plugin: modbus_read_registers (%s) failed. "
           "While trying to reconnect, connecting to \"%s\" failed. "
           "Giving up.",
           host->host, host->node);
@@ -399,7 +488,7 @@ static int mb_read_data (mb_host_t *host, mb_slave_t *slave, /* {{{ */
   } /* for (i = 0, 1) */
 
   DEBUG ("Modbus plugin: mb_read_data: Success! "
-      "read_holding_registers returned with status %i.", status);
+      "modbus_read_registers returned with status %i.", status);
 
   if (data->register_type == REG_TYPE_FLOAT)
   {
@@ -767,7 +856,7 @@ static int mb_config_add_host (oconfig_item_t *ci) /* {{{ */
         status = -1;
     }
     else if (strcasecmp ("Interval", child->key) == 0)
-      status = cf_util_get_int (child, &host->interval);
+      status = cf_util_get_cdtime (child, &host->interval);
     else if (strcasecmp ("Slave", child->key) == 0)
       /* Don't set status: Gracefully continue if a slave fails. */
       mb_config_add_slave (host, child);
@@ -793,21 +882,19 @@ static int mb_config_add_host (oconfig_item_t *ci) /* {{{ */
   {
     user_data_t ud;
     char name[1024];
-    struct timespec interval;
+    struct timespec interval = { 0, 0 };
 
     ud.data = host;
     ud.free_func = host_free;
 
     ssnprintf (name, sizeof (name), "modbus-%s", host->host);
 
-    interval.tv_nsec = 0;
-    if (host->interval > 0)
-      interval.tv_sec = host->interval;
-    else
-      interval.tv_sec = 0;
+    CDTIME_T_TO_TIMESPEC (host->interval, &interval);
 
     plugin_register_complex_read (/* group = */ NULL, name,
-        mb_read, (interval.tv_sec > 0) ? &interval : NULL, &ud);
+        /* callback = */ mb_read,
+        /* interval = */ (host->interval > 0) ? &interval : NULL,
+        &ud);
   }
   else
   {
index 69df7c7..32b352b 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/mysql.c
- * Copyright (C) 2006-2009  Florian octo Forster
+ * Copyright (C) 2006-2010  Florian octo Forster
  * Copyright (C) 2008       Mirko Buffoni
  * Copyright (C) 2009       Doug MacEachern
  * Copyright (C) 2009       Sebastian tokkee Harl
@@ -20,7 +20,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Mirko Buffoni <briareos at eswat.org>
  *   Doug MacEachern <dougm at hyperic.com>
  *   Sebastian tokkee Harl <sh at tokkee.org>
@@ -42,7 +42,6 @@
 
 struct mysql_database_s /* {{{ */
 {
-       /* instance == NULL  =>  legacy mode */
        char *instance;
        char *host;
        char *user;
@@ -51,12 +50,12 @@ struct mysql_database_s /* {{{ */
        char *socket;
        int   port;
 
-       int   master_stats;
-       int   slave_stats;
+       _Bool master_stats;
+       _Bool slave_stats;
 
-       int   slave_notif;
-       int   slave_io_running;
-       int   slave_sql_running;
+       _Bool slave_notif;
+       _Bool slave_io_running;
+       _Bool slave_sql_running;
 
        MYSQL *con;
        int    state;
@@ -98,88 +97,9 @@ static void mysql_database_free (void *arg) /* {{{ */
  *   </Database>
  * </Plugin>
  */
-
-static int mysql_config_set_string (char **ret_string, /* {{{ */
-                                   oconfig_item_t *ci)
-{
-       char *string;
-
-       if ((ci->values_num != 1)
-           || (ci->values[0].type != OCONFIG_TYPE_STRING))
-       {
-               WARNING ("mysql plugin: The `%s' config option "
-                        "needs exactly one string argument.", ci->key);
-               return (-1);
-       }
-
-       string = strdup (ci->values[0].value.string);
-       if (string == NULL)
-       {
-               ERROR ("mysql plugin: strdup failed.");
-               return (-1);
-       }
-
-       if (*ret_string != NULL)
-               free (*ret_string);
-       *ret_string = string;
-
-       return (0);
-} /* }}} int mysql_config_set_string */
-
-static int mysql_config_set_int (int *ret_int, /* {{{ */
-                                oconfig_item_t *ci)
-{
-       if ((ci->values_num != 1)
-           || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-       {
-               WARNING ("mysql plugin: The `%s' config option "
-                        "needs exactly one string argument.", ci->key);
-               return (-1);
-       }
-
-       *ret_int = ci->values[0].value.number;
-
-       return (0);
-} /* }}} int mysql_config_set_int */
-
-static int mysql_config_set_boolean (int *ret_boolean, /* {{{ */
-                               oconfig_item_t *ci)
-{
-       int status = 0;
-
-       if (ci->values_num != 1)
-               status = -1;
-
-       if (status == 0)
-       {
-               if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
-                       *ret_boolean = ci->values[0].value.boolean;
-               else if (ci->values[0].type == OCONFIG_TYPE_STRING)
-               {
-                       if (IS_TRUE (ci->values[0].value.string))
-                               *ret_boolean = 1;
-                       else if (IS_FALSE (ci->values[0].value.string))
-                               *ret_boolean = 0;
-                       else
-                               status = -1;
-               }
-               else
-                       status = -1;
-       }
-
-       if (status != 0)
-       {
-               WARNING ("mysql plugin: The `%s' config option "
-                       "needs exactly one boolean argument.", ci->key);
-               return (-1);
-       }
-       return (0);
-} /* }}} mysql_config_set_boolean */
-
-static int mysql_config (oconfig_item_t *ci) /* {{{ */
+static int mysql_config_database (oconfig_item_t *ci) /* {{{ */
 {
        mysql_database_t *db;
-       int plugin_block;
        int status = 0;
        int i;
 
@@ -211,28 +131,13 @@ static int mysql_config (oconfig_item_t *ci) /* {{{ */
        db->slave_io_running  = 1;
        db->slave_sql_running = 1;
 
-       plugin_block = 1;
-       if (strcasecmp ("Plugin", ci->key) == 0)
-       {
-               db->instance = NULL;
-       }
-       else if (strcasecmp ("Database", ci->key) == 0)
-       {
-               plugin_block = 0;
-               status = mysql_config_set_string (&db->instance, ci);
-               if (status != 0)
-               {
-                       sfree (db);
-                       return (status);
-               }
-               assert (db->instance != NULL);
-       }
-       else
+       status = cf_util_get_string (ci, &db->instance);
+       if (status != 0)
        {
-               ERROR ("mysql plugin: mysql_config: "
-                               "Invalid key: %s", ci->key);
-               return (-1);
+               sfree (db);
+               return (status);
        }
+       assert (db->instance != NULL);
 
        /* Fill the `mysql_database_t' structure.. */
        for (i = 0; i < ci->children_num; i++)
@@ -240,36 +145,30 @@ static int mysql_config (oconfig_item_t *ci) /* {{{ */
                oconfig_item_t *child = ci->children + i;
 
                if (strcasecmp ("Host", child->key) == 0)
-                       status = mysql_config_set_string (&db->host, child);
+                       status = cf_util_get_string (child, &db->host);
                else if (strcasecmp ("User", child->key) == 0)
-                       status = mysql_config_set_string (&db->user, child);
+                       status = cf_util_get_string (child, &db->user);
                else if (strcasecmp ("Password", child->key) == 0)
-                       status = mysql_config_set_string (&db->pass, child);
+                       status = cf_util_get_string (child, &db->pass);
                else if (strcasecmp ("Port", child->key) == 0)
-                       status = mysql_config_set_int (&db->port, child);
-               else if (strcasecmp ("Socket", child->key) == 0)
-                       status = mysql_config_set_string (&db->socket, child);
-               /* Check if we're currently handling the `Plugin' block. If so,
-                * handle `Database' _blocks_, too. */
-               else if ((plugin_block != 0)
-                               && (strcasecmp ("Database", child->key) == 0)
-                               && (child->children != NULL))
                {
-                       /* If `plugin_block > 1', there has been at least one
-                        * `Database' block */
-                       plugin_block++;
-                       status = mysql_config (child);
+                       status = cf_util_get_port_number (child);
+                       if (status > 0)
+                       {
+                               db->port = status;
+                               status = 0;
+                       }
                }
-               /* Now handle ordinary `Database' options (without children) */
-               else if ((strcasecmp ("Database", child->key) == 0)
-                               && (child->children == NULL))
-                       status = mysql_config_set_string (&db->database, child);
+               else if (strcasecmp ("Socket", child->key) == 0)
+                       status = cf_util_get_string (child, &db->socket);
+               else if (strcasecmp ("Database", child->key) == 0)
+                       status = cf_util_get_string (child, &db->database);
                else if (strcasecmp ("MasterStats", child->key) == 0)
-                       status = mysql_config_set_boolean (&db->master_stats, child);
+                       status = cf_util_get_boolean (child, &db->master_stats);
                else if (strcasecmp ("SlaveStats", child->key) == 0)
-                       status = mysql_config_set_boolean (&db->slave_stats, child);
+                       status = cf_util_get_boolean (child, &db->slave_stats);
                else if (strcasecmp ("SlaveNotifications", child->key) == 0)
-                       status = mysql_config_set_boolean (&db->slave_notif, child);
+                       status = cf_util_get_boolean (child, &db->slave_notif);
                else
                {
                        WARNING ("mysql plugin: Option `%s' not allowed here.", child->key);
@@ -280,49 +179,6 @@ static int mysql_config (oconfig_item_t *ci) /* {{{ */
                        break;
        }
 
-       /* Check if there were any `Database' blocks. */
-       if (plugin_block > 1)
-       {
-               /* There were connection blocks. Don't use any legacy stuff. */
-               if ((db->host != NULL)
-                       || (db->user != NULL)
-                       || (db->pass != NULL)
-                       || (db->database != NULL)
-                       || (db->socket != NULL)
-                       || (db->port != 0))
-               {
-                       WARNING ("mysql plugin: At least one <Database> "
-                                       "block has been found. The legacy "
-                                       "configuration will be ignored.");
-               }
-               mysql_database_free (db);
-               return (0);
-       }
-       else if (plugin_block != 0)
-       {
-               WARNING ("mysql plugin: You're using the legacy "
-                               "configuration options. Please consider "
-                               "updating your configuration!");
-       }
-
-       /* Check that all necessary options have been given. */
-       while (status == 0)
-       {
-               /* Zero is allowed and automatically handled by
-                * `mysql_real_connect'. */
-               if ((db->port < 0) || (db->port > 65535))
-               {
-                       ERROR ("mysql plugin: Database %s: Port number out "
-                                       "of range: %i",
-                                       (db->instance != NULL)
-                                       ? db->instance
-                                       : "<legacy>",
-                                       db->port);
-                       status = -1;
-               }
-               break;
-       } /* while (status == 0) */
-
        /* If all went well, register this database for reading */
        if (status == 0)
        {
@@ -336,9 +192,9 @@ static int mysql_config (oconfig_item_t *ci) /* {{{ */
                ud.data = (void *) db;
                ud.free_func = mysql_database_free;
 
-               if (db->database != NULL)
+               if (db->instance != NULL)
                        ssnprintf (cb_name, sizeof (cb_name), "mysql-%s",
-                                       db->database);
+                                       db->instance);
                else
                        sstrncpy (cb_name, "mysql", sizeof (cb_name));
 
@@ -353,6 +209,28 @@ static int mysql_config (oconfig_item_t *ci) /* {{{ */
        }
 
        return (0);
+} /* }}} int mysql_config_database */
+
+static int mysql_config (oconfig_item_t *ci) /* {{{ */
+{
+       int i;
+
+       if (ci == NULL)
+               return (EINVAL);
+
+       /* Fill the `mysql_database_t' structure.. */
+       for (i = 0; i < ci->children_num; i++)
+       {
+               oconfig_item_t *child = ci->children + i;
+
+               if (strcasecmp ("Database", child->key) == 0)
+                       mysql_config_database (child);
+               else
+                       WARNING ("mysql plugin: Option \"%s\" not allowed here.",
+                                       child->key);
+       }
+
+       return (0);
 } /* }}} int mysql_config */
 
 /* }}} End of configuration handling functions */
@@ -364,10 +242,10 @@ static MYSQL *getconnection (mysql_database_t *db)
                int err;
                if ((err = mysql_ping (db->con)) != 0)
                {
-                       WARNING ("mysql_ping failed for %s: %s",
-                                       (db->instance != NULL)
-                                       ? db->instance
-                                       : "<legacy>",
+                       /* Assured by "mysql_config_database" */
+                       assert (db->instance != NULL);
+                       WARNING ("mysql_ping failed for instance \"%s\": %s",
+                                       db->instance,
                                        mysql_error (db->con));
                        db->state = 0;
                }
@@ -411,29 +289,13 @@ static MYSQL *getconnection (mysql_database_t *db)
 
 static void set_host (mysql_database_t *db, char *buf, size_t buflen)
 {
-       /* XXX legacy mode - use hostname_g */
-       if (db->instance == NULL)
+       if ((db->host == NULL)
+                       || (strcmp ("", db->host) == 0)
+                       || (strcmp ("localhost", db->host) == 0))
                sstrncpy (buf, hostname_g, buflen);
        else
-       {
-               if ((db->host == NULL)
-                               || (strcmp ("", db->host) == 0)
-                               || (strcmp ("localhost", db->host) == 0))
-                       sstrncpy (buf, hostname_g, buflen);
-               else
-                       sstrncpy (buf, db->host, buflen);
-       }
-}
-
-static void set_plugin_instance (mysql_database_t *db,
-               char *buf, size_t buflen)
-{
-       /* XXX legacy mode - no plugin_instance */
-       if (db->instance == NULL)
-               sstrncpy (buf, "", buflen);
-       else
-               sstrncpy (buf, db->instance, buflen);
-}
+               sstrncpy (buf, db->host, buflen);
+} /* void set_host */
 
 static void submit (const char *type, const char *type_instance,
                value_t *values, size_t values_len, mysql_database_t *db)
@@ -446,7 +308,10 @@ static void submit (const char *type, const char *type_instance,
        set_host (db, vl.host, sizeof (vl.host));
 
        sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
-       set_plugin_instance (db, vl.plugin_instance, sizeof (vl.plugin_instance));
+
+       /* Assured by "mysql_config_database" */
+       assert (db->instance != NULL);
+       sstrncpy (vl.plugin_instance, db->instance, sizeof (vl.plugin_instance));
 
        sstrncpy (vl.type, type, sizeof (vl.type));
        if (type_instance != NULL)
@@ -456,11 +321,11 @@ static void submit (const char *type, const char *type_instance,
 } /* submit */
 
 static void counter_submit (const char *type, const char *type_instance,
-               counter_t value, mysql_database_t *db)
+               derive_t value, mysql_database_t *db)
 {
        value_t values[1];
 
-       values[0].counter = value;
+       values[0].derive = value;
        submit (type, type_instance, values, STATIC_ARRAY_SIZE (values), db);
 } /* void counter_submit */
 
@@ -473,40 +338,21 @@ static void gauge_submit (const char *type, const char *type_instance,
        submit (type, type_instance, values, STATIC_ARRAY_SIZE (values), db);
 } /* void gauge_submit */
 
-static void qcache_submit (counter_t hits, counter_t inserts,
-               counter_t not_cached, counter_t lowmem_prunes,
-               gauge_t queries_in_cache, mysql_database_t *db)
+static void derive_submit (const char *type, const char *type_instance,
+               derive_t value, mysql_database_t *db)
 {
-       value_t values[5];
-
-       values[0].counter = hits;
-       values[1].counter = inserts;
-       values[2].counter = not_cached;
-       values[3].counter = lowmem_prunes;
-       values[4].gauge   = queries_in_cache;
-
-       submit ("mysql_qcache", NULL, values, STATIC_ARRAY_SIZE (values), db);
-} /* void qcache_submit */
-
-static void threads_submit (gauge_t running, gauge_t connected, gauge_t cached,
-               counter_t created, mysql_database_t *db)
-{
-       value_t values[4];
-
-       values[0].gauge   = running;
-       values[1].gauge   = connected;
-       values[2].gauge   = cached;
-       values[3].counter = created;
+       value_t values[1];
 
-       submit ("mysql_threads", NULL, values, STATIC_ARRAY_SIZE (values), db);
-} /* void threads_submit */
+       values[0].derive = value;
+       submit (type, type_instance, values, STATIC_ARRAY_SIZE (values), db);
+} /* void derive_submit */
 
-static void traffic_submit (counter_t rx, counter_t tx, mysql_database_t *db)
+static void traffic_submit (derive_t rx, derive_t tx, mysql_database_t *db)
 {
        value_t values[2];
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        submit ("mysql_octets", NULL, values, STATIC_ARRAY_SIZE (values), db);
 } /* void traffic_submit */
@@ -639,7 +485,7 @@ static int mysql_read_slave_stats (mysql_database_t *db, MYSQL *con)
 
        if (db->slave_notif)
        {
-               notification_t n = { 0, time (NULL), "", "",
+               notification_t n = { 0, cdtime (), "", "",
                        "mysql", "", "time_offset", "", NULL };
 
                char *io, *sql;
@@ -648,8 +494,10 @@ static int mysql_read_slave_stats (mysql_database_t *db, MYSQL *con)
                sql = row[SLAVE_SQL_RUNNING_IDX];
 
                set_host (db, n.host, sizeof (n.host));
-               set_plugin_instance (db,
-                               n.plugin_instance, sizeof (n.plugin_instance));
+
+               /* Assured by "mysql_config_database" */
+               assert (db->instance != NULL);
+               sstrncpy (n.plugin_instance, db->instance, sizeof (n.plugin_instance));
 
                if (((io == NULL) || (strcasecmp (io, "yes") != 0))
                                && (db->slave_io_running))
@@ -708,16 +556,16 @@ static int mysql_read (user_data_t *ud)
        MYSQL_ROW  row;
        char      *query;
 
-       unsigned long long qcache_hits          = 0ULL;
-       unsigned long long qcache_inserts       = 0ULL;
-       unsigned long long qcache_not_cached    = 0ULL;
-       unsigned long long qcache_lowmem_prunes = 0ULL;
-       int qcache_queries_in_cache = -1;
+       derive_t qcache_hits          = 0;
+       derive_t qcache_inserts       = 0;
+       derive_t qcache_not_cached    = 0;
+       derive_t qcache_lowmem_prunes = 0;
+       gauge_t qcache_queries_in_cache = NAN;
 
-       int threads_running   = -1;
-       int threads_connected = -1;
-       int threads_cached    = -1;
-       unsigned long long threads_created = 0ULL;
+       gauge_t threads_running   = NAN;
+       gauge_t threads_connected = NAN;
+       gauge_t threads_cached    = NAN;
+       derive_t threads_created = 0;
 
        unsigned long long traffic_incoming = 0ULL;
        unsigned long long traffic_outgoing = 0ULL;
@@ -776,15 +624,15 @@ static int mysql_read (user_data_t *ud)
                                                strlen ("Qcache_")) == 0)
                {
                        if (strcmp (key, "Qcache_hits") == 0)
-                               qcache_hits = val;
+                               qcache_hits = (derive_t) val;
                        else if (strcmp (key, "Qcache_inserts") == 0)
-                               qcache_inserts = val;
+                               qcache_inserts = (derive_t) val;
                        else if (strcmp (key, "Qcache_not_cached") == 0)
-                               qcache_not_cached = val;
+                               qcache_not_cached = (derive_t) val;
                        else if (strcmp (key, "Qcache_lowmem_prunes") == 0)
-                               qcache_lowmem_prunes = val;
+                               qcache_lowmem_prunes = (derive_t) val;
                        else if (strcmp (key, "Qcache_queries_in_cache") == 0)
-                               qcache_queries_in_cache = (int) val;
+                               qcache_queries_in_cache = (gauge_t) val;
                }
                else if (strncmp (key, "Bytes_", 
                                        strlen ("Bytes_")) == 0)
@@ -798,13 +646,13 @@ static int mysql_read (user_data_t *ud)
                                                strlen ("Threads_")) == 0)
                {
                        if (strcmp (key, "Threads_running") == 0)
-                               threads_running = (int) val;
+                               threads_running = (gauge_t) val;
                        else if (strcmp (key, "Threads_connected") == 0)
-                               threads_connected = (int) val;
+                               threads_connected = (gauge_t) val;
                        else if (strcmp (key, "Threads_cached") == 0)
-                               threads_cached = (int) val;
+                               threads_cached = (gauge_t) val;
                        else if (strcmp (key, "Threads_created") == 0)
-                               threads_created = val;
+                               threads_created = (derive_t) val;
                }
                else if (strncmp (key, "Table_locks_",
                                        strlen ("Table_locks_")) == 0)
@@ -816,16 +664,36 @@ static int mysql_read (user_data_t *ud)
        }
        mysql_free_result (res); res = NULL;
 
-       if ((qcache_hits != 0ULL)
-                       || (qcache_inserts != 0ULL)
-                       || (qcache_not_cached != 0ULL)
-                       || (qcache_lowmem_prunes != 0ULL))
-               qcache_submit (qcache_hits, qcache_inserts, qcache_not_cached,
-                              qcache_lowmem_prunes, qcache_queries_in_cache, db);
+       if ((qcache_hits != 0)
+                       || (qcache_inserts != 0)
+                       || (qcache_not_cached != 0)
+                       || (qcache_lowmem_prunes != 0))
+       {
+               derive_submit ("cache_result", "qcache-hits",
+                               qcache_hits, db);
+               derive_submit ("cache_result", "qcache-inserts",
+                               qcache_inserts, db);
+               derive_submit ("cache_result", "qcache-not_cached",
+                               qcache_not_cached, db);
+               derive_submit ("cache_result", "qcache-prunes",
+                               qcache_lowmem_prunes, db);
+
+               gauge_submit ("cache_size", "qcache",
+                               qcache_queries_in_cache, db);
+       }
 
-       if (threads_created != 0ULL)
-               threads_submit (threads_running, threads_connected,
-                               threads_cached, threads_created, db);
+       if (threads_created != 0)
+       {
+               gauge_submit ("threads", "running",
+                               threads_running, db);
+               gauge_submit ("threads", "connected",
+                               threads_connected, db);
+               gauge_submit ("threads", "cached",
+                               threads_cached, db);
+
+               derive_submit ("total_threads", "created",
+                               threads_created, db);
+       }
 
        traffic_submit  (traffic_incoming, traffic_outgoing, db);
 
index c9ff6b5..f7bc04d 100644 (file)
@@ -38,8 +38,8 @@ typedef void service_handler_t(host_config_t *host, na_elem_t *result, void *dat
 
 struct cna_interval_s
 {
-       time_t interval;
-       time_t last_read;
+       cdtime_t interval;
+       cdtime_t last_read;
 };
 typedef struct cna_interval_s cna_interval_t;
 
@@ -79,7 +79,7 @@ typedef struct {
        cna_interval_t interval;
        na_elem_t *query;
 
-       time_t timestamp;
+       cdtime_t timestamp;
        uint64_t name_cache_hit;
        uint64_t name_cache_miss;
        uint64_t find_dir_hit;
@@ -104,7 +104,7 @@ typedef struct {
 typedef struct disk_s {
        char *name;
        uint32_t flags;
-       time_t timestamp;
+       cdtime_t timestamp;
        uint64_t disk_busy;
        uint64_t base_for_disk_busy;
        double disk_busy_percent;
@@ -153,7 +153,7 @@ typedef struct data_volume_perf_s data_volume_perf_t;
 struct data_volume_perf_s {
        char *name;
        uint32_t flags;
-       time_t timestamp;
+       cdtime_t timestamp;
 
        uint64_t read_bytes;
        uint64_t write_bytes;
@@ -242,7 +242,7 @@ struct host_config_s {
        int port;
        char *username;
        char *password;
-       int interval;
+       cdtime_t interval;
 
        na_server_t *srv;
        cfg_wafl_t *cfg_wafl;
@@ -566,7 +566,7 @@ static int submit_values (const char *host, /* {{{ */
                const char *plugin_inst,
                const char *type, const char *type_inst,
                value_t *values, int values_len,
-               time_t timestamp, int interval)
+               cdtime_t timestamp, cdtime_t interval)
 {
        value_list_t vl = VALUE_LIST_INIT;
 
@@ -593,33 +593,34 @@ static int submit_values (const char *host, /* {{{ */
        return (plugin_dispatch_values (&vl));
 } /* }}} int submit_uint64 */
 
-static int submit_two_counters (const char *host, const char *plugin_inst, /* {{{ */
-               const char *type, const char *type_inst, counter_t val0, counter_t val1,
-               time_t timestamp, int interval)
+static int submit_two_derive (const char *host, const char *plugin_inst, /* {{{ */
+               const char *type, const char *type_inst, derive_t val0, derive_t val1,
+               cdtime_t timestamp, cdtime_t interval)
 {
        value_t values[2];
 
-       values[0].counter = val0;
-       values[1].counter = val1;
+       values[0].derive = val0;
+       values[1].derive = val1;
 
        return (submit_values (host, plugin_inst, type, type_inst,
                                values, 2, timestamp, interval));
-} /* }}} int submit_two_counters */
+} /* }}} int submit_two_derive */
 
-static int submit_counter (const char *host, const char *plugin_inst, /* {{{ */
-               const char *type, const char *type_inst, counter_t counter, time_t timestamp, int interval)
+static int submit_derive (const char *host, const char *plugin_inst, /* {{{ */
+               const char *type, const char *type_inst, derive_t counter,
+               cdtime_t timestamp, cdtime_t interval)
 {
        value_t v;
 
-       v.counter = counter;
+       v.derive = counter;
 
        return (submit_values (host, plugin_inst, type, type_inst,
                                &v, 1, timestamp, interval));
-} /* }}} int submit_counter */
+} /* }}} int submit_derive */
 
 static int submit_two_gauge (const char *host, const char *plugin_inst, /* {{{ */
                const char *type, const char *type_inst, gauge_t val0, gauge_t val1,
-               time_t timestamp, int interval)
+               cdtime_t timestamp, cdtime_t interval)
 {
        value_t values[2];
 
@@ -631,7 +632,8 @@ static int submit_two_gauge (const char *host, const char *plugin_inst, /* {{{ *
 } /* }}} int submit_two_gauge */
 
 static int submit_double (const char *host, const char *plugin_inst, /* {{{ */
-               const char *type, const char *type_inst, double d, time_t timestamp, int interval)
+               const char *type, const char *type_inst, double d,
+               cdtime_t timestamp, cdtime_t interval)
 {
        value_t v;
 
@@ -650,8 +652,8 @@ static int submit_cache_ratio (const char *host, /* {{{ */
                uint64_t new_misses,
                uint64_t old_hits,
                uint64_t old_misses,
-               time_t timestamp,
-               int interval)
+               cdtime_t timestamp,
+               cdtime_t interval)
 {
        value_t v;
 
@@ -742,16 +744,16 @@ static int submit_volume_perf_data (const char *hostname, /* {{{ */
        if (HAS_ALL_FLAGS (old_data->flags, CFG_VOLUME_PERF_IO)
                        && HAS_ALL_FLAGS (new_data->flags, HAVE_VOLUME_PERF_BYTES_READ | HAVE_VOLUME_PERF_BYTES_WRITE))
        {
-               submit_two_counters (hostname, plugin_instance, "disk_octets", /* type instance = */ NULL,
-                               (counter_t) new_data->read_bytes, (counter_t) new_data->write_bytes, new_data->timestamp, interval);
+               submit_two_derive (hostname, plugin_instance, "disk_octets", /* type instance = */ NULL,
+                               (derive_t) new_data->read_bytes, (derive_t) new_data->write_bytes, new_data->timestamp, interval);
        }
 
        /* Check for and submit disk-operations values */
        if (HAS_ALL_FLAGS (old_data->flags, CFG_VOLUME_PERF_OPS)
                        && HAS_ALL_FLAGS (new_data->flags, HAVE_VOLUME_PERF_OPS_READ | HAVE_VOLUME_PERF_OPS_WRITE))
        {
-               submit_two_counters (hostname, plugin_instance, "disk_ops", /* type instance = */ NULL,
-                               (counter_t) new_data->read_ops, (counter_t) new_data->write_ops, new_data->timestamp, interval);
+               submit_two_derive (hostname, plugin_instance, "disk_ops", /* type instance = */ NULL,
+                               (derive_t) new_data->read_ops, (derive_t) new_data->write_ops, new_data->timestamp, interval);
        }
 
        /* Check for, calculate and submit disk-latency values */
@@ -816,6 +818,16 @@ static int submit_volume_perf_data (const char *hostname, /* {{{ */
        return (0);
 } /* }}} int submit_volume_perf_data */
 
+static cdtime_t cna_child_get_cdtime (na_elem_t *data) /* {{{ */
+{
+       time_t t;
+
+       t = (time_t) na_child_get_uint64 (data, "timestamp", /* default = */ 0);
+
+       return (TIME_T_TO_CDTIME_T (t));
+} /* }}} cdtime_t cna_child_get_cdtime */
+
+
 /* 
  * Query functions
  *
@@ -835,7 +847,7 @@ static int cna_handle_wafl_data (const char *hostname, cfg_wafl_t *cfg_wafl, /*
 
        memset (&perf_data, 0, sizeof (perf_data));
        
-       perf_data.timestamp = (time_t) na_child_get_uint64 (data, "timestamp", 0);
+       perf_data.timestamp = cna_child_get_cdtime (data);
 
        instances = na_elem_child(na_elem_child (data, "instances"), "instance-data");
        if (instances == NULL)
@@ -950,7 +962,7 @@ static int cna_query_wafl (host_config_t *host) /* {{{ */
 {
        na_elem_t *data;
        int status;
-       time_t now;
+       cdtime_t now;
 
        if (host == NULL)
                return (EINVAL);
@@ -959,7 +971,7 @@ static int cna_query_wafl (host_config_t *host) /* {{{ */
        if (host->cfg_wafl == NULL)
                return (0);
 
-       now = time (NULL);
+       now = cdtime ();
        if ((host->cfg_wafl->interval.interval + host->cfg_wafl->interval.last_read) > now)
                return (0);
 
@@ -988,9 +1000,9 @@ static int cna_query_wafl (host_config_t *host) /* {{{ */
 
 /* Data corresponding to <Disks /> */
 static int cna_handle_disk_data (const char *hostname, /* {{{ */
-               cfg_disk_t *cfg_disk, na_elem_t *data, int interval)
+               cfg_disk_t *cfg_disk, na_elem_t *data, cdtime_t interval)
 {
-       time_t timestamp;
+       cdtime_t timestamp;
        na_elem_t *instances;
        na_elem_t *instance;
        na_elem_iter_t instance_iter;
@@ -999,7 +1011,7 @@ static int cna_handle_disk_data (const char *hostname, /* {{{ */
        if ((cfg_disk == NULL) || (data == NULL))
                return (EINVAL);
        
-       timestamp = (time_t) na_child_get_uint64(data, "timestamp", 0);
+       timestamp = cna_child_get_cdtime (data);
 
        instances = na_elem_child (data, "instances");
        if (instances == NULL)
@@ -1144,7 +1156,7 @@ static int cna_query_disk (host_config_t *host) /* {{{ */
 {
        na_elem_t *data;
        int status;
-       time_t now;
+       cdtime_t now;
 
        if (host == NULL)
                return (EINVAL);
@@ -1154,7 +1166,7 @@ static int cna_query_disk (host_config_t *host) /* {{{ */
        if (host->cfg_disk == NULL)
                return (0);
 
-       now = time (NULL);
+       now = cdtime ();
        if ((host->cfg_disk->interval.interval + host->cfg_disk->interval.last_read) > now)
                return (0);
 
@@ -1183,14 +1195,14 @@ static int cna_query_disk (host_config_t *host) /* {{{ */
 
 /* Data corresponding to <VolumePerf /> */
 static int cna_handle_volume_perf_data (const char *hostname, /* {{{ */
-               cfg_volume_perf_t *cvp, na_elem_t *data, int interval)
+               cfg_volume_perf_t *cvp, na_elem_t *data, cdtime_t interval)
 {
-       time_t timestamp;
+       cdtime_t timestamp;
        na_elem_t *elem_instances;
        na_elem_iter_t iter_instances;
        na_elem_t *elem_instance;
        
-       timestamp = (time_t) na_child_get_uint64(data, "timestamp", 0);
+       timestamp = cna_child_get_cdtime (data);
 
        elem_instances = na_elem_child(data, "instances");
        if (elem_instances == NULL)
@@ -1315,7 +1327,7 @@ static int cna_query_volume_perf (host_config_t *host) /* {{{ */
 {
        na_elem_t *data;
        int status;
-       time_t now;
+       cdtime_t now;
 
        if (host == NULL)
                return (EINVAL);
@@ -1325,7 +1337,7 @@ static int cna_query_volume_perf (host_config_t *host) /* {{{ */
        if (host->cfg_volume_perf == NULL)
                return (0);
 
-       now = time (NULL);
+       now = cdtime ();
        if ((host->cfg_volume_perf->interval.interval + host->cfg_volume_perf->interval.last_read) > now)
                return (0);
 
@@ -1444,7 +1456,7 @@ static int cna_change_volume_status (const char *hostname, /* {{{ */
        notification_t n;
 
        memset (&n, 0, sizeof (&n));
-       n.time = time (NULL);
+       n.time = cdtime ();
        sstrncpy (n.host, hostname, sizeof (n.host));
        sstrncpy (n.plugin, "netapp", sizeof (n.plugin));
        sstrncpy (n.plugin_instance, v->name, sizeof (n.plugin_instance));
@@ -1682,7 +1694,7 @@ static int cna_query_volume_usage (host_config_t *host) /* {{{ */
 {
        na_elem_t *data;
        int status;
-       time_t now;
+       cdtime_t now;
 
        if (host == NULL)
                return (EINVAL);
@@ -1692,7 +1704,7 @@ static int cna_query_volume_usage (host_config_t *host) /* {{{ */
        if (host->cfg_volume_usage == NULL)
                return (0);
 
-       now = time (NULL);
+       now = cdtime ();
        if ((host->cfg_volume_usage->interval.interval + host->cfg_volume_usage->interval.last_read) > now)
                return (0);
 
@@ -1727,15 +1739,15 @@ static int cna_handle_system_data (const char *hostname, /* {{{ */
        na_elem_t *counter;
        na_elem_iter_t counter_iter;
 
-       counter_t disk_read = 0, disk_written = 0;
-       counter_t net_recv = 0, net_sent = 0;
-       counter_t cpu_busy = 0, cpu_total = 0;
+       derive_t disk_read = 0, disk_written = 0;
+       derive_t net_recv = 0, net_sent = 0;
+       derive_t cpu_busy = 0, cpu_total = 0;
        uint32_t counter_flags = 0;
 
        const char *instance;
-       time_t timestamp;
+       cdtime_t timestamp;
        
-       timestamp = (time_t) na_child_get_uint64 (data, "timestamp", 0);
+       timestamp = cna_child_get_cdtime (data);
 
        instances = na_elem_child(na_elem_child (data, "instances"), "instance-data");
        if (instances == NULL)
@@ -1772,47 +1784,47 @@ static int cna_handle_system_data (const char *hostname, /* {{{ */
                        continue;
 
                if (!strcmp(name, "disk_data_read")) {
-                       disk_read = (counter_t) (value * 1024);
+                       disk_read = (derive_t) (value * 1024);
                        counter_flags |= 0x01;
                } else if (!strcmp(name, "disk_data_written")) {
-                       disk_written = (counter_t) (value * 1024);
+                       disk_written = (derive_t) (value * 1024);
                        counter_flags |= 0x02;
                } else if (!strcmp(name, "net_data_recv")) {
-                       net_recv = (counter_t) (value * 1024);
+                       net_recv = (derive_t) (value * 1024);
                        counter_flags |= 0x04;
                } else if (!strcmp(name, "net_data_sent")) {
-                       net_sent = (counter_t) (value * 1024);
+                       net_sent = (derive_t) (value * 1024);
                        counter_flags |= 0x08;
                } else if (!strcmp(name, "cpu_busy")) {
-                       cpu_busy = (counter_t) value;
+                       cpu_busy = (derive_t) value;
                        counter_flags |= 0x10;
                } else if (!strcmp(name, "cpu_elapsed_time")) {
-                       cpu_total = (counter_t) value;
+                       cpu_total = (derive_t) value;
                        counter_flags |= 0x20;
                } else if ((cfg_system->flags & CFG_SYSTEM_OPS)
                                && (value > 0) && (strlen(name) > 4)
                                && (!strcmp(name + strlen(name) - 4, "_ops"))) {
-                       submit_counter (hostname, instance, "disk_ops_complex", name,
-                                       (counter_t) value, timestamp, interval);
+                       submit_derive (hostname, instance, "disk_ops_complex", name,
+                                       (derive_t) value, timestamp, interval);
                }
        } /* for (counter) */
 
        if ((cfg_system->flags & CFG_SYSTEM_DISK)
                        && (HAS_ALL_FLAGS (counter_flags, 0x01 | 0x02)))
-               submit_two_counters (hostname, instance, "disk_octets", NULL,
+               submit_two_derive (hostname, instance, "disk_octets", NULL,
                                disk_read, disk_written, timestamp, interval);
                                
        if ((cfg_system->flags & CFG_SYSTEM_NET)
                        && (HAS_ALL_FLAGS (counter_flags, 0x04 | 0x08)))
-               submit_two_counters (hostname, instance, "if_octets", NULL,
+               submit_two_derive (hostname, instance, "if_octets", NULL,
                                net_recv, net_sent, timestamp, interval);
 
        if ((cfg_system->flags & CFG_SYSTEM_CPU)
                        && (HAS_ALL_FLAGS (counter_flags, 0x10 | 0x20)))
        {
-               submit_counter (hostname, instance, "cpu", "system",
+               submit_derive (hostname, instance, "cpu", "system",
                                cpu_busy, timestamp, interval);
-               submit_counter (hostname, instance, "cpu", "idle",
+               submit_derive (hostname, instance, "cpu", "idle",
                                cpu_total - cpu_busy, timestamp, interval);
        }
 
@@ -1842,7 +1854,7 @@ static int cna_query_system (host_config_t *host) /* {{{ */
 {
        na_elem_t *data;
        int status;
-       time_t now;
+       cdtime_t now;
 
        if (host == NULL)
                return (EINVAL);
@@ -1851,7 +1863,7 @@ static int cna_query_system (host_config_t *host) /* {{{ */
        if (host->cfg_system == NULL)
                return (0);
 
-       now = time (NULL);
+       now = cdtime ();
        if ((host->cfg_system->interval.interval + host->cfg_system->interval.last_read) > now)
                return (0);
 
@@ -1908,23 +1920,12 @@ static int cna_config_bool_to_flag (const oconfig_item_t *ci, /* {{{ */
 static int cna_config_get_interval (const oconfig_item_t *ci, /* {{{ */
                cna_interval_t *out_interval)
 {
-       time_t tmp;
-
-       if ((ci == NULL) || (out_interval == NULL))
-               return (EINVAL);
-
-       if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-       {
-               WARNING ("netapp plugin: The `Interval' option needs exactly one numeric argument.");
-               return (-1);
-       }
+       cdtime_t tmp = 0;
+       int status;
 
-       tmp = (time_t) (ci->values[0].value.number + .5);
-       if (tmp < 1)
-       {
-               WARNING ("netapp plugin: The `Interval' option needs a positive integer argument.");
-               return (-1);
-       }
+       status = cf_util_get_cdtime (ci, &tmp);
+       if (status != 0)
+               return (status);
 
        out_interval->interval = tmp;
        out_interval->last_read = 0;
@@ -2424,11 +2425,7 @@ static host_config_t *cna_config_host (const oconfig_item_t *ci) /* {{{ */
                } else if (!strcasecmp(item->key, "Password")) {
                        status = cf_util_get_string (item, &host->password);
                } else if (!strcasecmp(item->key, "Interval")) {
-                       if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_NUMBER || item->values[0].value.number != (int) item->values[0].value.number || item->values[0].value.number < 2) {
-                               WARNING("netapp plugin: \"Interval\" of host %s needs exactly one integer argument.", ci->values[0].value.string);
-                               continue;
-                       }
-                       host->interval = item->values[0].value.number;
+                       status = cf_util_get_cdtime (item, &host->interval);
                } else if (!strcasecmp(item->key, "WAFL")) {
                        cna_config_wafl(host, item);
                } else if (!strcasecmp(item->key, "Disks")) {
@@ -2587,8 +2584,7 @@ static int cna_config (oconfig_item_t *ci) { /* {{{ */
 
                        ssnprintf (cb_name, sizeof (cb_name), "netapp-%s", host->name);
 
-                       memset (&interval, 0, sizeof (interval));
-                       interval.tv_sec = host->interval;
+                       CDTIME_T_TO_TIMESPEC (host->interval, &interval);
 
                        memset (&ud, 0, sizeof (ud));
                        ud.data = host;
index bac8757..39536d9 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/netlink.c
- * Copyright (C) 2007  Florian octo Forster
+ * Copyright (C) 2007-2010  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
@@ -161,12 +161,12 @@ static int check_ignorelist (const char *dev,
 } /* int check_ignorelist */
 
 static void submit_one (const char *dev, const char *type,
-    const char *type_instance, counter_t value)
+    const char *type_instance, derive_t value)
 {
   value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].counter = value;
+  values[0].derive = value;
 
   vl.values = values;
   vl.values_len = 1;
@@ -183,13 +183,13 @@ static void submit_one (const char *dev, const char *type,
 
 static void submit_two (const char *dev, const char *type,
     const char *type_instance,
-    counter_t rx, counter_t tx)
+    derive_t rx, derive_t tx)
 {
   value_t values[2];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].counter = rx;
-  values[1].counter = tx;
+  values[0].derive = rx;
+  values[1].derive = tx;
 
   vl.values = values;
   vl.values_len = 2;
index d6e0dc0..1f8fe0a 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/network.c
- * Copyright (C) 2005-2009  Florian octo Forster
+ * Copyright (C) 2005-2010  Florian octo Forster
  * Copyright (C) 2009       Aman Gupta
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -271,7 +271,8 @@ typedef struct receive_list_entry_s receive_list_entry_t;
  * Private variables
  */
 static int network_config_ttl = 0;
-static size_t network_config_packet_size = 1024;
+/* Ethernet - (IPv6 + UDP) = 1500 - (40 + 8) = 1452 */
+static size_t network_config_packet_size = 1452;
 static int network_config_forward = 0;
 static int network_config_stats = 0;
 
@@ -308,14 +309,14 @@ static pthread_mutex_t  send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
  * example). Only if neither is true, the stats_lock is acquired. The counters
  * are always read without holding a lock in the hope that writing 8 bytes to
  * memory is an atomic operation. */
-static uint64_t stats_octets_rx  = 0;
-static uint64_t stats_octets_tx  = 0;
-static uint64_t stats_packets_rx = 0;
-static uint64_t stats_packets_tx = 0;
-static uint64_t stats_values_dispatched = 0;
-static uint64_t stats_values_not_dispatched = 0;
-static uint64_t stats_values_sent = 0;
-static uint64_t stats_values_not_sent = 0;
+static derive_t stats_octets_rx  = 0;
+static derive_t stats_octets_tx  = 0;
+static derive_t stats_packets_rx = 0;
+static derive_t stats_packets_tx = 0;
+static derive_t stats_values_dispatched = 0;
+static derive_t stats_values_not_dispatched = 0;
+static derive_t stats_values_sent = 0;
+static derive_t stats_values_not_sent = 0;
 static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
 
 /*
@@ -332,30 +333,30 @@ static _Bool check_receive_okay (const value_list_t *vl) /* {{{ */
   /* This is a value we already sent. Don't allow it to be received again in
    * order to avoid looping. */
   if ((status == 0) && (time_sent >= ((uint64_t) vl->time)))
-    return (false);
+    return (0);
 
-  return (true);
+  return (1);
 } /* }}} _Bool check_receive_okay */
 
 static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
 {
-  _Bool received = false;
+  _Bool received = 0;
   int status;
 
   if (network_config_forward != 0)
-    return (true);
+    return (1);
 
   if (vl->meta == NULL)
-    return (true);
+    return (1);
 
   status = meta_data_get_boolean (vl->meta, "network:received", &received);
   if (status == -ENOENT)
-    return (true);
+    return (1);
   else if (status != 0)
   {
     ERROR ("network plugin: check_send_okay: meta_data_get_boolean failed "
        "with status %i.", status);
-    return (true);
+    return (1);
   }
 
   /* By default, only *send* value lists that were not *received* by the
@@ -433,7 +434,7 @@ static int network_dispatch_values (value_list_t *vl, /* {{{ */
     return (-ENOMEM);
   }
 
-  status = meta_data_add_boolean (vl->meta, "network:received", true);
+  status = meta_data_add_boolean (vl->meta, "network:received", 1);
   if (status != 0)
   {
     ERROR ("network plugin: meta_data_add_boolean failed.");
@@ -1451,8 +1452,19 @@ static int parse_packet (sockent_t *se, /* {{{ */
                                        &tmp);
                        if (status == 0)
                        {
-                               vl.time = (time_t) tmp;
-                               n.time = (time_t) tmp;
+                               vl.time = TIME_T_TO_CDTIME_T (tmp);
+                               n.time  = TIME_T_TO_CDTIME_T (tmp);
+                       }
+               }
+               else if (pkg_type == TYPE_TIME_HR)
+               {
+                       uint64_t tmp = 0;
+                       status = parse_part_number (&buffer, &buffer_size,
+                                       &tmp);
+                       if (status == 0)
+                       {
+                               vl.time = (cdtime_t) tmp;
+                               n.time  = (cdtime_t) tmp;
                        }
                }
                else if (pkg_type == TYPE_INTERVAL)
@@ -1461,7 +1473,15 @@ static int parse_packet (sockent_t *se, /* {{{ */
                        status = parse_part_number (&buffer, &buffer_size,
                                        &tmp);
                        if (status == 0)
-                               vl.interval = (int) tmp;
+                               vl.interval = TIME_T_TO_CDTIME_T (tmp);
+               }
+               else if (pkg_type == TYPE_INTERVAL_HR)
+               {
+                       uint64_t tmp = 0;
+                       status = parse_part_number (&buffer, &buffer_size,
+                                       &tmp);
+                       if (status == 0)
+                               vl.interval = (cdtime_t) tmp;
                }
                else if (pkg_type == TYPE_HOST)
                {
@@ -2662,7 +2682,7 @@ static int add_to_buffer (char *buffer, int buffer_size, /* {{{ */
 
        if (vl_def->time != vl->time)
        {
-               if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
+               if (write_part_number (&buffer, &buffer_size, TYPE_TIME_HR,
                                        (uint64_t) vl->time))
                        return (-1);
                vl_def->time = vl->time;
@@ -2670,7 +2690,7 @@ static int add_to_buffer (char *buffer, int buffer_size, /* {{{ */
 
        if (vl_def->interval != vl->interval)
        {
-               if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
+               if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL_HR,
                                        (uint64_t) vl->interval))
                        return (-1);
                vl_def->interval = vl->interval;
@@ -3132,8 +3152,6 @@ static int network_config (oconfig_item_t *ci) /* {{{ */
       network_config_set_boolean (child, &network_config_forward);
     else if (strcasecmp ("ReportStats", child->key) == 0)
       network_config_set_boolean (child, &network_config_stats);
-    else if (strcasecmp ("CacheFlush", child->key) == 0)
-      /* no op for backwards compatibility only */;
     else
     {
       WARNING ("network plugin: Option `%s' is not allowed here.",
@@ -3157,7 +3175,7 @@ static int network_notification (const notification_t *n,
 
   memset (buffer, 0, sizeof (buffer));
 
-  status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
+  status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME_HR,
       (uint64_t) n->time);
   if (status != 0)
     return (-1);
@@ -3262,15 +3280,15 @@ static int network_shutdown (void)
 
 static int network_stats_read (void) /* {{{ */
 {
-       uint64_t copy_octets_rx;
-       uint64_t copy_octets_tx;
-       uint64_t copy_packets_rx;
-       uint64_t copy_packets_tx;
-       uint64_t copy_values_dispatched;
-       uint64_t copy_values_not_dispatched;
-       uint64_t copy_values_sent;
-       uint64_t copy_values_not_sent;
-       uint64_t copy_receive_list_length;
+       derive_t copy_octets_rx;
+       derive_t copy_octets_tx;
+       derive_t copy_packets_rx;
+       derive_t copy_packets_tx;
+       derive_t copy_values_dispatched;
+       derive_t copy_values_not_dispatched;
+       derive_t copy_values_sent;
+       derive_t copy_values_not_sent;
+       derive_t copy_receive_list_length;
        value_list_t vl = VALUE_LIST_INIT;
        value_t values[2];
 
@@ -3293,14 +3311,14 @@ static int network_stats_read (void) /* {{{ */
        sstrncpy (vl.plugin, "network", sizeof (vl.plugin));
 
        /* Octets received / sent */
-       vl.values[0].counter = (counter_t) copy_octets_rx;
-       vl.values[1].counter = (counter_t) copy_octets_tx;
+       vl.values[0].derive = (derive_t) copy_octets_rx;
+       vl.values[1].derive = (derive_t) copy_octets_tx;
        sstrncpy (vl.type, "if_octets", sizeof (vl.type));
        plugin_dispatch_values_secure (&vl);
 
        /* Packets received / send */
-       vl.values[0].counter = (counter_t) copy_packets_rx;
-       vl.values[1].counter = (counter_t) copy_packets_tx;
+       vl.values[0].derive = (derive_t) copy_packets_rx;
+       vl.values[1].derive = (derive_t) copy_packets_tx;
        sstrncpy (vl.type, "if_packets", sizeof (vl.type));
        plugin_dispatch_values_secure (&vl);
 
@@ -3339,13 +3357,13 @@ static int network_stats_read (void) /* {{{ */
 
 static int network_init (void)
 {
-       static _Bool have_init = false;
+       static _Bool have_init = 0;
 
        /* Check if we were already initialized. If so, just return - there's
         * nothing more to do (for now, that is). */
        if (have_init)
                return (0);
-       have_init = true;
+       have_init = 1;
 
 #if HAVE_LIBGCRYPT
     /* http://lists.gnupg.org/pipermail/gcrypt-devel/2003-August/000458.html
@@ -3439,9 +3457,9 @@ static int network_init (void)
  * just send the buffer if `flush'  is called - if the requested value was in
  * there, good. If not, well, then there is nothing to flush.. -octo
  */
-static int network_flush (int timeout,
-               const char __attribute__((unused)) *identifier,
-               user_data_t __attribute__((unused)) *user_data)
+static int network_flush (__attribute__((unused)) cdtime_t timeout,
+               __attribute__((unused)) const char *identifier,
+               __attribute__((unused)) user_data_t *user_data)
 {
        pthread_mutex_lock (&send_buffer_lock);
 
index 777616c..1b35456 100644 (file)
 
 #define TYPE_HOST            0x0000
 #define TYPE_TIME            0x0001
+#define TYPE_TIME_HR         0x0008
 #define TYPE_PLUGIN          0x0002
 #define TYPE_PLUGIN_INSTANCE 0x0003
 #define TYPE_TYPE            0x0004
 #define TYPE_TYPE_INSTANCE   0x0005
 #define TYPE_VALUES          0x0006
 #define TYPE_INTERVAL        0x0007
+#define TYPE_INTERVAL_HR     0x0009
 
 /* Types to transmit notifications */
 #define TYPE_MESSAGE         0x0100
index e4d12e3..f3c636e 100644 (file)
--- a/src/nfs.c
+++ b/src/nfs.c
@@ -195,7 +195,7 @@ static void nfs_procedures_submit (const char *plugin_instance,
 
        for (i = 0; i < len; i++)
        {
-               values[0].counter = val[i];
+               values[0].derive = val[i];
                sstrncpy (vl.type_instance, names[i],
                                sizeof (vl.type_instance));
                DEBUG ("%s-%s/nfs_procedure-%s = %llu",
index d952951..3e162ba 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/nginx.c
- * Copyright (C) 2006,2007  Florian octo Forster
+ * Copyright (C) 2006-2010  Florian octo Forster
  * Copyright (C) 2008       Sebastian Harl
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -18,7 +18,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Sebastian Harl <sh at tokkee.org>
  **/
 
@@ -38,10 +38,9 @@ static char *cacert      = NULL;
 
 static CURL *curl = NULL;
 
-#define ABUFFER_SIZE 16384
-static char nginx_buffer[ABUFFER_SIZE];
-static int  nginx_buffer_len = 0;
-static char nginx_curl_error[CURL_ERROR_SIZE];
+static char   nginx_buffer[16384];
+static size_t nginx_buffer_len = 0;
+static char   nginx_curl_error[CURL_ERROR_SIZE];
 
 static const char *config_keys[] =
 {
@@ -59,17 +58,19 @@ static size_t nginx_curl_callback (void *buf, size_t size, size_t nmemb,
 {
   size_t len = size * nmemb;
 
-  if ((nginx_buffer_len + len) >= ABUFFER_SIZE)
+  /* Check if the data fits into the memory. If not, truncate it. */
+  if ((nginx_buffer_len + len) >= sizeof (nginx_buffer))
   {
-    len = (ABUFFER_SIZE - 1) - nginx_buffer_len;
+    assert (sizeof (nginx_buffer) > nginx_buffer_len);
+    len = (sizeof (nginx_buffer) - 1) - nginx_buffer_len;
   }
 
   if (len <= 0)
     return (len);
 
-  memcpy (nginx_buffer + nginx_buffer_len, (char *) buf, len);
+  memcpy (&nginx_buffer[nginx_buffer_len], buf, len);
   nginx_buffer_len += len;
-  nginx_buffer[nginx_buffer_len] = '\0';
+  nginx_buffer[nginx_buffer_len] = 0;
 
   return (len);
 }
@@ -178,7 +179,7 @@ static void submit (char *type, char *inst, long long value)
   if (strcmp (type, "nginx_connections") == 0)
     values[0].gauge = value;
   else if (strcmp (type, "nginx_requests") == 0)
-    values[0].counter = value;
+    values[0].derive = value;
   else
     return;
 
index 6b4678a..cd216ca 100644 (file)
@@ -229,6 +229,7 @@ static int notify_email_notification (const notification_t *n,
     user_data_t __attribute__((unused)) *user_data)
 {
 
+  time_t tt;
   struct tm timestamp_tm;
   char timestamp_str[64];
 
@@ -248,7 +249,8 @@ static int notify_email_notification (const notification_t *n,
       (email_subject == NULL) ? DEFAULT_SMTP_SUBJECT : email_subject,
       severity, n->host);
 
-  localtime_r (&n->time, &timestamp_tm);
+  tt = CDTIME_T_TO_TIME_T (n->time);
+  localtime_r (&tt, &timestamp_tm);
   strftime (timestamp_str, sizeof (timestamp_str), "%Y-%m-%d %H:%M:%S",
       &timestamp_tm);
   timestamp_str[sizeof (timestamp_str) - 1] = '\0';
index 462458c..09a6bf0 100644 (file)
@@ -59,7 +59,7 @@ static ow_family_features_t ow_family_features[] =
 static int ow_family_features_num = STATIC_ARRAY_SIZE (ow_family_features);
 
 static char *device_g = NULL;
-static int   ow_interval = 0;
+static cdtime_t ow_interval = 0;
 
 static const char *config_keys[] =
 {
@@ -106,10 +106,10 @@ static int cow_load_config (const char *key, const char *value)
   }
   else if (strcasecmp ("Interval", key) == 0)
   {
-    int tmp;
-    tmp = atoi (value);
-    if (tmp > 0)
-      ow_interval = tmp;
+    double tmp;
+    tmp = atof (value);
+    if (tmp > 0.0)
+      ow_interval = DOUBLE_TO_CDTIME_T (tmp);
     else
       ERROR ("onewire plugin: Invalid `Interval' setting: %s", value);
   }
@@ -306,12 +306,11 @@ static int cow_init (void)
     return (1);
   }
 
-  memset (&cb_interval, 0, sizeof (cb_interval));
-  if (ow_interval > 0)
-    cb_interval.tv_sec = (time_t) ow_interval;
+  CDTIME_T_TO_TIMESPEC (ow_interval, &cb_interval);
 
   plugin_register_complex_read (/* group = */ NULL, "onewire", cow_read,
-      &cb_interval, /* user data = */ NULL);
+      (ow_interval != 0) ? &cb_interval : NULL,
+      /* user data = */ NULL);
   plugin_register_shutdown ("onewire", cow_shutdown);
 
   return (0);
index 2aca414..9ce23b4 100644 (file)
@@ -1,9 +1,9 @@
 /**
  * collectd - src/openvpn.c
- * Copyright (C) 2008  Doug MacEachern
- * Copyright (C) 2009  Florian octo Forster
- * Copyright (C) 2009  Marco Chiappero
- * Copyright (C) 2009  Fabian Schuh
+ * Copyright (C) 2008       Doug MacEachern
+ * Copyright (C) 2009,2010  Florian octo Forster
+ * Copyright (C) 2009       Marco Chiappero
+ * Copyright (C) 2009       Fabian Schuh
  *
  * 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
@@ -20,7 +20,7 @@
  *
  * Authors:
  *   Doug MacEachern <dougm at hyperic.com>
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Marco Chiappero <marco at absence.it>
  *   Fabian Schuh <mail at xeroc.org>
  **/
@@ -114,13 +114,13 @@ static void numusers_submit (char *pinst, char *tinst, gauge_t value)
 } /* void numusers_submit */
 
 /* dispatches stats about traffic (TCP or UDP) generated by the tunnel per single endpoint */
-static void iostats_submit (char *pinst, char *tinst, counter_t rx, counter_t tx)
+static void iostats_submit (char *pinst, char *tinst, derive_t rx, derive_t tx)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        /* NOTE ON THE NEW NAMING SCHEMA:
         *       using plugin_instance to identify each vpn config (and
@@ -144,13 +144,13 @@ static void iostats_submit (char *pinst, char *tinst, counter_t rx, counter_t tx
 
 /* dispatches stats about data compression shown when in single mode */
 static void compression_submit (char *pinst, char *tinst,
-               counter_t uncompressed, counter_t compressed)
+               derive_t uncompressed, derive_t compressed)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = uncompressed;
-       values[1].counter = compressed;
+       values[0].derive = uncompressed;
+       values[1].derive = compressed;
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
@@ -173,11 +173,11 @@ static int single_read (char *name, FILE *fh)
        const int max_fields = STATIC_ARRAY_SIZE (fields);
        int  fields_num, read = 0;
 
-       counter_t link_rx, link_tx;
-       counter_t tun_rx, tun_tx;
-       counter_t pre_compress, post_compress;
-       counter_t pre_decompress, post_decompress;
-       counter_t overhead_rx, overhead_tx;
+       derive_t link_rx, link_tx;
+       derive_t tun_rx, tun_tx;
+       derive_t pre_compress, post_compress;
+       derive_t pre_decompress, post_decompress;
+       derive_t overhead_rx, overhead_tx;
 
        link_rx = 0;
        link_tx = 0;
index 828fc2e..80ae699 100644 (file)
@@ -352,7 +352,7 @@ static int o_config (oconfig_item_t *ci) /* {{{ */
     oconfig_item_t *child = ci->children + i;
     if (strcasecmp ("Query", child->key) == 0)
       udb_query_create (&queries, &queries_num, child,
-          /* callback = */ NULL, /* legacy mode = */ 0);
+          /* callback = */ NULL);
     else if (strcasecmp ("Database", child->key) == 0)
       o_config_add_database (child);
     else
@@ -615,7 +615,7 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
 
   status = udb_query_prepare_result (q, prep_area, hostname_g,
       /* plugin = */ "oracle", db->name, column_names, column_num,
-      /* interval = */ -1);
+      /* interval = */ 0);
   if (status != 0)
   {
     ERROR ("oracle plugin: o_read_database_query (%s, %s): "
index 41e763d..a2568da 100644 (file)
 
 #include "configfile.h"
 
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
+
 #include <EXTERN.h>
 #include <perl.h>
 
@@ -231,15 +235,6 @@ struct {
        { "", NULL }
 };
 
-struct {
-       char  name[64];
-       int  *var;
-} g_integers[] =
-{
-       { "Collectd::interval_g", &interval_g },
-       { "", NULL }
-};
-
 /*
  * Helper functions for data type conversion.
  */
@@ -393,10 +388,16 @@ static int hv2value_list (pTHX_ HV *hash, value_list_t *vl)
        }
 
        if (NULL != (tmp = hv_fetch (hash, "time", 4, 0)))
-               vl->time = (time_t)SvIV (*tmp);
+       {
+               double t = SvNV (*tmp);
+               vl->time = DOUBLE_TO_CDTIME_T (t);
+       }
 
        if (NULL != (tmp = hv_fetch (hash, "interval", 8, 0)))
-               vl->interval = SvIV (*tmp);
+       {
+               double t = SvNV (*tmp);
+               vl->interval = DOUBLE_TO_CDTIME_T (t);
+       }
 
        if (NULL != (tmp = hv_fetch (hash, "host", 4, 0)))
                sstrncpy (vl->host, SvPV_nolen (*tmp), sizeof (vl->host));
@@ -548,9 +549,12 @@ static int hv2notification (pTHX_ HV *hash, notification_t *n)
                n->severity = NOTIF_FAILURE;
 
        if (NULL != (tmp = hv_fetch (hash, "time", 4, 0)))
-               n->time = (time_t)SvIV (*tmp);
+       {
+               double t = SvNV (*tmp);
+               n->time = DOUBLE_TO_CDTIME_T (t);
+       }
        else
-               n->time = time (NULL);
+               n->time = cdtime ();
 
        if (NULL != (tmp = hv_fetch (hash, "message", 7, 0)))
                sstrncpy (n->message, SvPV_nolen (*tmp), sizeof (n->message));
@@ -668,11 +672,17 @@ static int value_list2hv (pTHX_ value_list_t *vl, data_set_t *ds, HV *hash)
                return -1;
 
        if (0 != vl->time)
-               if (NULL == hv_store (hash, "time", 4, newSViv (vl->time), 0))
+       {
+               double t = CDTIME_T_TO_DOUBLE (vl->time);
+               if (NULL == hv_store (hash, "time", 4, newSVnv (t), 0))
                        return -1;
+       }
 
-       if (NULL == hv_store (hash, "interval", 8, newSViv (vl->interval), 0))
-               return -1;
+       {
+               double t = CDTIME_T_TO_DOUBLE (vl->interval);
+               if (NULL == hv_store (hash, "interval", 8, newSVnv (t), 0))
+                       return -1;
+       }
 
        if ('\0' != vl->host[0])
                if (NULL == hv_store (hash, "host", 4, newSVpv (vl->host, 0), 0))
@@ -750,8 +760,11 @@ static int notification2hv (pTHX_ notification_t *n, HV *hash)
                return -1;
 
        if (0 != n->time)
-               if (NULL == hv_store (hash, "time", 4, newSViv (n->time), 0))
+       {
+               double t = CDTIME_T_TO_DOUBLE (n->time);
+               if (NULL == hv_store (hash, "time", 4, newSVnv (t), 0))
                        return -1;
+       }
 
        if ('\0' != *n->message)
                if (NULL == hv_store (hash, "message", 7, newSVpv (n->message, 0), 0))
@@ -1102,11 +1115,15 @@ static int pplugin_call_all (pTHX_ int type, ...)
                XPUSHs (sv_2mortal (newRV_noinc ((SV *)notif)));
        }
        else if (PLUGIN_FLUSH == type) {
+               cdtime_t timeout;
+
                /*
                 * $_[0] = $timeout;
                 * $_[1] = $identifier;
                 */
-               XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
+               timeout = va_arg (ap, cdtime_t);
+
+               XPUSHs (sv_2mortal (newSVnv (CDTIME_T_TO_DOUBLE (timeout))));
                XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
        }
 
@@ -1610,40 +1627,29 @@ static XS (Collectd_plugin_unregister_ds)
 static XS (Collectd_plugin_dispatch_values)
 {
        SV *values     = NULL;
-       int values_idx = 0;
 
        int ret = 0;
 
        dXSARGS;
 
-       if (2 == items) {
-               log_warn ("Collectd::plugin_dispatch_values with two arguments "
-                               "is deprecated - pass the type through values->{type}.");
-               values_idx = 1;
-       }
-       else if (1 != items) {
+       if (1 != items) {
                log_err ("Usage: Collectd::plugin_dispatch_values(values)");
                XSRETURN_EMPTY;
        }
 
        log_debug ("Collectd::plugin_dispatch_values: values=\"%s\"",
-                       SvPV_nolen (ST (values_idx)));
+                       SvPV_nolen (ST (/* stack index = */ 0)));
 
-       values = ST (values_idx);
+       values = ST (/* stack index = */ 0);
 
+       /* Make sure the argument is a hash reference. */
        if (! (SvROK (values) && (SVt_PVHV == SvTYPE (SvRV (values))))) {
                log_err ("Collectd::plugin_dispatch_values: Invalid values.");
                XSRETURN_EMPTY;
        }
 
-       if (((2 == items) && (NULL == ST (0))) || (NULL == values))
-               XSRETURN_EMPTY;
-
-       if ((2 == items) && (NULL == hv_store ((HV *)SvRV (values), "type", 4,
-                       newSVsv (ST (0)), 0))) {
-               log_err ("Collectd::plugin_dispatch_values: Could not store type.");
+       if (NULL == values)
                XSRETURN_EMPTY;
-       }
 
        ret = pplugin_dispatch_values (aTHX_ (HV *)SvRV (values));
 
@@ -2020,7 +2026,7 @@ static int perl_notify (const notification_t *notif,
        return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
 } /* static int perl_notify (const notification_t *) */
 
-static int perl_flush (int timeout, const char *identifier,
+static int perl_flush (cdtime_t timeout, const char *identifier,
                user_data_t __attribute__((unused)) *user_data)
 {
        dTHX;
@@ -2122,19 +2128,27 @@ static int g_pv_set (pTHX_ SV *var, MAGIC *mg)
        return 0;
 } /* static int g_pv_set (pTHX_ SV *, MAGIC *) */
 
-static int g_iv_get (pTHX_ SV *var, MAGIC *mg)
+static int g_interval_get (pTHX_ SV *var, MAGIC *mg)
 {
-       int *iv = (int *)mg->mg_ptr;
-       sv_setiv (var, *iv);
+       cdtime_t *interval = (cdtime_t *)mg->mg_ptr;
+       double nv;
+
+       nv = CDTIME_T_TO_DOUBLE (*interval);
+
+       sv_setnv (var, nv);
        return 0;
-} /* static int g_iv_get (pTHX_ SV *, MAGIC *) */
+} /* static int g_interval_get (pTHX_ SV *, MAGIC *) */
 
-static int g_iv_set (pTHX_ SV *var, MAGIC *mg)
+static int g_interval_set (pTHX_ SV *var, MAGIC *mg)
 {
-       int *iv = (int *)mg->mg_ptr;
-       *iv = (int)SvIV (var);
+       cdtime_t *interval = (cdtime_t *)mg->mg_ptr;
+       double nv;
+
+       nv = (double)SvNV (var);
+
+       *interval = DOUBLE_TO_CDTIME_T (nv);
        return 0;
-} /* static int g_iv_set (pTHX_ SV *, MAGIC *) */
+} /* static int g_interval_set (pTHX_ SV *, MAGIC *) */
 
 static MGVTBL g_pv_vtbl = {
        g_pv_get, g_pv_set, NULL, NULL, NULL, NULL, NULL
@@ -2142,8 +2156,8 @@ static MGVTBL g_pv_vtbl = {
                , NULL
 #endif
 };
-static MGVTBL g_iv_vtbl = {
-       g_iv_get, g_iv_set, NULL, NULL, NULL, NULL, NULL
+static MGVTBL g_interval_vtbl = {
+       g_interval_get, g_interval_set, NULL, NULL, NULL, NULL, NULL
 #if HAVE_PERL_STRUCT_MGVTBL_SVT_LOCAL
                , NULL
 #endif
@@ -2185,12 +2199,11 @@ static void xs_init (pTHX)
                                g_strings[i].var, 0);
        }
 
-       /* global integers */
-       for (i = 0; '\0' != g_integers[i].name[0]; ++i) {
-               tmp = get_sv (g_integers[i].name, 1);
-               sv_magicext (tmp, NULL, PERL_MAGIC_ext, &g_iv_vtbl,
-                               (char *)g_integers[i].var, 0);
-       }
+       tmp = get_sv ("Collectd::interval_g", /* create = */ 1);
+       sv_magicext (tmp, NULL, /* how = */ PERL_MAGIC_ext,
+                       /* vtbl = */ &g_interval_vtbl,
+                       /* name = */ (char *) &interval_g, /* namelen = */ 0);
+
        return;
 } /* static void xs_init (pTHX) */
 
index 3c92df2..91c40b6 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/plugin.c
- * Copyright (C) 2005-2009  Florian octo Forster
+ * Copyright (C) 2005-2011  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Sebastian Harl <sh at tokkee.org>
  **/
 
@@ -36,7 +36,6 @@
 #include "utils_llist.h"
 #include "utils_heap.h"
 #include "utils_cache.h"
-#include "utils_threshold.h"
 #include "filter_chain.h"
 
 /*
@@ -74,6 +73,7 @@ typedef struct read_func_s read_func_t;
 static llist_t *list_init;
 static llist_t *list_write;
 static llist_t *list_flush;
+static llist_t *list_missing;
 static llist_t *list_shutdown;
 static llist_t *list_log;
 static llist_t *list_notification;
@@ -346,7 +346,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
        while (read_loop != 0)
        {
                read_func_t *rf;
-               struct timeval now;
+               cdtime_t now;
                int status;
                int rf_type;
                int rc;
@@ -357,10 +357,9 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                {
                        struct timespec abstime;
 
-                       gettimeofday (&now, /* timezone = */ NULL);
+                       now = cdtime ();
 
-                       abstime.tv_sec = now.tv_sec + interval_g;
-                       abstime.tv_nsec = 1000 * now.tv_usec;
+                       CDTIME_T_TO_TIMESPEC (now + interval_g, &abstime);
 
                        pthread_mutex_lock (&read_lock);
                        pthread_cond_timedwait (&read_cond, &read_lock,
@@ -371,15 +370,13 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
 
                if ((rf->rf_interval.tv_sec == 0) && (rf->rf_interval.tv_nsec == 0))
                {
-                       gettimeofday (&now, /* timezone = */ NULL);
+                       now = cdtime ();
 
-                       rf->rf_interval.tv_sec = interval_g;
-                       rf->rf_interval.tv_nsec = 0;
+                       CDTIME_T_TO_TIMESPEC (interval_g, &rf->rf_interval);
 
                        rf->rf_effective_interval = rf->rf_interval;
 
-                       rf->rf_next_read.tv_sec = now.tv_sec;
-                       rf->rf_next_read.tv_nsec = 1000 * now.tv_usec;
+                       CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
                }
 
                /* sleep until this entry is due,
@@ -469,7 +466,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                }
 
                /* update the ``next read due'' field */
-               gettimeofday (&now, /* timezone = */ NULL);
+               now = cdtime ();
 
                DEBUG ("plugin_read_thread: Effective interval of the "
                                "%s plugin is %i.%09i.",
@@ -486,15 +483,12 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                NORMALIZE_TIMESPEC (rf->rf_next_read);
 
                /* Check, if `rf_next_read' is in the past. */
-               if ((rf->rf_next_read.tv_sec < now.tv_sec)
-                               || ((rf->rf_next_read.tv_sec == now.tv_sec)
-                                       && (rf->rf_next_read.tv_nsec < (1000 * now.tv_usec))))
+               if (TIMESPEC_TO_CDTIME_T (&rf->rf_next_read) < now)
                {
                        /* `rf_next_read' is in the past. Insert `now'
                         * so this value doesn't trail off into the
                         * past too much. */
-                       rf->rf_next_read.tv_sec = now.tv_sec;
-                       rf->rf_next_read.tv_nsec = 1000 * now.tv_usec;
+                       CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
                }
 
                DEBUG ("plugin_read_thread: Next read of the %s plugin at %i.%09i.",
@@ -744,6 +738,17 @@ static int plugin_insert_read (read_func_t *rf)
                }
        }
 
+       le = llist_search (read_list, rf->rf_name);
+       if (le != NULL)
+       {
+               pthread_mutex_unlock (&read_lock);
+               WARNING ("The read function \"%s\" is already registered. "
+                               "Check for duplicate \"LoadPlugin\" lines "
+                               "in your configuration!",
+                               rf->rf_name);
+               return (EINVAL);
+       }
+
        le = llentry_create (rf->rf_name, rf);
        if (le == NULL)
        {
@@ -772,14 +777,13 @@ int plugin_register_read (const char *name,
                int (*callback) (void))
 {
        read_func_t *rf;
+       int status;
 
-       rf = (read_func_t *) malloc (sizeof (read_func_t));
+       rf = malloc (sizeof (*rf));
        if (rf == NULL)
        {
-               char errbuf[1024];
-               ERROR ("plugin_register_read: malloc failed: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
-               return (-1);
+               ERROR ("plugin_register_read: malloc failed.");
+               return (ENOMEM);
        }
 
        memset (rf, 0, sizeof (read_func_t));
@@ -793,7 +797,11 @@ int plugin_register_read (const char *name,
        rf->rf_interval.tv_nsec = 0;
        rf->rf_effective_interval = rf->rf_interval;
 
-       return (plugin_insert_read (rf));
+       status = plugin_insert_read (rf);
+       if (status != 0)
+               sfree (rf);
+
+       return (status);
 } /* int plugin_register_read */
 
 int plugin_register_complex_read (const char *group, const char *name,
@@ -802,12 +810,13 @@ int plugin_register_complex_read (const char *group, const char *name,
                user_data_t *user_data)
 {
        read_func_t *rf;
+       int status;
 
-       rf = (read_func_t *) malloc (sizeof (read_func_t));
+       rf = malloc (sizeof (*rf));
        if (rf == NULL)
        {
                ERROR ("plugin_register_complex_read: malloc failed.");
-               return (-1);
+               return (ENOMEM);
        }
 
        memset (rf, 0, sizeof (read_func_t));
@@ -835,7 +844,11 @@ int plugin_register_complex_read (const char *group, const char *name,
                rf->rf_udata = *user_data;
        }
 
-       return (plugin_insert_read (rf));
+       status = plugin_insert_read (rf);
+       if (status != 0)
+               sfree (rf);
+
+       return (status);
 } /* int plugin_register_complex_read */
 
 int plugin_register_write (const char *name,
@@ -852,6 +865,13 @@ int plugin_register_flush (const char *name,
                                (void *) callback, ud));
 } /* int plugin_register_flush */
 
+int plugin_register_missing (const char *name,
+               plugin_missing_cb callback, user_data_t *ud)
+{
+       return (create_register_callback (&list_missing, name,
+                               (void *) callback, ud));
+} /* int plugin_register_missing */
+
 int plugin_register_shutdown (const char *name,
                int (*callback) (void))
 {
@@ -1038,6 +1058,11 @@ int plugin_unregister_flush (const char *name)
        return (plugin_unregister (list_flush, name));
 }
 
+int plugin_unregister_missing (const char *name)
+{
+       return (plugin_unregister (list_missing, name));
+}
+
 int plugin_unregister_shutdown (const char *name)
 {
        return (plugin_unregister (list_shutdown, name));
@@ -1261,7 +1286,7 @@ int plugin_write (const char *plugin, /* {{{ */
   return (status);
 } /* }}} int plugin_write */
 
-int plugin_flush (const char *plugin, int timeout, const char *identifier)
+int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier)
 {
   llentry_t *le;
 
@@ -1306,7 +1331,8 @@ void plugin_shutdown_all (void)
 
        destroy_read_heap ();
 
-       plugin_flush (/* plugin = */ NULL, /* timeout = */ -1,
+       plugin_flush (/* plugin = */ NULL,
+                       /* timeout = */ 0,
                        /* identifier = */ NULL);
 
        le = NULL;
@@ -1336,6 +1362,7 @@ void plugin_shutdown_all (void)
         * the real free function when registering the write callback. This way
         * the data isn't freed twice. */
        destroy_all_callbacks (&list_flush);
+       destroy_all_callbacks (&list_missing);
        destroy_all_callbacks (&list_write);
 
        destroy_all_callbacks (&list_notification);
@@ -1343,6 +1370,44 @@ void plugin_shutdown_all (void)
        destroy_all_callbacks (&list_log);
 } /* void plugin_shutdown_all */
 
+int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */
+{
+  llentry_t *le;
+
+  if (list_missing == NULL)
+    return (0);
+
+  le = llist_head (list_missing);
+  while (le != NULL)
+  {
+    callback_func_t *cf;
+    plugin_missing_cb callback;
+    int status;
+
+    cf = le->value;
+    callback = cf->cf_callback;
+
+    status = (*callback) (vl, &cf->cf_udata);
+    if (status != 0)
+    {
+      if (status < 0)
+      {
+        ERROR ("plugin_dispatch_missing: Callback function \"%s\" "
+            "failed with status %i.",
+            le->key, status);
+        return (status);
+      }
+      else
+      {
+        return (0);
+      }
+    }
+
+    le = le->next;
+  }
+  return (0);
+} /* int }}} plugin_dispatch_missing */
+
 int plugin_dispatch_values (value_list_t *vl)
 {
        int status;
@@ -1395,16 +1460,17 @@ int plugin_dispatch_values (value_list_t *vl)
        }
 
        if (vl->time == 0)
-               vl->time = time (NULL);
+               vl->time = cdtime ();
 
        if (vl->interval <= 0)
                vl->interval = interval_g;
 
-       DEBUG ("plugin_dispatch_values: time = %u; interval = %i; "
+       DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; "
                        "host = %s; "
                        "plugin = %s; plugin_instance = %s; "
                        "type = %s; type_instance = %s;",
-                       (unsigned int) vl->time, vl->interval,
+                       CDTIME_T_TO_DOUBLE (vl->time),
+                       CDTIME_T_TO_DOUBLE (vl->interval),
                        vl->host,
                        vl->plugin, vl->plugin_instance,
                        vl->type, vl->type_instance);
@@ -1488,9 +1554,6 @@ int plugin_dispatch_values (value_list_t *vl)
        /* Update the value cache */
        uc_update (ds, vl);
 
-       /* Initiate threshold checking */
-       ut_check_threshold (ds, vl);
-
        if (post_cache_chain != NULL)
        {
                status = fc_process_chain (ds, vl, post_cache_chain);
@@ -1575,9 +1638,9 @@ int plugin_dispatch_notification (const notification_t *notif)
        /* Possible TODO: Add flap detection here */
 
        DEBUG ("plugin_dispatch_notification: severity = %i; message = %s; "
-                       "time = %u; host = %s;",
+                       "time = %.3f; host = %s;",
                        notif->severity, notif->message,
-                       (unsigned int) notif->time, notif->host);
+                       CDTIME_T_TO_DOUBLE (notif->time), notif->host);
 
        /* Nobody cares for notifications */
        if (list_notification == NULL)
@@ -1711,7 +1774,7 @@ static int plugin_notification_meta_add (notification_t *n,
     }
     case NM_TYPE_BOOLEAN:
     {
-      meta->nm_value.nm_boolean = *((bool *) value);
+      meta->nm_value.nm_boolean = *((_Bool *) value);
       break;
     }
     default:
@@ -1765,7 +1828,7 @@ int plugin_notification_meta_add_double (notification_t *n,
 
 int plugin_notification_meta_add_boolean (notification_t *n,
     const char *name,
-    bool value)
+    _Bool value)
 {
   return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value));
 }
index 0b34ab1..86d4034 100644 (file)
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Sebastian Harl <sh at tokkee.org>
  **/
 
 #include "collectd.h"
 #include "configfile.h"
 #include "meta_data.h"
+#include "utils_time.h"
 
 #define PLUGIN_FLAGS_GLOBAL 0x0001
 
@@ -85,8 +86,8 @@ struct value_list_s
 {
        value_t *values;
        int      values_len;
-       time_t   time;
-       int      interval;
+       cdtime_t time;
+       cdtime_t interval;
        char     host[DATA_MAX_NAME_LEN];
        char     plugin[DATA_MAX_NAME_LEN];
        char     plugin_instance[DATA_MAX_NAME_LEN];
@@ -135,7 +136,7 @@ typedef struct notification_meta_s
                int64_t nm_signed_int;
                uint64_t nm_unsigned_int;
                double nm_double;
-               bool nm_boolean;
+               _Bool nm_boolean;
        } nm_value;
        struct notification_meta_s *next;
 } notification_meta_t;
@@ -143,7 +144,7 @@ typedef struct notification_meta_s
 typedef struct notification_s
 {
        int    severity;
-       time_t time;
+       cdtime_t time;
        char   message[NOTIF_MAX_MSG_LEN];
        char   host[DATA_MAX_NAME_LEN];
        char   plugin[DATA_MAX_NAME_LEN];
@@ -167,8 +168,12 @@ typedef int (*plugin_init_cb) (void);
 typedef int (*plugin_read_cb) (user_data_t *);
 typedef int (*plugin_write_cb) (const data_set_t *, const value_list_t *,
                user_data_t *);
-typedef int (*plugin_flush_cb) (int timeout, const char *identifier,
+typedef int (*plugin_flush_cb) (cdtime_t timeout, const char *identifier,
                user_data_t *);
+/* "missing" callback. Returns less than zero on failure, zero if other
+ * callbacks should be called, greater than zero if no more callbacks should be
+ * called. */
+typedef int (*plugin_missing_cb) (const value_list_t *, user_data_t *);
 typedef void (*plugin_log_cb) (int severity, const char *message,
                user_data_t *);
 typedef int (*plugin_shutdown_cb) (void);
@@ -248,7 +253,7 @@ void plugin_shutdown_all (void);
 int plugin_write (const char *plugin,
     const data_set_t *ds, const value_list_t *vl);
 
-int plugin_flush (const char *plugin, int timeout, const char *identifier);
+int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier);
 
 /*
  * The `plugin_register_*' functions are used to make `config', `init',
@@ -264,6 +269,8 @@ int plugin_register_init (const char *name,
                plugin_init_cb callback);
 int plugin_register_read (const char *name,
                int (*callback) (void));
+/* "user_data" will be freed automatically, unless
+ * "plugin_register_complex_read" returns an error (non-zero). */
 int plugin_register_complex_read (const char *group, const char *name,
                plugin_read_cb callback,
                const struct timespec *interval,
@@ -272,6 +279,8 @@ int plugin_register_write (const char *name,
                plugin_write_cb callback, user_data_t *user_data);
 int plugin_register_flush (const char *name,
                plugin_flush_cb callback, user_data_t *user_data);
+int plugin_register_missing (const char *name,
+               plugin_missing_cb callback, user_data_t *user_data);
 int plugin_register_shutdown (const char *name,
                plugin_shutdown_cb callback);
 int plugin_register_data_set (const data_set_t *ds);
@@ -287,6 +296,7 @@ int plugin_unregister_read (const char *name);
 int plugin_unregister_read_group (const char *group);
 int plugin_unregister_write (const char *name);
 int plugin_unregister_flush (const char *name);
+int plugin_unregister_missing (const char *name);
 int plugin_unregister_shutdown (const char *name);
 int plugin_unregister_data_set (const char *name);
 int plugin_unregister_log (const char *name);
@@ -309,6 +319,7 @@ int plugin_unregister_notification (const char *name);
  */
 int plugin_dispatch_values (value_list_t *vl);
 int plugin_dispatch_values_secure (const value_list_t *vl);
+int plugin_dispatch_missing (const value_list_t *vl);
 
 int plugin_dispatch_notification (const notification_t *notif);
 
@@ -341,7 +352,7 @@ int plugin_notification_meta_add_double (notification_t *n,
     double value);
 int plugin_notification_meta_add_boolean (notification_t *n,
     const char *name,
-    bool value);
+    _Bool value);
 
 int plugin_notification_meta_copy (notification_t *dst,
     const notification_t *src);
index dd53cb4..a8812e2 100644 (file)
@@ -117,7 +117,7 @@ typedef struct {
        udb_query_t    **queries;
        size_t           queries_num;
 
-       int interval;
+       cdtime_t interval;
 
        char *host;
        char *port;
@@ -335,8 +335,9 @@ static PGresult *c_psql_exec_query_params (c_psql_database_t *db,
                                params[i] = db->user;
                                break;
                        case C_PSQL_PARAM_INTERVAL:
-                               ssnprintf (interval, sizeof (interval), "%i",
-                                               db->interval > 0 ? db->interval : interval_g);
+                               ssnprintf (interval, sizeof (interval), "%.3f",
+                                               (db->interval > 0)
+                                               ? CDTIME_T_TO_DOUBLE (db->interval) : interval_g);
                                params[i] = interval;
                                break;
                        default:
@@ -535,28 +536,6 @@ static int config_set_s (char *name, char **var, const oconfig_item_t *ci)
        return 0;
 } /* config_set_s */
 
-static int config_set_i (char *name, int *var,
-               const oconfig_item_t *ci, int min)
-{
-       int value;
-
-       if ((0 != ci->children_num) || (1 != ci->values_num)
-                       || (OCONFIG_TYPE_NUMBER != ci->values[0].type)) {
-               log_err ("%s expects a single number argument.", name);
-               return 1;
-       }
-
-       value = (int)ci->values[0].value.number;
-
-       if (value < min) {
-               log_err ("%s expects a number greater or equal to %i.", name, min);
-               return 1;
-       }
-
-       *var = value;
-       return 0;
-} /* config_set_s */
-
 static int config_query_param_add (udb_query_t *q, oconfig_item_t *ci)
 {
        c_psql_user_data_t *data;
@@ -618,7 +597,7 @@ static int c_psql_config_database (oconfig_item_t *ci)
        c_psql_database_t *db;
 
        char cb_name[DATA_MAX_NAME_LEN];
-       struct timespec cb_interval;
+       struct timespec cb_interval = { 0, 0 };
        user_data_t ud;
 
        int i;
@@ -656,7 +635,7 @@ static int c_psql_config_database (oconfig_item_t *ci)
                        udb_query_pick_from_list (c, queries, queries_num,
                                        &db->queries, &db->queries_num);
                else if (0 == strcasecmp (c->key, "Interval"))
-                       config_set_i ("Interval", &db->interval, c, /* min = */ 1);
+                       cf_util_get_cdtime (c, &db->interval);
                else
                        log_warn ("Ignoring unknown config key \"%s\".", c->key);
        }
@@ -701,12 +680,11 @@ static int c_psql_config_database (oconfig_item_t *ci)
 
        ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->database);
 
-       memset (&cb_interval, 0, sizeof (cb_interval));
-       if (db->interval > 0)
-               cb_interval.tv_sec = (time_t)db->interval;
+       CDTIME_T_TO_TIMESPEC (db->interval, &cb_interval);
 
        plugin_register_complex_read ("postgresql", cb_name, c_psql_read,
-                       /* interval = */ &cb_interval, &ud);
+                       /* interval = */ (db->interval > 0) ? &cb_interval : NULL,
+                       &ud);
        return 0;
 } /* c_psql_config_database */
 
@@ -737,8 +715,7 @@ static int c_psql_config (oconfig_item_t *ci)
 
                if (0 == strcasecmp (c->key, "Query"))
                        udb_query_create (&queries, &queries_num, c,
-                                       /* callback = */ config_query_callback,
-                                       /* legacy mode = */ 1);
+                                       /* callback = */ config_query_callback);
                else if (0 == strcasecmp (c->key, "Database"))
                        c_psql_config_database (c);
                else
index 29f6bca..a1b2355 100644 (file)
@@ -321,6 +321,9 @@ static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
 
   struct sockaddr_un sa_unix;
 
+  struct timeval stv_timeout;
+  cdtime_t cdt_timeout;
+
   sd = socket (PF_UNIX, item->socktype, 0);
   if (sd < 0)
   {
@@ -361,12 +364,13 @@ static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
       break;
     }
 
-    struct timeval timeout;
-    timeout.tv_sec=2;
-    if (timeout.tv_sec < interval_g * 3 / 4)
-      timeout.tv_sec = interval_g * 3 / 4;
-    timeout.tv_usec=0;
-    status = setsockopt (sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof (timeout));
+    cdt_timeout = interval_g * 3 / 4;
+    if (cdt_timeout < TIME_T_TO_CDTIME_T (2))
+      cdt_timeout = TIME_T_TO_CDTIME_T (2);
+
+    CDTIME_T_TO_TIMEVAL (cdt_timeout, &stv_timeout);
+
+    status = setsockopt (sd, SOL_SOCKET, SO_RCVTIMEO, &stv_timeout, sizeof (stv_timeout));
     if (status != 0)
     {
       FUNC_ERROR ("setsockopt");
index 5e448cf..8a1436e 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * collectd - src/processes.c
  * Copyright (C) 2005       Lyonel Vincent
- * Copyright (C) 2006-2008  Florian octo Forster
+ * Copyright (C) 2006-2010  Florian octo Forster
  * Copyright (C) 2008       Oleg King
  * Copyright (C) 2009       Sebastian Harl
  * Copyright (C) 2009       Andrés J. Díaz
@@ -136,13 +136,13 @@ typedef struct procstat_entry_s
 
        unsigned long vmem_minflt;
        unsigned long vmem_majflt;
-       unsigned long vmem_minflt_counter;
-       unsigned long vmem_majflt_counter;
+       derive_t      vmem_minflt_counter;
+       derive_t      vmem_majflt_counter;
 
        unsigned long cpu_user;
        unsigned long cpu_system;
-       unsigned long cpu_user_counter;
-       unsigned long cpu_system_counter;
+       derive_t      cpu_user_counter;
+       derive_t      cpu_system_counter;
 
        /* io data */
        derive_t io_rchar;
@@ -169,11 +169,11 @@ typedef struct procstat
        unsigned long vmem_code;
        unsigned long stack_size;
 
-       unsigned long vmem_minflt_counter;
-       unsigned long vmem_majflt_counter;
+       derive_t vmem_minflt_counter;
+       derive_t vmem_majflt_counter;
 
-       unsigned long cpu_user_counter;
-       unsigned long cpu_system_counter;
+       derive_t cpu_user_counter;
+       derive_t cpu_system_counter;
 
        /* io data */
        derive_t io_rchar;
@@ -676,8 +676,8 @@ static void ps_submit_proc_list (procstat_t *ps)
        plugin_dispatch_values (&vl);
 
        sstrncpy (vl.type, "ps_cputime", sizeof (vl.type));
-       vl.values[0].counter = ps->cpu_user_counter;
-       vl.values[1].counter = ps->cpu_system_counter;
+       vl.values[0].derive = ps->cpu_user_counter;
+       vl.values[1].derive = ps->cpu_system_counter;
        vl.values_len = 2;
        plugin_dispatch_values (&vl);
 
@@ -688,8 +688,8 @@ static void ps_submit_proc_list (procstat_t *ps)
        plugin_dispatch_values (&vl);
 
        sstrncpy (vl.type, "ps_pagefaults", sizeof (vl.type));
-       vl.values[0].counter = ps->vmem_minflt_counter;
-       vl.values[1].counter = ps->vmem_majflt_counter;
+       vl.values[0].derive = ps->vmem_minflt_counter;
+       vl.values[1].derive = ps->vmem_majflt_counter;
        vl.values_len = 2;
        plugin_dispatch_values (&vl);
 
@@ -714,8 +714,8 @@ static void ps_submit_proc_list (procstat_t *ps)
        DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; "
                         "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
                        "vmem_code = %lu; "
-                       "vmem_minflt_counter = %lu; vmem_majflt_counter = %lu; "
-                       "cpu_user_counter = %lu; cpu_system_counter = %lu; "
+                       "vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; "
+                       "cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; "
                        "io_rchar = %"PRIi64"; io_wchar = %"PRIi64"; "
                        "io_syscr = %"PRIi64"; io_syscw = %"PRIi64";",
                        ps->name, ps->num_proc, ps->num_lwp,
@@ -888,8 +888,8 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        size_t name_end_pos;
        size_t name_len;
 
-       long long unsigned cpu_user_counter;
-       long long unsigned cpu_system_counter;
+       derive_t cpu_user_counter;
+       derive_t cpu_system_counter;
        long long unsigned vmem_size;
        long long unsigned vmem_rss;
        long long unsigned stack_size;
@@ -1001,8 +1001,8 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
                DEBUG("ps_read_process: did not get vmem data for pid %i",pid);
        }
 
-       ps->cpu_user_counter = (unsigned long) cpu_user_counter;
-       ps->cpu_system_counter = (unsigned long) cpu_system_counter;
+       ps->cpu_user_counter = cpu_user_counter;
+       ps->cpu_system_counter = cpu_system_counter;
        ps->vmem_size = (unsigned long) vmem_size;
        ps->vmem_rss = (unsigned long) vmem_rss;
        ps->stack_size = (unsigned long) stack_size;
index e90c1a4..0dfba21 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/protocols.c
- * Copyright (C) 2009  Florian octo Forster
+ * Copyright (C) 2009,2010  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
@@ -51,14 +51,10 @@ static void submit (const char *protocol_name,
 {
   value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
+  int status;
 
-  char *tmp_ptr;
-
-  errno = 0;
-  tmp_ptr = NULL;
-  values[0].counter = (counter_t) strtoll (str_value, &tmp_ptr,
-      /* base = */ 0);
-  if ((errno != 0) || (tmp_ptr == str_value))
+  status = parse_value (str_value, values, DS_TYPE_DERIVE);
+  if (status != 0)
   {
     ERROR ("protocols plugin: Parsing string as integer failed: %s",
         str_value);
index 22f3db6..0fb49d4 100644 (file)
@@ -433,8 +433,8 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
                sstrncpy(v->data.type_instance, value_list->type_instance, sizeof(v->data.type_instance));
                sstrncpy(v->data.plugin, value_list->plugin, sizeof(v->data.plugin));
                sstrncpy(v->data.plugin_instance, value_list->plugin_instance, sizeof(v->data.plugin_instance));
-               v->data.time = value_list->time;
-               v->interval = value_list->interval;
+               v->data.time = CDTIME_T_TO_DOUBLE(value_list->time);
+               v->interval = CDTIME_T_TO_DOUBLE(value_list->interval);
                Py_CLEAR(v->values);
                v->values = list;
                Py_CLEAR(v->meta);
@@ -463,7 +463,7 @@ static int cpy_notification_callback(const notification_t *notification, user_da
                sstrncpy(n->data.type_instance, notification->type_instance, sizeof(n->data.type_instance));
                sstrncpy(n->data.plugin, notification->plugin, sizeof(n->data.plugin));
                sstrncpy(n->data.plugin_instance, notification->plugin_instance, sizeof(n->data.plugin_instance));
-               n->data.time = notification->time;
+               n->data.time = CDTIME_T_TO_DOUBLE(notification->time);
                sstrncpy(n->message, notification->message, sizeof(n->message));
                n->severity = notification->severity;
                ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
index fd07882..307af17 100644 (file)
@@ -99,7 +99,7 @@ static PyObject *cpy_common_repr(PyObject *s) {
 
        if (self->time != 0) {
                CPY_STRCAT(&ret, l_time);
-               tmp = PyInt_FromLong(self->time);
+               tmp = PyFloat_FromDouble(self->time);
                CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
                CPY_STRCAT_AND_DEL(&ret, tmp);
        }
@@ -362,14 +362,13 @@ static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
        Values *self = (Values *) s;
-       int interval = 0;
-       double time = 0;
+       double interval = 0, time = 0;
        PyObject *values = NULL, *meta = NULL, *tmp;
        char *type = NULL, *plugin_instance = NULL, *type_instance = NULL, *plugin = NULL, *host = NULL;
        static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
                        "plugin", "host", "time", "interval", "meta", NULL};
        
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
                        NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
                        NULL, &plugin, NULL, &host, &time, &interval, &meta))
                return -1;
@@ -504,13 +503,12 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
        value_t *value;
        value_list_t value_list = VALUE_LIST_INIT;
        PyObject *values = self->values, *meta = self->meta;
-       double time = self->data.time;
-       int interval = self->interval;
+       double time = self->data.time, interval = self->interval;
        char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL;
        
        static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
                        "plugin", "host", "time", "interval", "meta", NULL};
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
                        NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
                        NULL, &plugin, NULL, &host, &time, &interval, &meta))
                return NULL;
@@ -589,8 +587,8 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
        value_list.values = value;
        value_list.meta = cpy_build_meta(meta);
        value_list.values_len = size;
-       value_list.time = time;
-       value_list.interval = interval;
+       value_list.time = DOUBLE_TO_CDTIME_T(time);
+       value_list.interval = DOUBLE_TO_CDTIME_T(interval);
        if (value_list.host[0] == 0)
                sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
        if (value_list.plugin[0] == 0)
@@ -614,8 +612,7 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
        value_t *value;
        value_list_t value_list = VALUE_LIST_INIT;
        PyObject *values = self->values, *meta = self->meta;
-       double time = self->data.time;
-       int interval = self->interval;
+       double time = self->data.time, interval = self->interval;
        char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL, *type_instance = NULL, *dest = NULL;
        
        static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
@@ -693,8 +690,8 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
        }
        value_list.values = value;
        value_list.values_len = size;
-       value_list.time = time;
-       value_list.interval = interval;
+       value_list.time = DOUBLE_TO_CDTIME_T(time);
+       value_list.interval = DOUBLE_TO_CDTIME_T(interval);
        value_list.meta = cpy_build_meta(meta);;
        if (value_list.host[0] == 0)
                sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
@@ -732,7 +729,7 @@ static PyObject *Values_repr(PyObject *s) {
        ret = cpy_common_repr(s);
        if (self->interval != 0) {
                CPY_STRCAT(&ret, l_interval);
-               tmp = PyInt_FromLong(self->interval);
+               tmp = PyFloat_FromDouble(self->interval);
                CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
                CPY_STRCAT_AND_DEL(&ret, tmp);
        }
@@ -885,7 +882,7 @@ static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObj
                        NULL, &plugin, NULL, &host, &t, &severity))
                return NULL;
 
-       notification.time = t;
+       notification.time = DOUBLE_TO_CDTIME_T(t);
        notification.severity = severity;
        sstrncpy(notification.message, message ? message : self->message, sizeof(notification.message));
        sstrncpy(notification.host, host ? host : self->data.host, sizeof(notification.host));
@@ -907,8 +904,8 @@ static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObj
                return NULL;
        }
 
-       if (notification.time < 1)
-               notification.time = time(0);
+       if (notification.time == 0)
+               notification.time = cdtime();
        if (notification.host[0] == 0)
                sstrncpy(notification.host, hostname_g, sizeof(notification.host));
        if (notification.plugin[0] == 0)
diff --git a/src/redis.c b/src/redis.c
new file mode 100644 (file)
index 0000000..86062d9
--- /dev/null
@@ -0,0 +1,315 @@
+/**
+ * collectd - src/redis.c, based on src/memcached.c
+ * Copyright (C) 2010       Andrés J. Díaz <ajdiaz@connectical.com>
+ *
+ * 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:
+ *   Andrés J. Díaz <ajdiaz@connectical.com>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <pthread.h>
+#include <credis.h>
+
+#ifndef HOST_NAME_MAX
+# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+#endif
+
+#define REDIS_DEF_HOST   "localhost"
+#define REDIS_DEF_PORT    6379
+#define REDIS_DEF_TIMEOUT 2000
+#define MAX_REDIS_NODE_NAME 64
+
+/* Redis plugin configuration example:
+ *
+ * <Plugin redis>
+ *   <Node "mynode">
+ *     Host "localhost"
+ *     Port "6379"
+ *     Timeout 2000
+ *   </Node>
+ * </Plugin>
+ */
+
+struct redis_node_s;
+typedef struct redis_node_s redis_node_t;
+struct redis_node_s
+{
+  char name[MAX_REDIS_NODE_NAME];
+  char host[HOST_NAME_MAX];
+  int port;
+  int timeout;
+
+  redis_node_t *next;
+};
+
+static redis_node_t *nodes_head = NULL;
+
+static int redis_node_add (const redis_node_t *rn) /* {{{ */
+{
+  redis_node_t *rn_copy;
+  redis_node_t *rn_ptr;
+
+  /* Check for duplicates first */
+  for (rn_ptr = nodes_head; rn_ptr != NULL; rn_ptr = rn_ptr->next)
+    if (strcmp (rn->name, rn_ptr->name) == 0)
+      break;
+
+  if (rn_ptr != NULL)
+  {
+    ERROR ("redis plugin: A node with the name `%s' already exists.",
+        rn->name);
+    return (-1);
+  }
+
+  rn_copy = malloc (sizeof (*rn_copy));
+  if (rn_copy == NULL)
+  {
+    ERROR ("redis plugin: malloc failed adding redis_node to the tree.");
+    return (-1);
+  }
+
+  memcpy (rn_copy, rn, sizeof (*rn_copy));
+  rn_copy->next = NULL;
+
+  DEBUG ("redis plugin: Adding node \"%s\".", rn->name);
+
+  if (nodes_head == NULL)
+    nodes_head = rn_copy;
+  else
+  {
+    rn_ptr = nodes_head;
+    while (rn_ptr->next != NULL)
+      rn_ptr = rn_ptr->next;
+    rn_ptr->next = rn_copy;
+  }
+
+  return (0);
+} /* }}} */
+
+static int redis_config_node (oconfig_item_t *ci) /* {{{ */
+{
+  redis_node_t rn;
+  int i;
+  int status;
+
+  memset (&rn, 0, sizeof (rn));
+  sstrncpy (rn.host, REDIS_DEF_HOST, sizeof (rn.host));
+  rn.port = REDIS_DEF_PORT;
+  rn.timeout = REDIS_DEF_TIMEOUT;
+
+  status = cf_util_get_string_buffer (ci, rn.name, sizeof (rn.name));
+  if (status != 0)
+    return (status);
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+
+    if (strcasecmp ("Host", option->key) == 0)
+      status = cf_util_get_string_buffer (option, rn.host, sizeof (rn.host));
+    else if (strcasecmp ("Port", option->key) == 0)
+    {
+      status = cf_util_get_port_number (option);
+      if (status > 0)
+      {
+        rn.port = status;
+        status = 0;
+      }
+    }
+    else if (strcasecmp ("Timeout", option->key) == 0)
+      status = cf_util_get_int (option, &rn.timeout);
+    else
+      WARNING ("redis plugin: Option `%s' not allowed inside a `Node' "
+          "block. I'll ignore this option.", option->key);
+
+    if (status != 0)
+      break;
+  }
+
+  if (status != 0)
+    return (status);
+
+  return (redis_node_add (&rn));
+} /* }}} int redis_config_node */
+
+static int redis_config (oconfig_item_t *ci) /* {{{ */
+{
+  int i;
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+
+    if (strcasecmp ("Node", option->key) == 0)
+      redis_config_node (option);
+    else
+      WARNING ("redis plugin: Option `%s' not allowed in redis"
+          " configuration. It will be ignored.", option->key);
+  }
+
+  if (nodes_head == NULL)
+  {
+    ERROR ("redis plugin: No valid node configuration could be found.");
+    return (ENOENT);
+  }
+
+  return (0);
+} /* }}} */
+
+  __attribute__ ((nonnull(2)))
+static void redis_submit_g (char *plugin_instance,
+    const char *type, const char *type_instance,
+    gauge_t value) /* {{{ */
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  values[0].gauge = value;
+
+  vl.values = values;
+  vl.values_len = 1;
+  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  sstrncpy (vl.plugin, "redis", sizeof (vl.plugin));
+  if (plugin_instance != NULL)
+    sstrncpy (vl.plugin_instance, plugin_instance,
+        sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, type, sizeof (vl.type));
+  if (type_instance != NULL)
+    sstrncpy (vl.type_instance, type_instance,
+        sizeof (vl.type_instance));
+
+  plugin_dispatch_values (&vl);
+} /* }}} */
+
+  __attribute__ ((nonnull(2)))
+static void redis_submit_d (char *plugin_instance,
+    const char *type, const char *type_instance,
+    derive_t value) /* {{{ */
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  values[0].derive = value;
+
+  vl.values = values;
+  vl.values_len = 1;
+  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  sstrncpy (vl.plugin, "redis", sizeof (vl.plugin));
+  if (plugin_instance != NULL)
+    sstrncpy (vl.plugin_instance, plugin_instance,
+        sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, type, sizeof (vl.type));
+  if (type_instance != NULL)
+    sstrncpy (vl.type_instance, type_instance,
+        sizeof (vl.type_instance));
+
+  plugin_dispatch_values (&vl);
+} /* }}} */
+
+static int redis_init (void) /* {{{ */
+{
+  redis_node_t rn = { "default", REDIS_DEF_HOST, REDIS_DEF_PORT,
+    REDIS_DEF_TIMEOUT, /* next = */ NULL };
+
+  if (nodes_head == NULL)
+    redis_node_add (&rn);
+
+  return (0);
+} /* }}} int redis_init */
+
+static int redis_read (void) /* {{{ */
+{
+  redis_node_t *rn;
+
+  for (rn = nodes_head; rn != NULL; rn = rn->next)
+  {
+    REDIS rh;
+    REDIS_INFO info;
+
+    int status;
+
+    DEBUG ("redis plugin: querying info from node `%s' (%s:%d).", rn->name, rn->host, rn->port);
+
+    rh = credis_connect (rn->host, rn->port, rn->timeout);
+    if (rh == NULL)
+    {
+      ERROR ("redis plugin: unable to connect to node `%s' (%s:%d).", rn->name, rn->host, rn->port);
+      continue;
+    }
+
+    memset (&info, 0, sizeof (info));
+    status = credis_info (rh, &info);
+    if (status != 0)
+    {
+      WARNING ("redis plugin: unable to get info from node `%s'.", rn->name);
+      credis_close (rh);
+      continue;
+    }
+
+    /* typedef struct _cr_info {
+     *   char redis_version[CREDIS_VERSION_STRING_SIZE];
+     *   int bgsave_in_progress;
+     *   int connected_clients;
+     *   int connected_slaves;
+     *   unsigned int used_memory;
+     *   long long changes_since_last_save;
+     *   int last_save_time;
+     *   long long total_connections_received;
+     *   long long total_commands_processed;
+     *   int uptime_in_seconds;
+     *   int uptime_in_days;
+     *   int role;
+     * } REDIS_INFO; */
+
+    DEBUG ("redis plugin: received info from node `%s': connected_clients = %d; "
+        "connected_slaves = %d; used_memory = %lu; changes_since_last_save = %lld; "
+        "bgsave_in_progress = %d; total_connections_received = %lld; "
+        "total_commands_processed = %lld; uptime_in_seconds = %ld", rn->name,
+        info.connected_clients, info.connected_slaves, info.used_memory,
+        info.changes_since_last_save, info.bgsave_in_progress,
+        info.total_connections_received, info.total_commands_processed,
+        info.uptime_in_seconds);
+
+    redis_submit_g (rn->name, "current_connections", "clients", info.connected_clients);
+    redis_submit_g (rn->name, "current_connections", "slaves", info.connected_slaves);
+    redis_submit_g (rn->name, "memory", "used", info.used_memory);
+    redis_submit_g (rn->name, "volatile_changes", NULL, info.changes_since_last_save);
+    redis_submit_d (rn->name, "total_connections", NULL, info.total_connections_received);
+    redis_submit_d (rn->name, "total_operations", NULL, info.total_commands_processed);
+
+    credis_close (rh);
+  }
+
+  return 0;
+}
+/* }}} */
+
+void module_register (void) /* {{{ */
+{
+  plugin_register_complex_config ("redis", redis_config);
+  plugin_register_init ("redis", redis_init);
+  plugin_register_read ("redis", redis_read);
+  /* TODO: plugin_register_write: one redis list per value id with
+   * X elements */
+}
+/* }}} */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
index ff8789e..d61ffe9 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/routeros.c
- * Copyright (C) 2009  Florian octo Forster
+ * Copyright (C) 2009,2010  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
@@ -44,13 +44,13 @@ struct cr_data_s
 typedef struct cr_data_s cr_data_t;
 
 static void cr_submit_io (cr_data_t *rd, const char *type, /* {{{ */
-    const char *type_instance, counter_t rx, counter_t tx)
+    const char *type_instance, derive_t rx, derive_t tx)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
@@ -75,13 +75,13 @@ static void submit_interface (cr_data_t *rd, /* {{{ */
   }
 
   cr_submit_io (rd, "if_packets", i->name,
-      (counter_t) i->rx_packets, (counter_t) i->tx_packets);
+      (derive_t) i->rx_packets, (derive_t) i->tx_packets);
   cr_submit_io (rd, "if_octets", i->name,
-      (counter_t) i->rx_bytes, (counter_t) i->tx_bytes);
+      (derive_t) i->rx_bytes, (derive_t) i->tx_bytes);
   cr_submit_io (rd, "if_errors", i->name,
-      (counter_t) i->rx_errors, (counter_t) i->tx_errors);
+      (derive_t) i->rx_errors, (derive_t) i->tx_errors);
   cr_submit_io (rd, "if_dropped", i->name,
-      (counter_t) i->rx_drops, (counter_t) i->tx_drops);
+      (derive_t) i->rx_drops, (derive_t) i->tx_drops);
 
   submit_interface (rd, i->next);
 } /* }}} void submit_interface */
@@ -116,12 +116,12 @@ static void cr_submit_gauge (cr_data_t *rd, const char *type, /* {{{ */
 
 #if ROS_VERSION >= ROS_VERSION_ENCODE(1, 1, 0)
 static void cr_submit_counter (cr_data_t *rd, const char *type, /* {{{ */
-    const char *type_instance, counter_t value)
+    const char *type_instance, derive_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = value;
+       values[0].derive = value;
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
@@ -166,7 +166,7 @@ static void submit_regtable (cr_data_t *rd, /* {{{ */
   ssnprintf (type_instance, sizeof (type_instance), "%s-%s",
       r->interface, r->radio_name);
   cr_submit_io (rd, "if_octets", type_instance,
-      (counter_t) r->rx_bytes, (counter_t) r->tx_bytes);
+      (derive_t) r->rx_bytes, (derive_t) r->tx_bytes);
   cr_submit_gauge (rd, "snr", type_instance, (gauge_t) r->signal_to_noise);
 
   submit_regtable (rd, r->next);
@@ -212,7 +212,7 @@ static int handle_system_resource (__attribute__((unused)) ros_connection_t *c,
 
   if (rd->collect_disk)
   {
-    cr_submit_counter (rd, "counter", "secors_written", (counter_t) r->write_sect_total);
+    cr_submit_counter (rd, "counter", "secors_written", (derive_t) r->write_sect_total);
     cr_submit_gauge (rd, "gauge", "bad_blocks", (gauge_t) r->bad_blocks);
   }
 
index 34e860b..fb7eb79 100644 (file)
@@ -64,12 +64,14 @@ static int value_list_to_string (char *buffer, int buffer_len,
   int offset;
   int status;
   int i;
+  time_t t;
 
   assert (0 == strcmp (ds->type, vl->type));
 
   memset (buffer, '\0', buffer_len);
 
-  status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+  t = CDTIME_T_TO_TIME_T (vl->time);
+  status = ssnprintf (buffer, buffer_len, "%lu", (unsigned long) t);
   if ((status < 1) || (status >= buffer_len))
     return (-1);
   offset = status;
index 2b384d0..e5f964e 100644 (file)
  */
 struct rrd_cache_s
 {
-       int    values_num;
-       char **values;
-       time_t first_value;
-       time_t last_value;
-       int random_variation;
+       int      values_num;
+       char   **values;
+       cdtime_t first_value;
+       cdtime_t last_value;
+       int64_t  random_variation;
        enum
        {
                FLAG_NONE   = 0x00,
@@ -107,10 +107,10 @@ static rrdcreate_config_t rrdcreate_config =
 
 /* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
  * ALWAYS lock `cache_lock' first! */
-static int         cache_timeout = 0;
-static int         cache_flush_timeout = 0;
-static int         random_timeout = 1;
-static time_t      cache_flush_last;
+static cdtime_t    cache_timeout = 0;
+static cdtime_t    cache_flush_timeout = 0;
+static cdtime_t    random_timeout = TIME_T_TO_CDTIME_T (1);
+static cdtime_t    cache_flush_last;
 static c_avl_tree_t *cache = NULL;
 static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -199,11 +199,13 @@ static int value_list_to_string (char *buffer, int buffer_len,
 {
        int offset;
        int status;
+       time_t tt;
        int i;
 
        memset (buffer, '\0', buffer_len);
 
-       status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+       tt = CDTIME_T_TO_TIME_T (vl->time);
+       status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) tt);
        if ((status < 1) || (status >= buffer_len))
                return (-1);
        offset = status;
@@ -303,7 +305,7 @@ static void *rrd_queue_thread (void __attribute__((unused)) *data)
 
                 pthread_mutex_lock (&queue_lock);
                 /* Wait for values to arrive */
-                while (true)
+                while (42)
                 {
                   struct timespec ts_wait;
 
@@ -342,7 +344,7 @@ static void *rrd_queue_thread (void __attribute__((unused)) *data)
                       &ts_wait);
                   if (status == ETIMEDOUT)
                     break;
-                } /* while (true) */
+                } /* while (42) */
 
                 /* XXX: If you need to lock both, cache_lock and queue_lock, at
                  * the same time, ALWAYS lock `cache_lock' first! */
@@ -510,10 +512,11 @@ static int rrd_queue_dequeue (const char *filename,
   return (0);
 } /* int rrd_queue_dequeue */
 
-static void rrd_cache_flush (int timeout)
+/* XXX: You must hold "cache_lock" when calling this function! */
+static void rrd_cache_flush (cdtime_t timeout)
 {
        rrd_cache_t *rc;
-       time_t       now;
+       cdtime_t     now;
 
        char **keys = NULL;
        int    keys_num = 0;
@@ -522,9 +525,11 @@ static void rrd_cache_flush (int timeout)
        c_avl_iterator_t *iter;
        int i;
 
-       DEBUG ("rrdtool plugin: Flushing cache, timeout = %i", timeout);
+       DEBUG ("rrdtool plugin: Flushing cache, timeout = %.3f",
+                       CDTIME_T_TO_DOUBLE (timeout));
 
-       now = time (NULL);
+       now = cdtime ();
+       timeout = TIME_T_TO_CDTIME_T (timeout);
 
        /* Build a list of entries to be flushed */
        iter = c_avl_get_iterator (cache);
@@ -532,7 +537,9 @@ static void rrd_cache_flush (int timeout)
        {
                if (rc->flags != FLAG_NONE)
                        continue;
-               else if ((now - rc->first_value) < timeout)
+               /* timeout == 0  =>  flush everything */
+               else if ((timeout != 0)
+                               && ((now - rc->first_value) < timeout))
                        continue;
                else if (rc->values_num > 0)
                {
@@ -585,10 +592,11 @@ static void rrd_cache_flush (int timeout)
        cache_flush_last = now;
 } /* void rrd_cache_flush */
 
-static int rrd_cache_flush_identifier (int timeout, const char *identifier)
+static int rrd_cache_flush_identifier (cdtime_t timeout,
+    const char *identifier)
 {
   rrd_cache_t *rc;
-  time_t now;
+  cdtime_t now;
   int status;
   char key[2048];
 
@@ -598,7 +606,7 @@ static int rrd_cache_flush_identifier (int timeout, const char *identifier)
     return (0);
   }
 
-  now = time (NULL);
+  now = cdtime ();
 
   if (datadir == NULL)
     snprintf (key, sizeof (key), "%s.rrd",
@@ -642,8 +650,43 @@ static int rrd_cache_flush_identifier (int timeout, const char *identifier)
   return (status);
 } /* int rrd_cache_flush_identifier */
 
+static int64_t rrd_get_random_variation (void)
+{
+  double dbl_timeout;
+  cdtime_t ctm_timeout;
+  double rand_fact;
+  _Bool negative;
+  int64_t ret;
+
+  if (random_timeout <= 0)
+    return (0);
+
+  /* Assure that "cache_timeout + random_variation" is never negative. */
+  if (random_timeout > cache_timeout)
+  {
+         INFO ("rrdtool plugin: Adjusting \"RandomTimeout\" to %.3f seconds.",
+                         CDTIME_T_TO_DOUBLE (cache_timeout));
+         random_timeout = cache_timeout;
+  }
+
+  /* This seems a bit complicated, but "random_timeout" is likely larger than
+   * RAND_MAX, so we can't simply use modulo here. */
+  dbl_timeout = CDTIME_T_TO_DOUBLE (random_timeout);
+  rand_fact = ((double) random ())
+    / ((double) RAND_MAX);
+  negative = (_Bool) (random () % 2);
+
+  ctm_timeout = DOUBLE_TO_CDTIME_T (dbl_timeout * rand_fact);
+
+  ret = (int64_t) ctm_timeout;
+  if (negative)
+    ret *= -1;
+
+  return (ret);
+} /* int64_t rrd_get_random_variation */
+
 static int rrd_cache_insert (const char *filename,
-               const char *value, time_t value_time)
+               const char *value, cdtime_t value_time)
 {
        rrd_cache_t *rc = NULL;
        int new_rc = 0;
@@ -664,14 +707,14 @@ static int rrd_cache_insert (const char *filename,
 
        if (rc == NULL)
        {
-               rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
+               rc = malloc (sizeof (*rc));
                if (rc == NULL)
                        return (-1);
                rc->values_num = 0;
                rc->values = NULL;
                rc->first_value = 0;
                rc->last_value = 0;
-               rc->random_variation = 0;
+               rc->random_variation = rrd_get_random_variation ();
                rc->flags = FLAG_NONE;
                new_rc = 1;
        }
@@ -679,9 +722,9 @@ static int rrd_cache_insert (const char *filename,
        if (rc->last_value >= value_time)
        {
                pthread_mutex_unlock (&cache_lock);
-               DEBUG ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
-                               (unsigned int) rc->last_value,
-                               (unsigned int) value_time);
+               DEBUG ("rrdtool plugin: (rc->last_value = %"PRIu64") "
+                               ">= (value_time = %"PRIu64")",
+                               rc->last_value, value_time);
                return (-1);
        }
 
@@ -738,11 +781,11 @@ static int rrd_cache_insert (const char *filename,
        }
 
        DEBUG ("rrdtool plugin: rrd_cache_insert: file = %s; "
-                       "values_num = %i; age = %lu;",
+                       "values_num = %i; age = %.3f;",
                        filename, rc->values_num,
-                       (unsigned long)(rc->last_value - rc->first_value));
+                       CDTIME_T_TO_DOUBLE (rc->last_value - rc->first_value));
 
-       if ((rc->last_value + rc->random_variation - rc->first_value) >= cache_timeout)
+       if ((rc->last_value - rc->first_value) >= (cache_timeout + rc->random_variation))
        {
                /* XXX: If you need to lock both, cache_lock and queue_lock, at
                 * the same time, ALWAYS lock `cache_lock' first! */
@@ -754,17 +797,7 @@ static int rrd_cache_insert (const char *filename,
                        if (status == 0)
                                rc->flags = FLAG_QUEUED;
 
-                       /* Update the jitter value. Negative values are
-                        * slightly preferred. */
-                       if (random_timeout > 0)
-                       {
-                               rc->random_variation = (rand () % (2 * random_timeout))
-                                       - random_timeout;
-                       }
-                       else
-                       {
-                               rc->random_variation = 0;
-                       }
+                        rc->random_variation = rrd_get_random_variation ();
                }
                else
                {
@@ -773,7 +806,7 @@ static int rrd_cache_insert (const char *filename,
        }
 
        if ((cache_timeout > 0) &&
-                       ((time (NULL) - cache_flush_last) > cache_flush_timeout))
+                       ((cdtime () - cache_flush_last) > cache_flush_timeout))
                rrd_cache_flush (cache_flush_timeout);
 
        pthread_mutex_unlock (&cache_lock);
@@ -899,8 +932,8 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl,
        return (status);
 } /* int rrd_write */
 
-static int rrd_flush (int timeout, const char *identifier,
-               user_data_t __attribute__((unused)) *user_data)
+static int rrd_flush (cdtime_t timeout, const char *identifier,
+               __attribute__((unused)) user_data_t *user_data)
 {
        pthread_mutex_lock (&cache_lock);
 
@@ -919,7 +952,7 @@ static int rrd_config (const char *key, const char *value)
 {
        if (strcasecmp ("CacheTimeout", key) == 0)
        {
-               int tmp = atoi (value);
+               double tmp = atof (value);
                if (tmp < 0)
                {
                        fprintf (stderr, "rrdtool: `CacheTimeout' must "
@@ -928,7 +961,7 @@ static int rrd_config (const char *key, const char *value)
                                        "be greater than 0.\n");
                        return (1);
                }
-               cache_timeout = tmp;
+               cache_timeout = DOUBLE_TO_CDTIME_T (tmp);
        }
        else if (strcasecmp ("CacheFlush", key) == 0)
        {
@@ -965,7 +998,7 @@ static int rrd_config (const char *key, const char *value)
        }
        else if (strcasecmp ("StepSize", key) == 0)
        {
-               int temp = atoi (value);
+               unsigned long temp = strtoul (value, NULL, 0);
                if (temp > 0)
                        rrdcreate_config.stepsize = temp;
        }
@@ -1061,10 +1094,10 @@ static int rrd_config (const char *key, const char *value)
        }
        else if (strcasecmp ("RandomTimeout", key) == 0)
         {
-               int tmp;
+               double tmp;
 
-               tmp = atoi (value);
-               if (tmp < 0)
+               tmp = atof (value);
+               if (tmp < 0.0)
                {
                        fprintf (stderr, "rrdtool: `RandomTimeout' must "
                                        "be greater than or equal to zero.\n");
@@ -1073,7 +1106,7 @@ static int rrd_config (const char *key, const char *value)
                }
                else
                {
-                       random_timeout = tmp;
+                       random_timeout = DOUBLE_TO_CDTIME_T (tmp);
                }
        }
        else
@@ -1086,7 +1119,7 @@ static int rrd_config (const char *key, const char *value)
 static int rrd_shutdown (void)
 {
        pthread_mutex_lock (&cache_lock);
-       rrd_cache_flush (-1);
+       rrd_cache_flush (0);
        pthread_mutex_unlock (&cache_lock);
 
        pthread_mutex_lock (&queue_lock);
@@ -1128,18 +1161,16 @@ static int rrd_init (void)
                return (0);
        init_once = 1;
 
-       if (rrdcreate_config.stepsize < 0)
-               rrdcreate_config.stepsize = 0;
        if (rrdcreate_config.heartbeat <= 0)
                rrdcreate_config.heartbeat = 2 * rrdcreate_config.stepsize;
 
        if ((rrdcreate_config.heartbeat > 0)
-                       && (rrdcreate_config.heartbeat < interval_g))
+                       && (rrdcreate_config.heartbeat < CDTIME_T_TO_TIME_T (interval_g)))
                WARNING ("rrdtool plugin: Your `heartbeat' is "
                                "smaller than your `interval'. This will "
                                "likely cause problems.");
        else if ((rrdcreate_config.stepsize > 0)
-                       && (rrdcreate_config.stepsize < interval_g))
+                       && (rrdcreate_config.stepsize < CDTIME_T_TO_TIME_T (interval_g)))
                WARNING ("rrdtool plugin: Your `stepsize' is "
                                "smaller than your `interval'. This will "
                                "create needlessly big RRD-files.");
@@ -1154,10 +1185,9 @@ static int rrd_init (void)
                return (-1);
        }
 
-       cache_flush_last = time (NULL);
-       if (cache_timeout < 2)
+       cache_flush_last = cdtime ();
+       if (cache_timeout == 0)
        {
-               cache_timeout = 0;
                cache_flush_timeout = 0;
        }
        else if (cache_flush_timeout < cache_timeout)
@@ -1174,7 +1204,7 @@ static int rrd_init (void)
        }
        queue_thread_running = 1;
 
-       DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
+       DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %lu;"
                        " heartbeat = %i; rrarows = %i; xff = %lf;",
                        (datadir == NULL) ? "(null)" : datadir,
                        rrdcreate_config.stepsize,
index cfa26bb..9bd885d 100644 (file)
 #endif
 
 static void serial_submit (const char *type_instance,
-               counter_t rx, counter_t tx)
+               derive_t rx, derive_t tx)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        vl.values = values;
        vl.values_len = 2;
@@ -54,8 +54,8 @@ static int serial_read (void)
        FILE *fh;
        char buffer[1024];
 
-       counter_t rx = 0;
-       counter_t tx = 0;
+       derive_t rx = 0;
+       derive_t tx = 0;
        
        char *fields[16];
        int i, numfields;
index d440f7f..b8bbee4 100644 (file)
@@ -69,7 +69,7 @@ struct host_definition_s
   int version;
   void *sess_handle;
   c_complain_t complaint;
-  uint32_t interval;
+  cdtime_t interval;
   data_definition_t **data_list;
   int data_list_len;
 };
@@ -207,7 +207,6 @@ static void csnmp_host_definition_destroy (void *arg) /* {{{ */
  *      +-> csnmp_config_add_host_community
  *      +-> csnmp_config_add_host_version
  *      +-> csnmp_config_add_host_collect
- *      +-> csnmp_config_add_host_interval
  */
 static void call_snmp_init_once (void)
 {
@@ -591,22 +590,6 @@ static int csnmp_config_add_host_collect (host_definition_t *host,
   return (0);
 } /* int csnmp_config_add_host_collect */
 
-static int csnmp_config_add_host_interval (host_definition_t *hd, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("snmp plugin: The `Interval' config option needs exactly one number argument.");
-    return (-1);
-  }
-
-  hd->interval = ci->values[0].value.number >= 0
-    ? (uint32_t) ci->values[0].value.number
-    : 0;
-
-  return (0);
-} /* int csnmp_config_add_host_interval */
-
 static int csnmp_config_add_host (oconfig_item_t *ci)
 {
   host_definition_t *hd;
@@ -655,7 +638,7 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
     else if (strcasecmp ("Collect", option->key) == 0)
       csnmp_config_add_host_collect (hd, option);
     else if (strcasecmp ("Interval", option->key) == 0)
-      csnmp_config_add_host_interval (hd, option);
+      cf_util_get_cdtime (option, &hd->interval);
     else
     {
       WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
@@ -699,9 +682,7 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
   cb_data.data = hd;
   cb_data.free_func = csnmp_host_definition_destroy;
 
-  memset (&cb_interval, 0, sizeof (cb_interval));
-  if (hd->interval != 0)
-    cb_interval.tv_sec = (time_t) hd->interval;
+  CDTIME_T_TO_TIMESPEC (hd->interval, &cb_interval);
 
   status = plugin_register_complex_read (/* group = */ NULL, cb_name,
       csnmp_read_host, /* interval = */ &cb_interval,
@@ -1648,8 +1629,8 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
 static int csnmp_read_host (user_data_t *ud)
 {
   host_definition_t *host;
-  time_t time_start;
-  time_t time_end;
+  cdtime_t time_start;
+  cdtime_t time_end;
   int status;
   int success;
   int i;
@@ -1659,9 +1640,7 @@ static int csnmp_read_host (user_data_t *ud)
   if (host->interval == 0)
     host->interval = interval_g;
 
-  time_start = time (NULL);
-  DEBUG ("snmp plugin: csnmp_read_host (%s) started at %u;", host->name,
-      (unsigned int) time_start);
+  time_start = cdtime ();
 
   if (host->sess_handle == NULL)
     csnmp_host_open_session (host);
@@ -1683,14 +1662,14 @@ static int csnmp_read_host (user_data_t *ud)
       success++;
   }
 
-  time_end = time (NULL);
-  DEBUG ("snmp plugin: csnmp_read_host (%s) finished at %u;", host->name,
-      (unsigned int) time_end);
-  if ((uint32_t) (time_end - time_start) > host->interval)
+  time_end = cdtime ();
+  if ((time_end - time_start) > host->interval)
   {
-    WARNING ("snmp plugin: Host `%s' should be queried every %"PRIu32
-        " seconds, but reading all values takes %u seconds.",
-        host->name, host->interval, (unsigned int) (time_end - time_start));
+    WARNING ("snmp plugin: Host `%s' should be queried every %.3f "
+       "seconds, but reading all values takes %.3f seconds.",
+       host->name,
+       CDTIME_T_TO_DOUBLE (host->interval),
+       CDTIME_T_TO_DOUBLE (time_end - time_start));
   }
 
   if (success == 0)
index 46ba665..30daa4b 100644 (file)
@@ -1,8 +1,9 @@
 /**
  * collectd - src/swap.c
- * Copyright (C) 2005-2009  Florian octo Forster
+ * Copyright (C) 2005-2010  Florian octo Forster
  * Copyright (C) 2009       Stefan Völkel
  * Copyright (C) 2009       Manuel Sanmartin
+ * Copyright (C) 2010       Aurélien Reynaud
  *
  * 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
@@ -18,8 +19,9 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Manuel Sanmartin
+ *   Aurélien Reynaud <collectd at wattapower.net>
  **/
 
 #if HAVE_CONFIG_H
 /* No global variables */
 /* #endif KERNEL_LINUX */
 
-#elif HAVE_LIBKSTAT
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
 static derive_t pagesize;
-static kstat_t *ksp;
-/* #endif HAVE_LIBKSTAT */
 
-#elif HAVE_SWAPCTL
-/* No global variables */
-/* #endif HAVE_SWAPCTL */
+static const char *config_keys[] =
+{
+       "ReportByDevice"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static _Bool report_by_device = 0;
+/* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS */
 
 #elif defined(VM_SWAPUSAGE)
 /* No global variables */
@@ -108,15 +113,9 @@ static int swap_init (void)
        /* No init stuff */
 /* #endif KERNEL_LINUX */
 
-#elif HAVE_LIBKSTAT
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
        /* getpagesize(3C) tells me this does not fail.. */
        pagesize = (derive_t) getpagesize ();
-       if (get_kstat (&ksp, "unix", 0, "system_pages"))
-               ksp = NULL;
-/* #endif HAVE_LIBKSTAT */
-
-#elif HAVE_SWAPCTL
-       /* No init stuff */
 /* #endif HAVE_SWAPCTL */
 
 #elif defined(VM_SWAPUSAGE)
@@ -155,7 +154,8 @@ static int swap_init (void)
        return (0);
 }
 
-static void swap_submit (const char *type_instance, derive_t value, unsigned type)
+static void swap_submit_inst (const char *plugin_instance, /* {{{ */
+               const char *type_instance, derive_t value, unsigned type)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
@@ -179,14 +179,22 @@ static void swap_submit (const char *type_instance, derive_t value, unsigned typ
        vl.values_len = 1;
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "swap", sizeof (vl.plugin));
+       if (plugin_instance != NULL)
+               sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
        plugin_dispatch_values (&vl);
-} /* void swap_submit */
+} /* }}} void swap_submit_inst */
 
-static int swap_read (void)
+static void swap_submit (const char *type_instance, derive_t value, unsigned type)
 {
+       swap_submit_inst (/* plugin instance = */ NULL,
+                       type_instance, value, type);
+}
+
 #if KERNEL_LINUX
+static int swap_read (void) /* {{{ */
+{
        FILE *fh;
        char buffer[1024];
 
@@ -231,7 +239,7 @@ static int swap_read (void)
                                sstrerror (errno, errbuf, sizeof (errbuf)));
        }
 
-       if ((swap_total == 0LL) || ((swap_free + swap_cached) > swap_total))
+       if ((swap_free + swap_cached) > swap_total)
                return (-1);
 
        swap_used = swap_total - (swap_free + swap_cached);
@@ -289,9 +297,24 @@ static int swap_read (void)
        swap_submit ("cached", 1024 * swap_cached, DS_TYPE_GAUGE);
        swap_submit ("in",  swap_in,  DS_TYPE_DERIVE);
        swap_submit ("out", swap_out, DS_TYPE_DERIVE);
+
+       return (0);
+} /* }}} int swap_read */
 /* #endif KERNEL_LINUX */
 
-#elif HAVE_LIBKSTAT
+/*
+ * Under Solaris, two mechanisms can be used to read swap statistics, swapctl
+ * and kstat. The former reads physical space used on a device, the latter
+ * reports the view from the virtual memory system. It was decided that the
+ * kstat-based information should be moved to the "vmem" plugin, but nobody
+ * with enough Solaris experience was available at that time to do this. The
+ * code below is still there for your reference but it won't be activated in
+ * *this* plugin again. --octo
+ */
+#elif 0 && HAVE_LIBKSTAT
+/* kstat-based read function */
+static int swap_read_kstat (void) /* {{{ */
+{
        derive_t swap_alloc;
        derive_t swap_resv;
        derive_t swap_avail;
@@ -335,9 +358,168 @@ static int swap_read (void)
        swap_submit ("used", swap_alloc, DS_TYPE_GAUGE);
        swap_submit ("free", swap_avail, DS_TYPE_GAUGE);
        swap_submit ("reserved", swap_resv, DS_TYPE_GAUGE);
-/* #endif HAVE_LIBKSTAT */
 
-#elif HAVE_SWAPCTL
+       return (0);
+} /* }}} int swap_read_kstat */
+/* #endif 0 && HAVE_LIBKSTAT */
+
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
+/* swapctl-based read function */
+static int swap_read (void) /* {{{ */
+{
+        swaptbl_t *s;
+       char *s_paths;
+        int swap_num;
+        int status;
+        int i;
+
+        derive_t avail = 0;
+        derive_t total = 0;
+
+        swap_num = swapctl (SC_GETNSWP, NULL);
+        if (swap_num < 0)
+        {
+                ERROR ("swap plugin: swapctl (SC_GETNSWP) failed with status %i.",
+                                swap_num);
+                return (-1);
+        }
+        else if (swap_num == 0)
+                return (0);
+
+       /* Allocate and initialize the swaptbl_t structure */
+        s = (swaptbl_t *) smalloc (swap_num * sizeof (swapent_t) + sizeof (struct swaptable));
+        if (s == NULL)
+        {
+                ERROR ("swap plugin: smalloc failed.");
+                return (-1);
+        }
+
+       /* Memory to store the path names. We only use these paths when the
+        * separate option has been configured, but it's easier to just
+        * allocate enough memory in any case. */
+       s_paths = calloc (swap_num, PATH_MAX);
+       if (s_paths == NULL)
+       {
+               ERROR ("swap plugin: malloc failed.");
+               sfree (s);
+               return (-1);
+       }
+        for (i = 0; i < swap_num; i++)
+               s->swt_ent[i].ste_path = s_paths + (i * PATH_MAX);
+        s->swt_n = swap_num;
+
+        status = swapctl (SC_LIST, s);
+        if (status < 0)
+        {
+               char errbuf[1024];
+                ERROR ("swap plugin: swapctl (SC_LIST) failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               sfree (s_paths);
+                sfree (s);
+                return (-1);
+        }
+       else if (swap_num < status)
+       {
+               /* more elements returned than requested */
+               ERROR ("swap plugin: I allocated memory for %i structure%s, "
+                               "but swapctl(2) claims to have returned %i. "
+                               "I'm confused and will give up.",
+                               swap_num, (swap_num == 1) ? "" : "s",
+                               status);
+               sfree (s_paths);
+                sfree (s);
+                return (-1);
+       }
+       else if (swap_num > status)
+               /* less elements returned than requested */
+               swap_num = status;
+
+        for (i = 0; i < swap_num; i++)
+        {
+               char path[PATH_MAX];
+               derive_t this_total;
+               derive_t this_avail;
+
+                if ((s->swt_ent[i].ste_flags & ST_INDEL) != 0)
+                        continue;
+
+               this_total = ((derive_t) s->swt_ent[i].ste_pages) * pagesize;
+               this_avail = ((derive_t) s->swt_ent[i].ste_free)  * pagesize;
+
+               /* Shortcut for the "combined" setting (default) */
+               if (!report_by_device)
+               {
+                       avail += this_avail;
+                       total += this_total;
+                       continue;
+               }
+
+               /* Okay, using "/" as swap device would be super-weird, but
+                * we'll handle it anyway to cover all cases. */
+               if (strcmp ("/", s->swt_ent[i].ste_path) == 0)
+                       sstrncpy (path, "root", sizeof (path));
+               else
+               {
+                       int j;
+
+                       s->swt_ent[i].ste_path[PATH_MAX - 1] = 0;
+                       /* Don't copy the leading slash */
+                       sstrncpy (path, &s->swt_ent[i].ste_path[1], sizeof (path));
+                       /* Convert slashes to dashes, just like the "df" plugin. */
+                       for (j = 0; path[j] != 0; j++)
+                               if (path[j] == '/')
+                                       path[j] = '-';
+               }
+
+               swap_submit_inst (path, "used", this_total - this_avail, DS_TYPE_GAUGE);
+               swap_submit_inst (path, "free", this_avail, DS_TYPE_GAUGE);
+        } /* for (swap_num) */
+
+        if (total < avail)
+        {
+                ERROR ("swap plugin: Total swap space (%"PRIi64") "
+                                "is less than free swap space (%"PRIi64").",
+                                total, avail);
+               sfree (s_paths);
+                sfree (s);
+                return (-1);
+        }
+
+       /* If the "separate" option was specified (report_by_device == 2), all
+        * values have already been dispatched from within the loop. */
+       if (!report_by_device)
+       {
+               swap_submit ("used", total - avail, DS_TYPE_GAUGE);
+               swap_submit ("free", avail, DS_TYPE_GAUGE);
+       }
+
+       sfree (s_paths);
+        sfree (s);
+       return (0);
+} /* }}} int swap_read */
+
+/* Configuration: Present when swapctl or both methods are available. */
+static int swap_config (const char *key, const char *value) /* {{{ */
+{
+       if (strcasecmp ("ReportByDevice", key) == 0)
+       {
+               if (IS_TRUE (value))
+                       report_by_device = 1;
+               else
+                       report_by_device = 0;
+       }
+       else
+       {
+               return (-1);
+       }
+
+       return (0);
+} /* }}} int swap_config */
+/* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS */
+
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_THREE_ARGS
+static int swap_read (void) /* {{{ */
+{
        struct swapent *swap_entries;
        int swap_num;
        int status;
@@ -346,18 +528,6 @@ static int swap_read (void)
        derive_t used  = 0;
        derive_t total = 0;
 
-       /*
-        * XXX: This is the syntax for the *BSD `swapctl', which has the
-        * following prototype:
-        *   swapctl (int cmd, void *arg, int misc);
-        *
-        * HP-UX and Solaris (and possibly other UNIXes) provide `swapctl',
-        * too, but with the following prototype:
-        *   swapctl (int cmd, void *arg);
-        *
-        * Solaris is usually handled in the KSTAT case above. For other UNIXes
-        * a separate case for the other version of `swapctl' may be necessary.
-        */
        swap_num = swapctl (SWAP_NSWAP, NULL, 0);
        if (swap_num < 0)
        {
@@ -413,9 +583,14 @@ static int swap_read (void)
        swap_submit ("free", total - used, DS_TYPE_GAUGE);
 
        sfree (swap_entries);
-/* #endif HAVE_SWAPCTL */
+
+       return (0);
+} /* }}} int swap_read */
+/* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_THREE_ARGS */
 
 #elif defined(VM_SWAPUSAGE)
+static int swap_read (void) /* {{{ */
+{
        int              mib[3];
        size_t           mib_len;
        struct xsw_usage sw_usage;
@@ -433,9 +608,14 @@ static int swap_read (void)
        /* The returned values are bytes. */
        swap_submit ("used", (derive_t) sw_usage.xsu_used, DS_TYPE_GAUGE);
        swap_submit ("free", (derive_t) sw_usage.xsu_avail, DS_TYPE_GAUGE);
+
+       return (0);
+} /* }}} int swap_read */
 /* #endif VM_SWAPUSAGE */
 
 #elif HAVE_LIBKVM_GETSWAPINFO
+static int swap_read (void) /* {{{ */
+{
        struct kvm_swap data_s;
        int             status;
 
@@ -461,9 +641,14 @@ static int swap_read (void)
 
        swap_submit ("used", used, DS_TYPE_GAUGE);
        swap_submit ("free", free, DS_TYPE_GAUGE);
+
+       return (0);
+} /* }}} int swap_read */
 /* #endif HAVE_LIBKVM_GETSWAPINFO */
 
 #elif HAVE_LIBSTATGRAB
+static int swap_read (void) /* {{{ */
+{
        sg_swap_stats *swap;
 
        swap = sg_get_swap_stats ();
@@ -473,9 +658,14 @@ static int swap_read (void)
 
        swap_submit ("used", (derive_t) swap->used, DS_TYPE_GAUGE);
        swap_submit ("free", (derive_t) swap->free, DS_TYPE_GAUGE);
+
+       return (0);
+} /* }}} int swap_read */
 /* #endif  HAVE_LIBSTATGRAB */
 
 #elif HAVE_PERFSTAT
+static int swap_read (void) /* {{{ */
+{
         if(perfstat_memory_total(NULL, &pmemory, sizeof(perfstat_memory_total_t), 1) < 0)
        {
                 char errbuf[1024];
@@ -485,13 +675,18 @@ static int swap_read (void)
         }
        swap_submit ("used", (derive_t) (pmemory.pgsp_total - pmemory.pgsp_free) * pagesize, DS_TYPE_GAUGE);
        swap_submit ("free", (derive_t) pmemory.pgsp_free * pagesize , DS_TYPE_GAUGE);
-#endif /* HAVE_PERFSTAT */
 
        return (0);
-} /* int swap_read */
+} /* }}} int swap_read */
+#endif /* HAVE_PERFSTAT */
 
 void module_register (void)
 {
+#if HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
+       plugin_register_config ("swap", swap_config, config_keys, config_keys_num);
+#endif
        plugin_register_init ("swap", swap_init);
        plugin_register_read ("swap", swap_read);
 } /* void module_register */
+
+/* vim: set fdm=marker : */
index 32b4296..a8e7dc4 100644 (file)
@@ -58,13 +58,13 @@ static int tape_init (void)
 
 static void tape_submit (const char *plugin_instance,
                const char *type,
-               counter_t read, counter_t write)
+               derive_t read, derive_t write)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = read;
-       values[1].counter = write;
+       values[0].derive = read;
+       values[1].derive = write;
 
        vl.values = values;
        vl.values_len = 2;
index 96598af..cb68048 100644 (file)
@@ -209,7 +209,7 @@ static int tn_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
   /* Initialize the structure. */
   memset (&n, 0, sizeof (n));
   n.severity = data->severity;
-  n.time = time (NULL);
+  n.time = cdtime ();
   sstrncpy (n.message, data->message, sizeof (n.message));
   sstrncpy (n.host, vl->host, sizeof (n.host));
   sstrncpy (n.plugin, vl->plugin, sizeof (n.plugin));
index 29fecdf..af224f1 100644 (file)
@@ -96,7 +96,7 @@ static int ts_invoke_counter (const data_set_t *ds, value_list_t *vl, /* {{{ */
                {
                        difference = curr_counter - prev_counter;
                }
-               rate = ((double) difference) / ((double) vl->interval);
+               rate = ((double) difference) / CDTIME_T_TO_DOUBLE (vl->interval);
 
                /* Modify the rate. */
                if (!isnan (data->factor))
@@ -105,7 +105,7 @@ static int ts_invoke_counter (const data_set_t *ds, value_list_t *vl, /* {{{ */
                        rate += data->offset;
 
                /* Calculate the internal counter. */
-               int_fraction += (rate * ((double) vl->interval));
+               int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
                difference = (uint64_t) int_fraction;
                int_fraction -= ((double) difference);
                int_counter  += difference;
@@ -199,7 +199,7 @@ static int ts_invoke_derive (const data_set_t *ds, value_list_t *vl, /* {{{ */
 
                /* Calcualte the rate */
                difference = curr_derive - prev_derive;
-               rate = ((double) difference) / ((double) vl->interval);
+               rate = ((double) difference) / CDTIME_T_TO_DOUBLE (vl->interval);
 
                /* Modify the rate. */
                if (!isnan (data->factor))
@@ -208,7 +208,7 @@ static int ts_invoke_derive (const data_set_t *ds, value_list_t *vl, /* {{{ */
                        rate += data->offset;
 
                /* Calculate the internal derive. */
-               int_fraction += (rate * ((double) vl->interval));
+               int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
                if (int_fraction < 0.0) /* handle negative integer rounding correctly */
                        difference = ((int64_t) int_fraction) - 1;
                else
@@ -263,7 +263,7 @@ static int ts_invoke_absolute (const data_set_t *ds, value_list_t *vl, /* {{{ */
        if (status != 0)
                int_fraction = 0.0;
 
-       rate = ((double) curr_absolute) / ((double) vl->interval);
+       rate = ((double) curr_absolute) / CDTIME_T_TO_DOUBLE (vl->interval);
 
        /* Modify the rate. */
        if (!isnan (data->factor))
@@ -272,7 +272,7 @@ static int ts_invoke_absolute (const data_set_t *ds, value_list_t *vl, /* {{{ */
                rate += data->offset;
 
        /* Calculate the new absolute. */
-       int_fraction += (rate * ((double) vl->interval));
+       int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
        curr_absolute = (uint64_t) int_fraction;
        int_fraction -= ((double) curr_absolute);
 
diff --git a/src/target_v5upgrade.c b/src/target_v5upgrade.c
new file mode 100644 (file)
index 0000000..25f4637
--- /dev/null
@@ -0,0 +1,472 @@
+/**
+ * collectd - src/target_set.c
+ * Copyright (C) 2008-2010  Florian Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; only version 2.1 of the License is
+ * applicable.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "filter_chain.h"
+
+static void v5_swap_instances (value_list_t *vl) /* {{{ */
+{
+  char tmp[DATA_MAX_NAME_LEN];
+
+  assert (sizeof (tmp) == sizeof (vl->plugin_instance));
+  assert (sizeof (tmp) == sizeof (vl->type_instance));
+
+  memcpy (tmp, vl->plugin_instance, sizeof (tmp));
+  memcpy (vl->plugin_instance, vl->type_instance, sizeof (tmp));
+  memcpy (vl->type_instance, tmp, sizeof (tmp));
+} /* }}} void v5_swap_instances */
+
+/*
+ * Df type
+ *
+ * By default, the "df" plugin of version 4.* uses the "df" type and puts the
+ * mount point in the type instance. Detect this behavior and convert the type
+ * to "df_complex". This can be selected in versions 4.9 and 4.10 by setting
+ * the "ReportReserved" option of the "df" plugin.
+ */
+static int v5_df (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  value_list_t new_vl;
+  value_t new_value;
+
+  /* Can't upgrade if both instances have been set. */
+  if ((vl->plugin_instance[0] != 0)
+      && (vl->type_instance[0] != 0))
+    return (FC_TARGET_CONTINUE);
+
+  /* Copy everything: Time, interval, host, ... */
+  memcpy (&new_vl, vl, sizeof (new_vl));
+
+  /* Reset data we can't simply copy */
+  new_vl.values = &new_value;
+  new_vl.values_len = 1;
+  new_vl.meta = NULL;
+
+  /* Move the mount point name to the plugin instance */
+  if (new_vl.plugin_instance[0] == 0)
+    v5_swap_instances (&new_vl);
+
+  /* Change the type to "df_complex" */
+  sstrncpy (new_vl.type, "df_complex", sizeof (new_vl.type));
+
+  /* Dispatch two new value lists instead of this one */
+  new_vl.values[0].gauge = vl->values[0].gauge;
+  sstrncpy (new_vl.type_instance, "used", sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].gauge = vl->values[1].gauge;
+  sstrncpy (new_vl.type_instance, "free", sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  /* Abort processing */
+  return (FC_TARGET_STOP);
+} /* }}} int v5_df */
+
+/*
+ * Interface plugin
+ *
+ * 4.* stores the interface in the type instance and leaves the plugin
+ * instance empty. If this is the case, put the interface name into the plugin
+ * instance and clear the type instance.
+ */
+static int v5_interface (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  if ((vl->plugin_instance[0] != 0) || (vl->type_instance[0] == 0))
+    return (FC_TARGET_CONTINUE);
+
+  v5_swap_instances (vl);
+  return (FC_TARGET_CONTINUE);
+} /* }}} int v5_interface */
+
+/*
+ * MySQL query cache
+ *
+ * 4.* uses the "mysql_qcache" type which mixes different types of
+ * information. In 5.* this has been broken up.
+ */
+static int v5_mysql_qcache (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  value_list_t new_vl;
+  value_t new_value;
+
+  if (vl->values_len != 5)
+    return (FC_TARGET_STOP);
+
+  /* Copy everything: Time, interval, host, ... */
+  memcpy (&new_vl, vl, sizeof (new_vl));
+
+  /* Reset data we can't simply copy */
+  new_vl.values = &new_value;
+  new_vl.values_len = 1;
+  new_vl.meta = NULL;
+
+  /* Change the type to "cache_result" */
+  sstrncpy (new_vl.type, "cache_result", sizeof (new_vl.type));
+
+  /* Dispatch new value lists instead of this one */
+  new_vl.values[0].derive = (derive_t) vl->values[0].counter;
+  sstrncpy (new_vl.type_instance, "qcache-hits",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].derive = (derive_t) vl->values[1].counter;
+  sstrncpy (new_vl.type_instance, "qcache-inserts",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].derive = (derive_t) vl->values[2].counter;
+  sstrncpy (new_vl.type_instance, "qcache-not_cached",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].derive = (derive_t) vl->values[3].counter;
+  sstrncpy (new_vl.type_instance, "qcache-prunes",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  /* The last data source is a gauge value, so we have to use a different type
+   * here. */
+  new_vl.values[0].gauge = vl->values[4].gauge;
+  sstrncpy (new_vl.type, "cache_size", sizeof (new_vl.type));
+  sstrncpy (new_vl.type_instance, "qcache",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  /* Abort processing */
+  return (FC_TARGET_STOP);
+} /* }}} int v5_mysql_qcache */
+
+/*
+ * MySQL thread count
+ *
+ * 4.* uses the "mysql_threads" type which mixes different types of
+ * information. In 5.* this has been broken up.
+ */
+static int v5_mysql_threads (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  value_list_t new_vl;
+  value_t new_value;
+
+  if (vl->values_len != 4)
+    return (FC_TARGET_STOP);
+
+  /* Copy everything: Time, interval, host, ... */
+  memcpy (&new_vl, vl, sizeof (new_vl));
+
+  /* Reset data we can't simply copy */
+  new_vl.values = &new_value;
+  new_vl.values_len = 1;
+  new_vl.meta = NULL;
+
+  /* Change the type to "threads" */
+  sstrncpy (new_vl.type, "threads", sizeof (new_vl.type));
+
+  /* Dispatch new value lists instead of this one */
+  new_vl.values[0].gauge = vl->values[0].gauge;
+  sstrncpy (new_vl.type_instance, "running",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].gauge = vl->values[1].gauge;
+  sstrncpy (new_vl.type_instance, "connected",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].gauge = vl->values[2].gauge;
+  sstrncpy (new_vl.type_instance, "cached",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  /* The last data source is a counter value, so we have to use a different
+   * type here. */
+  new_vl.values[0].derive = (derive_t) vl->values[3].counter;
+  sstrncpy (new_vl.type, "total_threads", sizeof (new_vl.type));
+  sstrncpy (new_vl.type_instance, "created",
+      sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  /* Abort processing */
+  return (FC_TARGET_STOP);
+} /* }}} int v5_mysql_threads */
+
+/*
+ * ZFS ARC hit and miss counters
+ *
+ * 4.* uses the flawed "arc_counts" type. In 5.* this has been replaced by the
+ * more generic "cache_result" type.
+ */
+static int v5_zfs_arc_counts (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  value_list_t new_vl;
+  value_t new_value;
+  _Bool is_hits;
+
+  if (vl->values_len != 4)
+    return (FC_TARGET_STOP);
+
+  if (strcmp ("hits", vl->type_instance) == 0)
+    is_hits = 1;
+  else if (strcmp ("misses", vl->type_instance) == 0)
+    is_hits = 0;
+  else
+    return (FC_TARGET_STOP);
+
+  /* Copy everything: Time, interval, host, ... */
+  memcpy (&new_vl, vl, sizeof (new_vl));
+
+  /* Reset data we can't simply copy */
+  new_vl.values = &new_value;
+  new_vl.values_len = 1;
+  new_vl.meta = NULL;
+
+  /* Change the type to "cache_result" */
+  sstrncpy (new_vl.type, "cache_result", sizeof (new_vl.type));
+
+  /* Dispatch new value lists instead of this one */
+  new_vl.values[0].derive = (derive_t) vl->values[0].counter;
+  ssnprintf (new_vl.type_instance, sizeof (new_vl.type_instance),
+      "demand_data-%s",
+      is_hits ? "hit" : "miss");
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].derive = (derive_t) vl->values[1].counter;
+  ssnprintf (new_vl.type_instance, sizeof (new_vl.type_instance),
+      "demand_metadata-%s",
+      is_hits ? "hit" : "miss");
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].derive = (derive_t) vl->values[2].counter;
+  ssnprintf (new_vl.type_instance, sizeof (new_vl.type_instance),
+      "prefetch_data-%s",
+      is_hits ? "hit" : "miss");
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].derive = (derive_t) vl->values[3].counter;
+  ssnprintf (new_vl.type_instance, sizeof (new_vl.type_instance),
+      "prefetch_metadata-%s",
+      is_hits ? "hit" : "miss");
+  plugin_dispatch_values (&new_vl);
+
+  /* Abort processing */
+  return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_counts */
+
+/*
+ * ZFS ARC L2 bytes
+ *
+ * "arc_l2_bytes" -> "io_octets-L2".
+ */
+static int v5_zfs_arc_l2_bytes (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  value_list_t new_vl;
+  value_t new_values[2];
+
+  if (vl->values_len != 2)
+    return (FC_TARGET_STOP);
+
+  /* Copy everything: Time, interval, host, ... */
+  memcpy (&new_vl, vl, sizeof (new_vl));
+
+  /* Reset data we can't simply copy */
+  new_vl.values = new_values;
+  new_vl.values_len = 2;
+  new_vl.meta = NULL;
+
+  /* Change the type/-instance to "io_octets-L2" */
+  sstrncpy (new_vl.type, "io_octets", sizeof (new_vl.type));
+  sstrncpy (new_vl.type_instance, "L2", sizeof (new_vl.type_instance));
+
+  /* Copy the actual values. */
+  new_vl.values[0].derive = (derive_t) vl->values[0].counter;
+  new_vl.values[1].derive = (derive_t) vl->values[1].counter;
+
+  /* Dispatch new value lists instead of this one */
+  plugin_dispatch_values (&new_vl);
+
+  /* Abort processing */
+  return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_l2_bytes */
+
+/*
+ * ZFS ARC L2 cache size
+ *
+ * 4.* uses a separate type for this. 5.* uses the generic "cache_size" type
+ * instead.
+ */
+static int v5_zfs_arc_l2_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  value_list_t new_vl;
+  value_t new_value;
+
+  if (vl->values_len != 1)
+    return (FC_TARGET_STOP);
+
+  /* Copy everything: Time, interval, host, ... */
+  memcpy (&new_vl, vl, sizeof (new_vl));
+
+  /* Reset data we can't simply copy */
+  new_vl.values = &new_value;
+  new_vl.values_len = 1;
+  new_vl.meta = NULL;
+
+  new_vl.values[0].gauge = (gauge_t) vl->values[0].gauge;
+
+  /* Change the type to "cache_size" */
+  sstrncpy (new_vl.type, "cache_size", sizeof (new_vl.type));
+
+  /* Adapt the type instance */
+  sstrncpy (new_vl.type_instance, "L2", sizeof (new_vl.type_instance));
+
+  /* Dispatch new value lists instead of this one */
+  plugin_dispatch_values (&new_vl);
+
+  /* Abort processing */
+  return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_l2_size */
+
+/*
+ * ZFS ARC ratio
+ *
+ * "arc_ratio-L1" -> "cache_ratio-arc"
+ * "arc_ratio-L2" -> "cache_ratio-L2"
+ */
+static int v5_zfs_arc_ratio (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  value_list_t new_vl;
+  value_t new_value;
+
+  if (vl->values_len != 1)
+    return (FC_TARGET_STOP);
+
+  /* Copy everything: Time, interval, host, ... */
+  memcpy (&new_vl, vl, sizeof (new_vl));
+
+  /* Reset data we can't simply copy */
+  new_vl.values = &new_value;
+  new_vl.values_len = 1;
+  new_vl.meta = NULL;
+
+  new_vl.values[0].gauge = (gauge_t) vl->values[0].gauge;
+
+  /* Change the type to "cache_ratio" */
+  sstrncpy (new_vl.type, "cache_ratio", sizeof (new_vl.type));
+
+  /* Adapt the type instance */
+  if (strcmp ("L1", vl->type_instance) == 0)
+    sstrncpy (new_vl.type_instance, "arc", sizeof (new_vl.type_instance));
+
+  /* Dispatch new value lists instead of this one */
+  plugin_dispatch_values (&new_vl);
+
+  /* Abort processing */
+  return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_ratio */
+
+/*
+ * ZFS ARC size
+ *
+ * 4.* uses the "arc_size" type with four data sources. In 5.* this has been
+ * replaces with the "cache_size" type and static data has been removed.
+ */
+static int v5_zfs_arc_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+  value_list_t new_vl;
+  value_t new_value;
+
+  if (vl->values_len != 4)
+    return (FC_TARGET_STOP);
+
+  /* Copy everything: Time, interval, host, ... */
+  memcpy (&new_vl, vl, sizeof (new_vl));
+
+  /* Reset data we can't simply copy */
+  new_vl.values = &new_value;
+  new_vl.values_len = 1;
+  new_vl.meta = NULL;
+
+  /* Change the type to "cache_size" */
+  sstrncpy (new_vl.type, "cache_size", sizeof (new_vl.type));
+
+  /* Dispatch new value lists instead of this one */
+  new_vl.values[0].derive = (derive_t) vl->values[0].counter;
+  sstrncpy (new_vl.type_instance, "arc", sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  /* Abort processing */
+  return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_size */
+
+static int v5_destroy (void **user_data) /* {{{ */
+{
+  return (0);
+} /* }}} int v5_destroy */
+
+static int v5_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
+{
+  *user_data = NULL;
+  return (0);
+} /* }}} int v5_create */
+
+static int v5_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
+    notification_meta_t __attribute__((unused)) **meta,
+    void __attribute__((unused)) **user_data)
+{
+  if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
+    return (-EINVAL);
+
+  if (strcmp ("df", vl->type) == 0)
+    return (v5_df (ds, vl));
+  else if (strcmp ("interface", vl->plugin) == 0)
+    return (v5_interface (ds, vl));
+  else if (strcmp ("mysql_qcache", vl->type) == 0)
+    return (v5_mysql_qcache (ds, vl));
+  else if (strcmp ("mysql_threads", vl->type) == 0)
+    return (v5_mysql_threads (ds, vl));
+  else if (strcmp ("arc_counts", vl->type) == 0)
+    return (v5_zfs_arc_counts (ds, vl));
+  else if (strcmp ("arc_l2_bytes", vl->type) == 0)
+    return (v5_zfs_arc_l2_bytes (ds, vl));
+  else if (strcmp ("arc_l2_size", vl->type) == 0)
+    return (v5_zfs_arc_l2_size (ds, vl));
+  else if (strcmp ("arc_ratio", vl->type) == 0)
+    return (v5_zfs_arc_ratio (ds, vl));
+  else if (strcmp ("arc_size", vl->type) == 0)
+    return (v5_zfs_arc_size (ds, vl));
+
+  return (FC_TARGET_CONTINUE);
+} /* }}} int v5_invoke */
+
+void module_register (void)
+{
+       target_proc_t tproc;
+
+       memset (&tproc, 0, sizeof (tproc));
+       tproc.create  = v5_create;
+       tproc.destroy = v5_destroy;
+       tproc.invoke  = v5_invoke;
+       fc_register_target ("v5upgrade", tproc);
+} /* module_register */
+
+/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */
+
index 502145d..2552ad3 100644 (file)
@@ -25,8 +25,8 @@
 #include "common.h"
 #include "plugin.h"
 
-#include <arpa/inet.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netdb.h>
@@ -146,7 +146,7 @@ static void tss2_submit_gauge (const char *plugin_instance,
 } /* void tss2_submit_gauge */
 
 static void tss2_submit_io (const char *plugin_instance, const char *type,
-               counter_t rx, counter_t tx)
+               derive_t rx, derive_t tx)
 {
        /*
         * Submits the io rx/tx tuple to the collectd daemon
@@ -154,8 +154,8 @@ static void tss2_submit_io (const char *plugin_instance, const char *type,
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        vl.values     = values;
        vl.values_len = 2;
@@ -505,10 +505,10 @@ static int tss2_read_vserver (vserver_list_t *vserver)
        gauge_t users = NAN;
        gauge_t channels = NAN;
        gauge_t servers = NAN;
-       counter_t rx_octets = 0;
-       counter_t tx_octets = 0;
-       counter_t rx_packets = 0;
-       counter_t tx_packets = 0;
+       derive_t rx_octets = 0;
+       derive_t tx_octets = 0;
+       derive_t rx_packets = 0;
+       derive_t tx_packets = 0;
        gauge_t packet_loss = NAN;
        int valid = 0;
 
index 8dc00e5..bf519bb 100644 (file)
--- a/src/ted.c
+++ b/src/ted.c
@@ -271,7 +271,6 @@ static void ted_submit (char *type, double value)
 
     values[0].gauge = value;
 
-    vl.time = time (NULL);
     vl.values = values;
     vl.values_len = 1;
     sstrncpy (vl.host, hostname_g, sizeof (vl.host));
index b9d07bf..0ad0d90 100644 (file)
 # error "This module is for Linux only."
 #endif
 
+static const char *config_keys[] = {
+       "Device",
+       "IgnoreSelected",
+       "ForceUseProcfs"
+};
+
 const char *const dirname_sysfs = "/sys/class/thermal";
 const char *const dirname_procfs = "/proc/acpi/thermal_zone";
 
-static char force_procfs = 0;
+static _Bool force_procfs = 0;
 static ignorelist_t *device_list;
-static value_list_t vl_temp_template = VALUE_LIST_STATIC;
-static value_list_t vl_state_template = VALUE_LIST_STATIC;
 
 enum dev_type {
        TEMP = 0,
@@ -45,16 +49,18 @@ enum dev_type {
 static void thermal_submit (const char *plugin_instance, enum dev_type dt,
                gauge_t value)
 {
-       value_list_t vl = (dt == TEMP) ? vl_temp_template : vl_state_template;
-       value_t vt;
+       value_list_t vl = VALUE_LIST_INIT;
+       value_t v;
 
-       vt.gauge = value;
+       v.gauge = value;
+       vl.values = &v;
 
-       vl.values = &vt;
        sstrncpy (vl.plugin, "thermal", sizeof(vl.plugin));
-       sstrncpy (vl.plugin_instance, plugin_instance,
-                       sizeof(vl.plugin_instance));
-       sstrncpy (vl.type, (dt == TEMP) ? "temperature" : "gauge",
+       if (plugin_instance != NULL)
+               sstrncpy (vl.plugin_instance, plugin_instance,
+                               sizeof (vl.plugin_instance));
+       sstrncpy (vl.type,
+                       (dt == TEMP) ? "temperature" : "gauge",
                        sizeof (vl.type));
 
        plugin_dispatch_values (&vl);
@@ -66,7 +72,7 @@ static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
        char filename[256];
        char data[1024];
        int len;
-       int ok = 0;
+       _Bool success = 0;
 
        if (device_list && ignorelist_match (device_list, name))
                return -1;
@@ -87,7 +93,7 @@ static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
 
                if (endptr == data + len && errno == 0) {
                        thermal_submit(name, TEMP, temp);
-                       ++ok;
+                       success = 1;
                }
        }
 
@@ -107,11 +113,11 @@ static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
 
                if (endptr == data + len && errno == 0) {
                        thermal_submit(name, COOLING_DEV, state);
-                       ++ok;
+                       success = 1;
                }
        }
 
-       return ok ? 0 : -1;
+       return (success ? 0 : -1);
 }
 
 static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
@@ -141,17 +147,17 @@ static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
                        && (! strncmp(data, str_temp, sizeof(str_temp)-1))) {
                char *endptr = NULL;
                double temp;
-               double celsius, add;
+               double factor, add;
                
                if (data[--len] == 'C') {
                        add = 0;
-                       celsius = 1;
+                       factor = 1.0;
                } else if (data[len] == 'F') {
                        add = -32;
-                       celsius = 5/9;
+                       factor = 5.0/9.0;
                } else if (data[len] == 'K') {
                        add = -273.15;
-                       celsius = 1;
+                       factor = 1.0;
                } else
                        return -1;
 
@@ -164,7 +170,7 @@ static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
                ++len;
 
                errno = 0;
-               temp = (strtod (data + len, &endptr) + add) * celsius;
+               temp = (strtod (data + len, &endptr) + add) * factor;
 
                if (endptr != data + len && errno == 0) {
                        thermal_submit(name, TEMP, temp);
@@ -175,12 +181,6 @@ static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
        return -1;
 }
 
-static const char *config_keys[] = {
-       "Device",
-       "IgnoreSelected",
-       "ForceUseProcfs"
-};
-
 static int thermal_config (const char *key, const char *value)
 {
        if (device_list == NULL)
@@ -237,21 +237,6 @@ static int thermal_init (void)
                ret = plugin_register_read ("thermal", thermal_procfs_read);
        }
 
-       if (!ret) {
-               vl_temp_template.values_len = 1;
-               vl_temp_template.interval = interval_g;
-               sstrncpy (vl_temp_template.host, hostname_g,
-                       sizeof(vl_temp_template.host));
-               sstrncpy (vl_temp_template.plugin, "thermal",
-                       sizeof(vl_temp_template.plugin));
-               sstrncpy (vl_temp_template.type_instance, "temperature",
-                       sizeof(vl_temp_template.type_instance));
-
-               vl_state_template = vl_temp_template;
-               sstrncpy (vl_state_template.type_instance, "cooling_state",
-                       sizeof(vl_state_template.type_instance));
-       }
-
        return ret;
 }
 
diff --git a/src/threshold.c b/src/threshold.c
new file mode 100644 (file)
index 0000000..7bbc59e
--- /dev/null
@@ -0,0 +1,1019 @@
+/**
+ * collectd - src/threshold.c
+ * Copyright (C) 2007-2010  Florian Forster
+ * Copyright (C) 2008-2009  Sebastian Harl
+ * Copyright (C) 2009       Andrés J. Díaz
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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
+ *
+ * Author:
+ *   Florian octo Forster <octo at collectd.org>
+ *   Sebastian Harl <sh at tokkee.org>
+ *   Andrés J. Díaz <ajdiaz at connectical.com>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_avltree.h"
+#include "utils_cache.h"
+
+#include <assert.h>
+#include <pthread.h>
+
+/*
+ * Private data structures
+ * {{{ */
+#define UT_FLAG_INVERT  0x01
+#define UT_FLAG_PERSIST 0x02
+#define UT_FLAG_PERCENTAGE 0x04
+#define UT_FLAG_INTERESTING 0x08
+typedef struct threshold_s
+{
+  char host[DATA_MAX_NAME_LEN];
+  char plugin[DATA_MAX_NAME_LEN];
+  char plugin_instance[DATA_MAX_NAME_LEN];
+  char type[DATA_MAX_NAME_LEN];
+  char type_instance[DATA_MAX_NAME_LEN];
+  char data_source[DATA_MAX_NAME_LEN];
+  gauge_t warning_min;
+  gauge_t warning_max;
+  gauge_t failure_min;
+  gauge_t failure_max;
+  gauge_t hysteresis;
+  unsigned int flags;
+  int hits;
+  struct threshold_s *next;
+} threshold_t;
+/* }}} */
+
+/*
+ * Private (static) variables
+ * {{{ */
+static c_avl_tree_t   *threshold_tree = NULL;
+static pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER;
+/* }}} */
+
+/*
+ * Threshold management
+ * ====================
+ * The following functions add, delete, search, etc. configured thresholds to
+ * the underlying AVL trees.
+ */
+/*
+ * threshold_t *threshold_get
+ *
+ * Retrieve one specific threshold configuration. For looking up a threshold
+ * matching a value_list_t, see "threshold_search" below. Returns NULL if the
+ * specified threshold doesn't exist.
+ */
+static threshold_t *threshold_get (const char *hostname,
+    const char *plugin, const char *plugin_instance,
+    const char *type, const char *type_instance)
+{ /* {{{ */
+  char name[6 * DATA_MAX_NAME_LEN];
+  threshold_t *th = NULL;
+
+  format_name (name, sizeof (name),
+      (hostname == NULL) ? "" : hostname,
+      (plugin == NULL) ? "" : plugin, plugin_instance,
+      (type == NULL) ? "" : type, type_instance);
+  name[sizeof (name) - 1] = '\0';
+
+  if (c_avl_get (threshold_tree, name, (void *) &th) == 0)
+    return (th);
+  else
+    return (NULL);
+} /* }}} threshold_t *threshold_get */
+
+/*
+ * int ut_threshold_add
+ *
+ * Adds a threshold configuration to the list of thresholds. The threshold_t
+ * structure is copied and may be destroyed after this call. Returns zero on
+ * success, non-zero otherwise.
+ */
+static int ut_threshold_add (const threshold_t *th)
+{ /* {{{ */
+  char name[6 * DATA_MAX_NAME_LEN];
+  char *name_copy;
+  threshold_t *th_copy;
+  threshold_t *th_ptr;
+  int status = 0;
+
+  if (format_name (name, sizeof (name), th->host,
+       th->plugin, th->plugin_instance,
+       th->type, th->type_instance) != 0)
+  {
+    ERROR ("ut_threshold_add: format_name failed.");
+    return (-1);
+  }
+
+  name_copy = strdup (name);
+  if (name_copy == NULL)
+  {
+    ERROR ("ut_threshold_add: strdup failed.");
+    return (-1);
+  }
+
+  th_copy = (threshold_t *) malloc (sizeof (threshold_t));
+  if (th_copy == NULL)
+  {
+    sfree (name_copy);
+    ERROR ("ut_threshold_add: malloc failed.");
+    return (-1);
+  }
+  memcpy (th_copy, th, sizeof (threshold_t));
+  th_ptr = NULL;
+
+  DEBUG ("ut_threshold_add: Adding entry `%s'", name);
+
+  pthread_mutex_lock (&threshold_lock);
+
+  th_ptr = threshold_get (th->host, th->plugin, th->plugin_instance,
+      th->type, th->type_instance);
+
+  while ((th_ptr != NULL) && (th_ptr->next != NULL))
+    th_ptr = th_ptr->next;
+
+  if (th_ptr == NULL) /* no such threshold yet */
+  {
+    status = c_avl_insert (threshold_tree, name_copy, th_copy);
+  }
+  else /* th_ptr points to the last threshold in the list */
+  {
+    th_ptr->next = th_copy;
+    /* name_copy isn't needed */
+    sfree (name_copy);
+  }
+
+  pthread_mutex_unlock (&threshold_lock);
+
+  if (status != 0)
+  {
+    ERROR ("ut_threshold_add: c_avl_insert (%s) failed.", name);
+    sfree (name_copy);
+    sfree (th_copy);
+  }
+
+  return (status);
+} /* }}} int ut_threshold_add */
+
+/* 
+ * threshold_t *threshold_search
+ *
+ * Searches for a threshold configuration using all the possible variations of
+ * "Host", "Plugin" and "Type" blocks. Returns NULL if no threshold could be
+ * found.
+ * XXX: This is likely the least efficient function in collectd.
+ */
+static threshold_t *threshold_search (const value_list_t *vl)
+{ /* {{{ */
+  threshold_t *th;
+
+  if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
+         vl->type, vl->type_instance)) != NULL)
+    return (th);
+  else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
+         vl->type, NULL)) != NULL)
+    return (th);
+  else if ((th = threshold_get (vl->host, vl->plugin, NULL,
+         vl->type, vl->type_instance)) != NULL)
+    return (th);
+  else if ((th = threshold_get (vl->host, vl->plugin, NULL,
+         vl->type, NULL)) != NULL)
+    return (th);
+  else if ((th = threshold_get (vl->host, "", NULL,
+         vl->type, vl->type_instance)) != NULL)
+    return (th);
+  else if ((th = threshold_get (vl->host, "", NULL,
+         vl->type, NULL)) != NULL)
+    return (th);
+  else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
+         vl->type, vl->type_instance)) != NULL)
+    return (th);
+  else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
+         vl->type, NULL)) != NULL)
+    return (th);
+  else if ((th = threshold_get ("", vl->plugin, NULL,
+         vl->type, vl->type_instance)) != NULL)
+    return (th);
+  else if ((th = threshold_get ("", vl->plugin, NULL,
+         vl->type, NULL)) != NULL)
+    return (th);
+  else if ((th = threshold_get ("", "", NULL,
+         vl->type, vl->type_instance)) != NULL)
+    return (th);
+  else if ((th = threshold_get ("", "", NULL,
+         vl->type, NULL)) != NULL)
+    return (th);
+
+  return (NULL);
+} /* }}} threshold_t *threshold_search */
+
+/*
+ * Configuration
+ * =============
+ * The following approximately two hundred functions are used to handle the
+ * configuration and fill the threshold list.
+ * {{{ */
+static int ut_config_type_datasource (threshold_t *th, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("threshold values: The `DataSource' option needs exactly one "
+       "string argument.");
+    return (-1);
+  }
+
+  sstrncpy (th->data_source, ci->values[0].value.string,
+      sizeof (th->data_source));
+
+  return (0);
+} /* int ut_config_type_datasource */
+
+static int ut_config_type_instance (threshold_t *th, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("threshold values: The `Instance' option needs exactly one "
+       "string argument.");
+    return (-1);
+  }
+
+  sstrncpy (th->type_instance, ci->values[0].value.string,
+      sizeof (th->type_instance));
+
+  return (0);
+} /* int ut_config_type_instance */
+
+static int ut_config_type_max (threshold_t *th, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  {
+    WARNING ("threshold values: The `%s' option needs exactly one "
+       "number argument.", ci->key);
+    return (-1);
+  }
+
+  if (strcasecmp (ci->key, "WarningMax") == 0)
+    th->warning_max = ci->values[0].value.number;
+  else
+    th->failure_max = ci->values[0].value.number;
+
+  return (0);
+} /* int ut_config_type_max */
+
+static int ut_config_type_min (threshold_t *th, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  {
+    WARNING ("threshold values: The `%s' option needs exactly one "
+       "number argument.", ci->key);
+    return (-1);
+  }
+
+  if (strcasecmp (ci->key, "WarningMin") == 0)
+    th->warning_min = ci->values[0].value.number;
+  else
+    th->failure_min = ci->values[0].value.number;
+
+  return (0);
+} /* int ut_config_type_min */
+
+static int ut_config_type_hits (threshold_t *th, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  {
+    WARNING ("threshold values: The `%s' option needs exactly one "
+      "number argument.", ci->key);
+    return (-1);
+  }
+
+  th->hits = ci->values[0].value.number;
+
+  return (0);
+} /* int ut_config_type_hits */
+
+static int ut_config_type_hysteresis (threshold_t *th, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  {
+    WARNING ("threshold values: The `%s' option needs exactly one "
+      "number argument.", ci->key);
+    return (-1);
+  }
+
+  th->hysteresis = ci->values[0].value.number;
+
+  return (0);
+} /* int ut_config_type_hysteresis */
+
+static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
+{
+  int i;
+  threshold_t th;
+  int status = 0;
+
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("threshold values: The `Type' block needs exactly one string "
+       "argument.");
+    return (-1);
+  }
+
+  if (ci->children_num < 1)
+  {
+    WARNING ("threshold values: The `Type' block needs at least one option.");
+    return (-1);
+  }
+
+  memcpy (&th, th_orig, sizeof (th));
+  sstrncpy (th.type, ci->values[0].value.string, sizeof (th.type));
+
+  th.warning_min = NAN;
+  th.warning_max = NAN;
+  th.failure_min = NAN;
+  th.failure_max = NAN;
+  th.hits = 0;
+  th.hysteresis = 0;
+  th.flags = UT_FLAG_INTERESTING; /* interesting by default */
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+    status = 0;
+
+    if (strcasecmp ("Instance", option->key) == 0)
+      status = ut_config_type_instance (&th, option);
+    else if (strcasecmp ("DataSource", option->key) == 0)
+      status = ut_config_type_datasource (&th, option);
+    else if ((strcasecmp ("WarningMax", option->key) == 0)
+       || (strcasecmp ("FailureMax", option->key) == 0))
+      status = ut_config_type_max (&th, option);
+    else if ((strcasecmp ("WarningMin", option->key) == 0)
+       || (strcasecmp ("FailureMin", option->key) == 0))
+      status = ut_config_type_min (&th, option);
+    else if (strcasecmp ("Interesting", option->key) == 0)
+      status = cf_util_get_flag (option, &th.flags, UT_FLAG_INTERESTING);
+    else if (strcasecmp ("Invert", option->key) == 0)
+      status = cf_util_get_flag (option, &th.flags, UT_FLAG_INVERT);
+    else if (strcasecmp ("Persist", option->key) == 0)
+      status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERSIST);
+    else if (strcasecmp ("Percentage", option->key) == 0)
+      status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERCENTAGE);
+    else if (strcasecmp ("Hits", option->key) == 0)
+      status = ut_config_type_hits (&th, option);
+    else if (strcasecmp ("Hysteresis", option->key) == 0)
+      status = ut_config_type_hysteresis (&th, option);
+    else
+    {
+      WARNING ("threshold values: Option `%s' not allowed inside a `Type' "
+         "block.", option->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  }
+
+  if (status == 0)
+  {
+    status = ut_threshold_add (&th);
+  }
+
+  return (status);
+} /* int ut_config_type */
+
+static int ut_config_plugin_instance (threshold_t *th, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("threshold values: The `Instance' option needs exactly one "
+       "string argument.");
+    return (-1);
+  }
+
+  sstrncpy (th->plugin_instance, ci->values[0].value.string,
+      sizeof (th->plugin_instance));
+
+  return (0);
+} /* int ut_config_plugin_instance */
+
+static int ut_config_plugin (const threshold_t *th_orig, oconfig_item_t *ci)
+{
+  int i;
+  threshold_t th;
+  int status = 0;
+
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("threshold values: The `Plugin' block needs exactly one string "
+       "argument.");
+    return (-1);
+  }
+
+  if (ci->children_num < 1)
+  {
+    WARNING ("threshold values: The `Plugin' block needs at least one nested "
+       "block.");
+    return (-1);
+  }
+
+  memcpy (&th, th_orig, sizeof (th));
+  sstrncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+    status = 0;
+
+    if (strcasecmp ("Type", option->key) == 0)
+      status = ut_config_type (&th, option);
+    else if (strcasecmp ("Instance", option->key) == 0)
+      status = ut_config_plugin_instance (&th, option);
+    else
+    {
+      WARNING ("threshold values: Option `%s' not allowed inside a `Plugin' "
+         "block.", option->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  }
+
+  return (status);
+} /* int ut_config_plugin */
+
+static int ut_config_host (const threshold_t *th_orig, oconfig_item_t *ci)
+{
+  int i;
+  threshold_t th;
+  int status = 0;
+
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("threshold values: The `Host' block needs exactly one string "
+       "argument.");
+    return (-1);
+  }
+
+  if (ci->children_num < 1)
+  {
+    WARNING ("threshold values: The `Host' block needs at least one nested "
+       "block.");
+    return (-1);
+  }
+
+  memcpy (&th, th_orig, sizeof (th));
+  sstrncpy (th.host, ci->values[0].value.string, sizeof (th.host));
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+    status = 0;
+
+    if (strcasecmp ("Type", option->key) == 0)
+      status = ut_config_type (&th, option);
+    else if (strcasecmp ("Plugin", option->key) == 0)
+      status = ut_config_plugin (&th, option);
+    else
+    {
+      WARNING ("threshold values: Option `%s' not allowed inside a `Host' "
+         "block.", option->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  }
+
+  return (status);
+} /* int ut_config_host */
+
+int ut_config (oconfig_item_t *ci)
+{
+  int i;
+  int status = 0;
+
+  threshold_t th;
+
+  if (threshold_tree == NULL)
+  {
+    threshold_tree = c_avl_create ((void *) strcmp);
+    if (threshold_tree == NULL)
+    {
+      ERROR ("ut_config: c_avl_create failed.");
+      return (-1);
+    }
+  }
+
+  memset (&th, '\0', sizeof (th));
+  th.warning_min = NAN;
+  th.warning_max = NAN;
+  th.failure_min = NAN;
+  th.failure_max = NAN;
+
+  th.hits = 0;
+  th.hysteresis = 0;
+  th.flags = UT_FLAG_INTERESTING; /* interesting by default */
+    
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+    status = 0;
+
+    if (strcasecmp ("Type", option->key) == 0)
+      status = ut_config_type (&th, option);
+    else if (strcasecmp ("Plugin", option->key) == 0)
+      status = ut_config_plugin (&th, option);
+    else if (strcasecmp ("Host", option->key) == 0)
+      status = ut_config_host (&th, option);
+    else
+    {
+      WARNING ("threshold values: Option `%s' not allowed here.", option->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  }
+
+  return (status);
+} /* int um_config */
+/*
+ * End of the functions used to configure threshold values.
+ */
+/* }}} */
+
+/*
+ * int ut_report_state
+ *
+ * Checks if the `state' differs from the old state and creates a notification
+ * if appropriate.
+ * Does not fail.
+ */
+static int ut_report_state (const data_set_t *ds,
+    const value_list_t *vl,
+    const threshold_t *th,
+    const gauge_t *values,
+    int ds_index,
+    int state)
+{ /* {{{ */
+  int state_old;
+  notification_t n;
+
+  char *buf;
+  size_t bufsize;
+
+  int status;
+
+  /* Check if hits matched */
+  if ( (th->hits != 0) )
+  {
+    int hits = uc_get_hits(ds,vl);
+    /* The STATE_OKAY always reset hits, or if hits reaise the limit */
+    if ( (state == STATE_OKAY) || (hits > th->hits) )
+    {
+        DEBUG("ut_report_state: reset uc_get_hits = 0");
+        uc_set_hits(ds,vl,0); /* reset hit counter and notify */
+    } else {
+      DEBUG("ut_report_state: th->hits = %d, uc_get_hits = %d",th->hits,uc_get_hits(ds,vl));
+      (void) uc_inc_hits(ds,vl,1); /* increase hit counter */
+      return (0);
+    }
+  } /* end check hits */
+
+  state_old = uc_get_state (ds, vl);
+
+  /* If the state didn't change, only report if `persistent' is specified and
+   * the state is not `okay'. */
+  if (state == state_old)
+  {
+    if ((th->flags & UT_FLAG_PERSIST) == 0)
+      return (0);
+    else if (state == STATE_OKAY)
+      return (0);
+  }
+
+  if (state != state_old)
+    uc_set_state (ds, vl, state);
+
+  NOTIFICATION_INIT_VL (&n, vl);
+
+  buf = n.message;
+  bufsize = sizeof (n.message);
+
+  if (state == STATE_OKAY)
+    n.severity = NOTIF_OKAY;
+  else if (state == STATE_WARNING)
+    n.severity = NOTIF_WARNING;
+  else
+    n.severity = NOTIF_FAILURE;
+
+  n.time = vl->time;
+
+  status = ssnprintf (buf, bufsize, "Host %s, plugin %s",
+      vl->host, vl->plugin);
+  buf += status;
+  bufsize -= status;
+
+  if (vl->plugin_instance[0] != '\0')
+  {
+    status = ssnprintf (buf, bufsize, " (instance %s)",
+       vl->plugin_instance);
+    buf += status;
+    bufsize -= status;
+  }
+
+  status = ssnprintf (buf, bufsize, " type %s", vl->type);
+  buf += status;
+  bufsize -= status;
+
+  if (vl->type_instance[0] != '\0')
+  {
+    status = ssnprintf (buf, bufsize, " (instance %s)",
+       vl->type_instance);
+    buf += status;
+    bufsize -= status;
+  }
+
+  plugin_notification_meta_add_string (&n, "DataSource",
+      ds->ds[ds_index].name);
+  plugin_notification_meta_add_double (&n, "CurrentValue", values[ds_index]);
+  plugin_notification_meta_add_double (&n, "WarningMin", th->warning_min);
+  plugin_notification_meta_add_double (&n, "WarningMax", th->warning_max);
+  plugin_notification_meta_add_double (&n, "FailureMin", th->failure_min);
+  plugin_notification_meta_add_double (&n, "FailureMax", th->failure_max);
+
+  /* Send an okay notification */
+  if (state == STATE_OKAY)
+  {
+    if (state_old == STATE_MISSING)
+      status = ssnprintf (buf, bufsize,
+          ": Value is no longer missing.");
+    else
+      status = ssnprintf (buf, bufsize,
+          ": All data sources are within range again.");
+    buf += status;
+    bufsize -= status;
+  }
+  else
+  {
+    double min;
+    double max;
+
+    min = (state == STATE_ERROR) ? th->failure_min : th->warning_min;
+    max = (state == STATE_ERROR) ? th->failure_max : th->warning_max;
+
+    if (th->flags & UT_FLAG_INVERT)
+    {
+      if (!isnan (min) && !isnan (max))
+      {
+        status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
+            "%f. That is within the %s region of %f%s and %f%s.",
+            ds->ds[ds_index].name, values[ds_index],
+            (state == STATE_ERROR) ? "failure" : "warning",
+            min, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "",
+            max, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
+      }
+      else
+      {
+       status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
+           "%f. That is %s the %s threshold of %f%s.",
+           ds->ds[ds_index].name, values[ds_index],
+           isnan (min) ? "below" : "above",
+           (state == STATE_ERROR) ? "failure" : "warning",
+           isnan (min) ? max : min,
+           ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
+      }
+    }
+    else if (th->flags & UT_FLAG_PERCENTAGE)
+    {
+      gauge_t value;
+      gauge_t sum;
+      int i;
+
+      sum = 0.0;
+      for (i = 0; i < vl->values_len; i++)
+      {
+        if (isnan (values[i]))
+          continue;
+
+        sum += values[i];
+      }
+
+      if (sum == 0.0)
+        value = NAN;
+      else
+        value = 100.0 * values[ds_index] / sum;
+
+      status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
+          "%g (%.2f%%). That is %s the %s threshold of %.2f%%.",
+          ds->ds[ds_index].name, values[ds_index], value,
+          (value < min) ? "below" : "above",
+          (state == STATE_ERROR) ? "failure" : "warning",
+          (value < min) ? min : max);
+    }
+    else /* is not inverted */
+    {
+      status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
+         "%f. That is %s the %s threshold of %f.",
+         ds->ds[ds_index].name, values[ds_index],
+         (values[ds_index] < min) ? "below" : "above",
+         (state == STATE_ERROR) ? "failure" : "warning",
+         (values[ds_index] < min) ? min : max);
+    }
+    buf += status;
+    bufsize -= status;
+  }
+
+  plugin_dispatch_notification (&n);
+
+  plugin_notification_meta_free (n.meta);
+  return (0);
+} /* }}} int ut_report_state */
+
+/*
+ * int ut_check_one_data_source
+ *
+ * Checks one data source against the given threshold configuration. If the
+ * `DataSource' option is set in the threshold, and the name does NOT match,
+ * `okay' is returned. If the threshold does match, its failure and warning
+ * min and max values are checked and `failure' or `warning' is returned if
+ * appropriate.
+ * Does not fail.
+ */
+static int ut_check_one_data_source (const data_set_t *ds,
+    const value_list_t __attribute__((unused)) *vl,
+    const threshold_t *th,
+    const gauge_t *values,
+    int ds_index)
+{ /* {{{ */
+  const char *ds_name;
+  int is_warning = 0;
+  int is_failure = 0;
+  int prev_state = STATE_OKAY;
+
+  /* check if this threshold applies to this data source */
+  if (ds != NULL)
+  {
+    ds_name = ds->ds[ds_index].name;
+    if ((th->data_source[0] != 0)
+       && (strcmp (ds_name, th->data_source) != 0))
+      return (STATE_OKAY);
+  }
+
+  if ((th->flags & UT_FLAG_INVERT) != 0)
+  {
+    is_warning--;
+    is_failure--;
+  }
+
+  /* XXX: This is an experimental code, not optimized, not fast, not reliable,
+   * and probably, do not work as you expect. Enjoy! :D */
+  if ( (th->hysteresis > 0) && ((prev_state = uc_get_state(ds,vl)) != STATE_OKAY) )
+  {
+    switch(prev_state)
+    {
+      case STATE_ERROR:
+       if ( (!isnan (th->failure_min) && ((th->failure_min + th->hysteresis) < values[ds_index])) ||
+            (!isnan (th->failure_max) && ((th->failure_max - th->hysteresis) > values[ds_index])) )
+         return (STATE_OKAY);
+       else
+         is_failure++;
+      case STATE_WARNING:
+       if ( (!isnan (th->warning_min) && ((th->warning_min + th->hysteresis) < values[ds_index])) ||
+            (!isnan (th->warning_max) && ((th->warning_max - th->hysteresis) > values[ds_index])) )
+         return (STATE_OKAY);
+       else
+         is_warning++;
+     }
+  }
+  else { /* no hysteresis */
+    if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
+       || (!isnan (th->failure_max) && (th->failure_max < values[ds_index])))
+      is_failure++;
+
+    if ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
+       || (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
+      is_warning++;
+ }
+
+  if (is_failure != 0)
+    return (STATE_ERROR);
+
+  if (is_warning != 0)
+    return (STATE_WARNING);
+
+  return (STATE_OKAY);
+} /* }}} int ut_check_one_data_source */
+
+/*
+ * int ut_check_one_threshold
+ *
+ * Checks all data sources of a value list against the given threshold, using
+ * the ut_check_one_data_source function above. Returns the worst status,
+ * which is `okay' if nothing has failed.
+ * Returns less than zero if the data set doesn't have any data sources.
+ */
+static int ut_check_one_threshold (const data_set_t *ds,
+    const value_list_t *vl,
+    const threshold_t *th,
+    const gauge_t *values,
+    int *ret_ds_index)
+{ /* {{{ */
+  int ret = -1;
+  int ds_index = -1;
+  int i;
+  gauge_t values_copy[ds->ds_num];
+
+  memcpy (values_copy, values, sizeof (values_copy));
+
+  if ((th->flags & UT_FLAG_PERCENTAGE) != 0)
+  {
+    int num = 0;
+    gauge_t sum=0.0;
+
+    if (ds->ds_num == 1)
+    {
+      WARNING ("ut_check_one_threshold: The %s type has only one data "
+          "source, but you have configured to check this as a percentage. "
+          "That doesn't make much sense, because the percentage will always "
+          "be 100%%!", ds->type);
+    }
+
+    /* Prepare `sum' and `num'. */
+    for (i = 0; i < ds->ds_num; i++)
+      if (!isnan (values[i]))
+      {
+        num++;
+       sum += values[i];
+      }
+
+    if ((num == 0) /* All data sources are undefined. */
+        || (sum == 0.0)) /* Sum is zero, cannot calculate percentage. */
+    {
+      for (i = 0; i < ds->ds_num; i++)
+        values_copy[i] = NAN;
+    }
+    else /* We can actually calculate the percentage. */
+    {
+      for (i = 0; i < ds->ds_num; i++)
+        values_copy[i] = 100.0 * values[i] / sum;
+    }
+  } /* if (UT_FLAG_PERCENTAGE) */
+
+  for (i = 0; i < ds->ds_num; i++)
+  {
+    int status;
+
+    status = ut_check_one_data_source (ds, vl, th, values_copy, i);
+    if (ret < status)
+    {
+      ret = status;
+      ds_index = i;
+    }
+  } /* for (ds->ds_num) */
+
+  if (ret_ds_index != NULL)
+    *ret_ds_index = ds_index;
+
+  return (ret);
+} /* }}} int ut_check_one_threshold */
+
+/*
+ * int ut_check_threshold
+ *
+ * Gets a list of matching thresholds and searches for the worst status by one
+ * of the thresholds. Then reports that status using the ut_report_state
+ * function above. 
+ * Returns zero on success and if no threshold has been configured. Returns
+ * less than zero on failure.
+ */
+static int ut_check_threshold (const data_set_t *ds, const value_list_t *vl,
+    __attribute__((unused)) user_data_t *ud)
+{ /* {{{ */
+  threshold_t *th;
+  gauge_t *values;
+  int status;
+
+  int worst_state = -1;
+  threshold_t *worst_th = NULL;
+  int worst_ds_index = -1;
+
+  if (threshold_tree == NULL)
+    return (0);
+
+  /* Is this lock really necessary? So far, thresholds are only inserted at
+   * startup. -octo */
+  pthread_mutex_lock (&threshold_lock);
+  th = threshold_search (vl);
+  pthread_mutex_unlock (&threshold_lock);
+  if (th == NULL)
+    return (0);
+
+  DEBUG ("ut_check_threshold: Found matching threshold(s)");
+
+  values = uc_get_rate (ds, vl);
+  if (values == NULL)
+    return (0);
+
+  while (th != NULL)
+  {
+    int ds_index = -1;
+
+    status = ut_check_one_threshold (ds, vl, th, values, &ds_index);
+    if (status < 0)
+    {
+      ERROR ("ut_check_threshold: ut_check_one_threshold failed.");
+      sfree (values);
+      return (-1);
+    }
+
+    if (worst_state < status)
+    {
+      worst_state = status;
+      worst_th = th;
+      worst_ds_index = ds_index;
+    }
+
+    th = th->next;
+  } /* while (th) */
+
+  status = ut_report_state (ds, vl, worst_th, values,
+      worst_ds_index, worst_state);
+  if (status != 0)
+  {
+    ERROR ("ut_check_threshold: ut_report_state failed.");
+    sfree (values);
+    return (-1);
+  }
+
+  sfree (values);
+
+  return (0);
+} /* }}} int ut_check_threshold */
+
+/*
+ * int ut_missing
+ *
+ * This function is called whenever a value goes "missing".
+ */
+static int ut_missing (const value_list_t *vl,
+    __attribute__((unused)) user_data_t *ud)
+{ /* {{{ */
+  threshold_t *th;
+  cdtime_t missing_time;
+  char identifier[6 * DATA_MAX_NAME_LEN];
+  notification_t n;
+
+  th = threshold_search (vl);
+  if (th == NULL)
+    return (0);
+
+  missing_time = cdtime () - vl->time;
+  FORMAT_VL (identifier, sizeof (identifier), vl);
+
+  NOTIFICATION_INIT_VL (&n, vl);
+  ssnprintf (n.message, sizeof (n.message),
+      "%s has not been updated for %.3f seconds.",
+      identifier, CDTIME_T_TO_DOUBLE (missing_time));
+
+  plugin_dispatch_notification (&n);
+
+  return (0);
+} /* }}} int ut_missing */
+
+void module_register (void)
+{
+  plugin_register_complex_config ("threshold", ut_config);
+  plugin_register_missing ("threshold", ut_missing,
+      /* user data = */ NULL);
+  plugin_register_write ("threshold", ut_check_threshold,
+      /* user data = */ NULL);
+}
+
+/* vim: set sw=2 ts=8 sts=2 tw=78 et fdm=marker : */
index ad54240..e6345ab 100644 (file)
-absolute               count:ABSOLUTE:0:U
-apache_bytes           count:COUNTER:0:134217728
-apache_connections     count:GAUGE:0:65535
-apache_idle_workers    count:GAUGE:0:65535
-apache_requests                count:COUNTER:0:134217728
-apache_scoreboard      count:GAUGE:0:65535
-arc_counts             demand_data:COUNTER:0:U, demand_metadata:COUNTER:0:U, prefetch_data:COUNTER:0:U, prefetch_metadata:COUNTER:0:U
-arc_l2_bytes           read:COUNTER:0:U, write:COUNTER:0:U
-arc_l2_size            value:GAUGE:0:U
-arc_ratio              value:GAUGE:0:U
-arc_size               current:GAUGE:0:U, target:GAUGE:0:U, minlimit:GAUGE:0:U, maxlimit:GAUGE:0:U
+absolute               value:ABSOLUTE:0:U
+apache_bytes           value:DERIVE:0:U
+apache_connections     value:GAUGE:0:65535
+apache_idle_workers    value:GAUGE:0:65535
+apache_requests                value:DERIVE:0:U
+apache_scoreboard      value:GAUGE:0:65535
 ath_nodes              value:GAUGE:0:65535
-ath_stat               value:COUNTER:0:4294967295
+ath_stat               value:DERIVE:0:U
 bitrate                        value:GAUGE:0:4294967295
 bytes                  value:GAUGE:0:U
+cache_operation                value:DERIVE:0:U
 cache_ratio            value:GAUGE:0:100
-cache_result           value:COUNTER:0:4294967295
+cache_result           value:DERIVE:0:U
 cache_size             value:GAUGE:0:4294967295
 charge                 value:GAUGE:0:U
-compression            uncompressed:COUNTER:0:U, compressed:COUNTER:0:U
 compression_ratio      value:GAUGE:0:2
-connections            value:COUNTER:0:U
-conntrack              entropy:GAUGE:0:4294967295
-contextswitch          contextswitches:DERIVE:0:U
+compression            uncompressed:DERIVE:0:U, compressed:DERIVE:0:U
+connections            value:DERIVE:0:U
+conntrack              value:GAUGE:0:4294967295
+contextswitch          value:DERIVE:0:U
 counter                        value:COUNTER:U:U
 cpufreq                        value:GAUGE:0:U
-cpu                    value:COUNTER:0:4294967295
+cpu                    value:DERIVE:0:U
+current_connections    value:GAUGE:0:U
+current_sessions       value:GAUGE:0:U
 current                        value:GAUGE:U:U
-delay                  seconds:GAUGE:-1000000:1000000
+delay                  value:GAUGE:-1000000:1000000
 derive                 value:DERIVE:0:U
-df                     used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
 df_complex             value:GAUGE:0:U
 df_inodes              value:GAUGE:0:U
+df                     used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
 disk_latency           read:GAUGE:0:U, write:GAUGE:0:U
-disk_merged            read:COUNTER:0:4294967295, write:COUNTER:0:4294967295
-disk_octets            read:COUNTER:0:17179869183, write:COUNTER:0:17179869183
-disk_ops               read:COUNTER:0:4294967295, write:COUNTER:0:4294967295
-disk_ops_complex       value:COUNTER:0:4294967296
-disk_time              read:COUNTER:0:1000000, write:COUNTER:0:1000000
-dns_answer             value:COUNTER:0:65535
-dns_notify             value:COUNTER:0:65535
-dns_octets             queries:COUNTER:0:125000000, responses:COUNTER:0:125000000
-dns_opcode             value:COUNTER:0:65535
+disk_merged            read:DERIVE:0:U, write:DERIVE:0:U
+disk_octets            read:DERIVE:0:U, write:DERIVE:0:U
+disk_ops_complex       value:DERIVE:0:U
+disk_ops               read:DERIVE:0:U, write:DERIVE:0:U
+disk_time              read:DERIVE:0:U, write:DERIVE:0:U
+dns_answer             value:DERIVE:0:U
+dns_notify             value:DERIVE:0:U
+dns_octets             queries:DERIVE:0:U, responses:DERIVE:0:U
+dns_opcode             value:DERIVE:0:U
 dns_qtype_cached       value:GAUGE:0:4294967295
-dns_qtype              value:COUNTER:0:65535
-dns_query              value:COUNTER:0:65535
-dns_question           value:COUNTER:0:65535
-dns_rcode              value:COUNTER:0:65535
-dns_reject             value:COUNTER:0:65535
-dns_request            value:COUNTER:0:65535
-dns_resolver           value:COUNTER:0:65535
-dns_response           value:COUNTER:0:65535
-dns_transfer           value:COUNTER:0:65535
-dns_update             value:COUNTER:0:65535
-dns_zops               value:COUNTER:0:65535
+dns_qtype              value:DERIVE:0:U
+dns_query              value:DERIVE:0:U
+dns_question           value:DERIVE:0:U
+dns_rcode              value:DERIVE:0:U
+dns_reject             value:DERIVE:0:U
+dns_request            value:DERIVE:0:U
+dns_resolver           value:DERIVE:0:U
+dns_response           value:DERIVE:0:U
+dns_transfer           value:DERIVE:0:U
+dns_update             value:DERIVE:0:U
+dns_zops               value:DERIVE:0:U
 email_check            value:GAUGE:0:U
 email_count            value:GAUGE:0:U
 email_size             value:GAUGE:0:U
-entropy                        entropy:GAUGE:0:4294967295
+entropy                        value:GAUGE:0:4294967295
 fanspeed               value:GAUGE:0:U
-file_size              bytes:GAUGE:0:U
+file_size              value:GAUGE:0:U
 files                  value:GAUGE:0:U
-frequency              frequency:GAUGE:0:U
-frequency_offset       ppm:GAUGE:-1000000:1000000
-fscache_stat           value:COUNTER:0:4294967295
 fork_rate              value:DERIVE:0:U
+frequency              value:GAUGE:0:U
+frequency_offset       value:GAUGE:-1000000:1000000
+fscache_stat           value:DERIVE:0:U
 gauge                  value:GAUGE:U:U
-http_request_methods   count:COUNTER:0:134217728
-http_requests          count:COUNTER:0:134217728
-http_response_codes    count:COUNTER:0:134217728
+http_request_methods   value:DERIVE:0:U
+http_requests          value:DERIVE:0:U
+http_response_codes    value:DERIVE:0:U
 humidity               value:GAUGE:0:100
-if_collisions          value:COUNTER:0:4294967295
-if_dropped             rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-if_errors              rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-if_multicast           value:COUNTER:0:4294967295
-if_octets              rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-if_packets             rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-if_rx_errors           value:COUNTER:0:4294967295
-if_tx_errors           value:COUNTER:0:4294967295
+if_collisions          value:DERIVE:0:U
+if_dropped             rx:DERIVE:0:U, tx:DERIVE:0:U
+if_errors              rx:DERIVE:0:U, tx:DERIVE:0:U
+if_multicast           value:DERIVE:0:U
+if_octets              rx:DERIVE:0:U, tx:DERIVE:0:U
+if_packets             rx:DERIVE:0:U, tx:DERIVE:0:U
+if_rx_errors           value:DERIVE:0:U
+if_tx_errors           value:DERIVE:0:U
 invocations            value:DERIVE:0:U
-io_octets              rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-io_packets             rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-ipt_bytes              value:COUNTER:0:134217728
-ipt_packets            value:COUNTER:0:134217728
-irq                    value:COUNTER:U:65535
+io_octets              rx:DERIVE:0:U, tx:DERIVE:0:U
+io_packets             rx:DERIVE:0:U, tx:DERIVE:0:U
+ipt_bytes              value:DERIVE:0:U
+ipt_packets            value:DERIVE:0:U
+irq                    value:DERIVE:0:U
 latency                        value:GAUGE:0:65535
 links                  value:GAUGE:0:U
 load                   shortterm:GAUGE:0:100, midterm:GAUGE:0:100, longterm:GAUGE:0:100
-memcached_command      value:COUNTER:0:U
+memcached_command      value:DERIVE:0:U
 memcached_connections  value:GAUGE:0:U
 memcached_items                value:GAUGE:0:U
-memcached_octets       rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-memcached_ops          value:COUNTER:0:134217728
+memcached_octets       rx:DERIVE:0:U, tx:DERIVE:0:U
+memcached_ops          value:DERIVE:0:U
 memory                 value:GAUGE:0:281474976710656
 multimeter             value:GAUGE:U:U
-mysql_commands         value:COUNTER:0:U
-mysql_handler          value:COUNTER:0:U
-mysql_locks            value:COUNTER:0:U
-mysql_log_position     value:COUNTER:0:4294967295
-mysql_octets           rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-mysql_qcache           hits:COUNTER:0:U, inserts:COUNTER:0:U, not_cached:COUNTER:0:U, lowmem_prunes:COUNTER:0:U, queries_in_cache:GAUGE:0:U
-mysql_threads          running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created:COUNTER:0:U
-nfs_procedure          value:COUNTER:0:4294967295
+mysql_commands         value:DERIVE:0:U
+mysql_handler          value:DERIVE:0:U
+mysql_locks            value:DERIVE:0:U
+mysql_log_position     value:DERIVE:0:U
+mysql_octets           rx:DERIVE:0:U, tx:DERIVE:0:U
+nfs_procedure          value:DERIVE:0:U
 nginx_connections      value:GAUGE:0:U
-nginx_requests         value:COUNTER:0:134217728
-node_octets            rx:COUNTER:0:U, tx:COUNTER:0:U
+nginx_requests         value:DERIVE:0:U
+node_octets            rx:DERIVE:0:U, tx:DERIVE:0:U
 node_rssi              value:GAUGE:0:255
-node_stat              value:COUNTER:0:4294967295
+node_stat              value:DERIVE:0:U
 node_tx_rate           value:GAUGE:0:127
-operations             value:COUNTER:0:4294967295
-percent                        percent:GAUGE:0:100.1
-pg_blks                        value:COUNTER:0:U
+operations             value:DERIVE:0:U
+percent                        value:GAUGE:0:100.1
+pg_blks                        value:DERIVE:0:U
 pg_db_size             value:GAUGE:0:U
-pg_n_tup_c             value:COUNTER:0:U
+pg_n_tup_c             value:DERIVE:0:U
 pg_n_tup_g             value:GAUGE:0:U
 pg_numbackends         value:GAUGE:0:U
-pg_scan                        value:COUNTER:0:U
-pg_xact                        value:COUNTER:0:U
+pg_scan                        value:DERIVE:0:U
+pg_xact                        value:DERIVE:0:U
 ping_droprate          value:GAUGE:0:100
-ping                   ping:GAUGE:0:65535
+ping                   value:GAUGE:0:65535
 ping_stddev            value:GAUGE:0:65535
 players                        value:GAUGE:0:1000000
 power                  value:GAUGE:0:U
-protocol_counter       value:COUNTER:0:U
+protocol_counter       value:DERIVE:0:U
+ps_code                        value:GAUGE:0:9223372036854775807
 ps_count               processes:GAUGE:0:1000000, threads:GAUGE:0:1000000
-ps_cputime             user:COUNTER:0:16000000, syst:COUNTER:0:16000000
-ps_pagefaults          minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807
+ps_cputime             user:DERIVE:0:U, syst:DERIVE:0:U
+ps_data                        value:GAUGE:0:9223372036854775807
 ps_disk_octets         read:DERIVE:0:U, write:DERIVE:0:U
 ps_disk_ops            read:DERIVE:0:U, write:DERIVE:0:U
+ps_pagefaults          minflt:DERIVE:0:U, majflt:DERIVE:0:U
 ps_rss                 value:GAUGE:0:9223372036854775807
-ps_code                        value:GAUGE:0:9223372036854775807
-ps_data                        value:GAUGE:0:9223372036854775807
 ps_stacksize           value:GAUGE:0:9223372036854775807
 ps_state               value:GAUGE:0:65535
 ps_vm                  value:GAUGE:0:9223372036854775807
 queue_length           value:GAUGE:0:U
+records                        value:GAUGE:0:U
+requests               value:GAUGE:0:U
 response_time          value:GAUGE:0:U
-records                        count:GAUGE:0:U
 route_etx              value:GAUGE:0:U
 route_metric           value:GAUGE:0:U
 routes                 value:GAUGE:0:U
-serial_octets          rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
+serial_octets          rx:DERIVE:0:U, tx:DERIVE:0:U
 signal_noise           value:GAUGE:U:0
 signal_power           value:GAUGE:U:0
 signal_quality         value:GAUGE:0:U
 snr                    value:GAUGE:0:U
 spam_check             value:GAUGE:0:U
 spam_score             value:GAUGE:U:U
-swap_io                        value:DERIVE:0:1099511627776
+swap_io                        value:DERIVE:0:U
 swap                   value:GAUGE:0:1099511627776
 tcp_connections                value:GAUGE:0:4294967295
 temperature            value:GAUGE:-273.15:U
 threads                        value:GAUGE:0:U
-time_dispersion                seconds:GAUGE:-1000000:1000000
-timeleft               timeleft:GAUGE:0:3600
-time_offset            seconds:GAUGE:-1000000:1000000
+time_dispersion                value:GAUGE:-1000000:1000000
+timeleft               value:GAUGE:0:3600
+time_offset            value:GAUGE:-1000000:1000000
 total_bytes            value:DERIVE:0:U
+total_connections      value:DERIVE:0:U
+total_operations       value:DERIVE:0:U
 total_requests         value:DERIVE:0:U
+total_sessions         value:DERIVE:0:U
+total_threads          value:DERIVE:0:U
 total_time_in_ms       value:DERIVE:0:U
 total_values           value:DERIVE:0:U
 uptime                 value:GAUGE:0:4294967295
-users                  users:GAUGE:0:65535
-virt_cpu_total         ns:COUNTER:0:256000000000
-virt_vcpu              ns:COUNTER:0:1000000000
-vmpage_action          value:COUNTER:0:4294967295
-vmpage_faults          minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807
-vmpage_io              in:COUNTER:0:4294967295, out:COUNTER:0:4294967295
+users                  value:GAUGE:0:65535
+vcpu                   value:GAUGE:0:U
+virt_cpu_total         value:DERIVE:0:U
+virt_vcpu              value:DERIVE:0:U
+vmpage_action          value:DERIVE:0:U
+vmpage_faults          minflt:DERIVE:0:U, majflt:DERIVE:0:U
+vmpage_io              in:DERIVE:0:U, out:DERIVE:0:U
 vmpage_number          value:GAUGE:0:4294967295
+volatile_changes       value:GAUGE:0:U
 voltage_threshold      value:GAUGE:U:U, threshold:GAUGE:U:U
 voltage                        value:GAUGE:U:U
 vs_memory              value:GAUGE:0:9223372036854775807
 vs_processes           value:GAUGE:0:65535
 vs_threads             value:GAUGE:0:65535
+#
+# Legacy types
+# (required for the v5 upgrade target)
+#
+arc_counts             demand_data:COUNTER:0:U, demand_metadata:COUNTER:0:U, prefetch_data:COUNTER:0:U, prefetch_metadata:COUNTER:0:U
+arc_l2_bytes           read:COUNTER:0:U, write:COUNTER:0:U
+arc_l2_size            value:GAUGE:0:U
+arc_ratio              value:GAUGE:0:U
+arc_size               current:GAUGE:0:U, target:GAUGE:0:U, minlimit:GAUGE:0:U, maxlimit:GAUGE:0:U
+mysql_qcache           hits:COUNTER:0:U, inserts:COUNTER:0:U, not_cached:COUNTER:0:U, lowmem_prunes:COUNTER:0:U, queries_in_cache:GAUGE:0:U
+mysql_threads          running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created:COUNTER:0:U
index 4971417..10cb4f2 100644 (file)
@@ -102,6 +102,10 @@ static void parse_line (char *buf)
   if (fields_num < 2)
     return;
 
+  /* Ignore lines which begin with a hash sign. */
+  if (fields[0][0] == '#')
+    return;
+
   ds = (data_set_t *) malloc (sizeof (data_set_t));
   if (ds == NULL)
     return;
index 35c7712..0dc7d65 100644 (file)
@@ -26,7 +26,6 @@
 
 #include "utils_cmd_flush.h"
 #include "utils_cmd_getval.h"
-#include "utils_cmd_getthreshold.h"
 #include "utils_cmd_listval.h"
 #include "utils_cmd_putval.h"
 #include "utils_cmd_putnotif.h"
@@ -54,7 +53,8 @@ static const char *config_keys[] =
 {
        "SocketFile",
        "SocketGroup",
-       "SocketPerms"
+       "SocketPerms",
+       "DeleteSocket"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
@@ -65,6 +65,7 @@ static int   sock_fd    = -1;
 static char *sock_file  = NULL;
 static char *sock_group = NULL;
 static int   sock_perms = S_IRWXU | S_IRWXG;
+static _Bool delete_socket = 0;
 
 static pthread_t listen_thread = (pthread_t) 0;
 
@@ -89,10 +90,27 @@ static int us_open_socket (void)
        sa.sun_family = AF_UNIX;
        sstrncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
                        sizeof (sa.sun_path));
-       /* unlink (sa.sun_path); */
 
        DEBUG ("unixsock plugin: socket path = %s", sa.sun_path);
 
+       if (delete_socket)
+       {
+               errno = 0;
+               status = unlink (sa.sun_path);
+               if ((status != 0) && (errno != ENOENT))
+               {
+                       char errbuf[1024];
+                       WARNING ("unixsock plugin: Deleting socket file \"%s\" failed: %s",
+                                       sa.sun_path,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+               }
+               else if (status == 0)
+               {
+                       INFO ("unixsock plugin: Successfully deleted socket file \"%s\".",
+                                       sa.sun_path);
+               }
+       }
+
        status = bind (sock_fd, (struct sockaddr *) &sa, sizeof (sa));
        if (status != 0)
        {
@@ -263,10 +281,6 @@ static void *us_handle_client (void *arg)
                {
                        handle_getval (fhout, buffer);
                }
-               else if (strcasecmp (fields[0], "getthreshold") == 0)
-               {
-                       handle_getthreshold (fhout, buffer);
-               }
                else if (strcasecmp (fields[0], "putval") == 0)
                {
                        handle_putval (fhout, buffer);
@@ -401,6 +415,13 @@ static int us_config (const char *key, const char *val)
        {
                sock_perms = (int) strtol (val, NULL, 8);
        }
+       else if (strcasecmp (key, "DeleteSocket") == 0)
+       {
+               if (IS_TRUE (val))
+                       delete_socket = 1;
+               else
+                       delete_socket = 0;
+       }
        else
        {
                return (-1);
index aeb662d..dd5bcb5 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/utils_cache.c
- * Copyright (C) 2007,2008  Florian octo Forster
+ * Copyright (C) 2007-2010  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Author:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
@@ -24,7 +24,6 @@
 #include "plugin.h"
 #include "utils_avltree.h"
 #include "utils_cache.h"
-#include "utils_threshold.h"
 #include "meta_data.h"
 
 #include <assert.h>
@@ -38,13 +37,13 @@ typedef struct cache_entry_s
        value_t   *values_raw;
        /* Time contained in the package
         * (for calculating rates) */
-       time_t last_time;
+       cdtime_t last_time;
        /* Time according to the local clock
         * (for purging old entries) */
-       time_t last_update;
+       cdtime_t last_update;
        /* Interval in which the data is collected
         * (for purding old entries) */
-       int interval;
+       cdtime_t interval;
        int state;
        int hits;
 
@@ -120,80 +119,6 @@ static void cache_free (cache_entry_t *ce)
   sfree (ce);
 } /* void cache_free */
 
-static int uc_send_notification (const char *name)
-{
-  cache_entry_t *ce = NULL;
-  int status;
-
-  char *name_copy;
-  char *host;
-  char *plugin;
-  char *plugin_instance;
-  char *type;
-  char *type_instance;
-
-  notification_t n;
-
-  name_copy = strdup (name);
-  if (name_copy == NULL)
-  {
-    ERROR ("uc_send_notification: strdup failed.");
-    return (-1);
-  }
-
-  status = parse_identifier (name_copy, &host,
-      &plugin, &plugin_instance,
-      &type, &type_instance);
-  if (status != 0)
-  {
-    ERROR ("uc_send_notification: Cannot parse name `%s'", name);
-    return (-1);
-  }
-
-  /* Copy the associative members */
-  notification_init (&n, NOTIF_FAILURE, /* host = */ NULL,
-      host, plugin, plugin_instance, type, type_instance);
-
-  sfree (name_copy);
-  name_copy = host = plugin = plugin_instance = type = type_instance = NULL;
-
-  pthread_mutex_lock (&cache_lock);
-
-  /*
-   * Set the time _after_ getting the lock because we don't know how long
-   * acquiring the lock takes and we will use this time later to decide
-   * whether or not the state is OKAY.
-   */
-  n.time = time (NULL);
-
-  status = c_avl_get (cache_tree, name, (void *) &ce);
-  if (status != 0)
-  {
-    pthread_mutex_unlock (&cache_lock);
-    sfree (name_copy);
-    return (-1);
-  }
-    
-  /* Check if the entry has been updated in the meantime */
-  if ((n.time - ce->last_update) < (timeout_g * ce->interval))
-  {
-    ce->state = STATE_OKAY;
-    pthread_mutex_unlock (&cache_lock);
-    sfree (name_copy);
-    return (-1);
-  }
-
-  ssnprintf (n.message, sizeof (n.message),
-      "%s has not been updated for %i seconds.", name,
-      (int) (n.time - ce->last_update));
-
-  pthread_mutex_unlock (&cache_lock);
-
-  plugin_dispatch_notification (&n);
-
-  return (0);
-} /* int uc_send_notification */
-
 static void uc_check_range (const data_set_t *ds, cache_entry_t *ce)
 {
   int i;
@@ -258,7 +183,7 @@ static int uc_insert (const data_set_t *ds, const value_list_t *vl,
        ce->values_gauge[i] = NAN;
        if (vl->interval > 0)
          ce->values_gauge[i] = ((double) vl->values[i].absolute)
-           / ((double) vl->interval);
+           / CDTIME_T_TO_DOUBLE (vl->interval);
        ce->values_raw[i].absolute = vl->values[i].absolute;
        break;
        
@@ -274,7 +199,7 @@ static int uc_insert (const data_set_t *ds, const value_list_t *vl,
   uc_check_range (ds, ce);
 
   ce->last_time = vl->time;
-  ce->last_update = time (NULL);
+  ce->last_update = cdtime ();
   ce->interval = vl->interval;
   ce->state = STATE_OKAY;
 
@@ -300,145 +225,133 @@ int uc_init (void)
 
 int uc_check_timeout (void)
 {
-  time_t now;
+  cdtime_t now;
   cache_entry_t *ce;
 
   char **keys = NULL;
+  cdtime_t *keys_time = NULL;
+  cdtime_t *keys_interval = NULL;
   int keys_len = 0;
 
   char *key;
   c_avl_iterator_t *iter;
+
+  int status;
   int i;
   
   pthread_mutex_lock (&cache_lock);
 
-  now = time (NULL);
+  now = cdtime ();
 
   /* Build a list of entries to be flushed */
   iter = c_avl_get_iterator (cache_tree);
   while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0)
   {
-    /* If entry has not been updated, add to `keys' array */
-    if ((now - ce->last_update) >= (timeout_g * ce->interval))
-    {
-      char **tmp;
-
-      tmp = (char **) realloc ((void *) keys,
-         (keys_len + 1) * sizeof (char *));
-      if (tmp == NULL)
-      {
-       ERROR ("uc_check_timeout: realloc failed.");
-       c_avl_iterator_destroy (iter);
-       sfree (keys);
-       pthread_mutex_unlock (&cache_lock);
-       return (-1);
-      }
-
-      keys = tmp;
-      keys[keys_len] = strdup (key);
-      if (keys[keys_len] == NULL)
-      {
-       ERROR ("uc_check_timeout: strdup failed.");
-       continue;
-      }
-      keys_len++;
-    }
-  } /* while (c_avl_iterator_next) */
-
-  ce = NULL;
-
-  for (i = 0; i < keys_len; i++)
-  {
-    int status;
+    char **tmp;
+    cdtime_t *tmp_time;
 
-    status = ut_check_interesting (keys[i]);
+    /* If the entry is fresh enough, continue. */
+    if ((now - ce->last_update) < (ce->interval * timeout_g))
+      continue;
 
-    if (status < 0)
+    /* If entry has not been updated, add to `keys' array */
+    tmp = (char **) realloc ((void *) keys,
+       (keys_len + 1) * sizeof (char *));
+    if (tmp == NULL)
     {
-      ERROR ("uc_check_timeout: ut_check_interesting failed.");
-      sfree (keys[i]);
+      ERROR ("uc_check_timeout: realloc failed.");
       continue;
     }
-    else if (status == 0) /* ``service'' is uninteresting */
+    keys = tmp;
+
+    tmp_time = realloc (keys_time, (keys_len + 1) * sizeof (*keys_time));
+    if (tmp_time == NULL)
     {
-      DEBUG ("uc_check_timeout: %s is missing but ``uninteresting''",
-         keys[i]);
-      ce = NULL;
-      status = c_avl_remove (cache_tree, keys[i],
-         (void *) &key, (void *) &ce);
-      if (status != 0)
-      {
-       ERROR ("uc_check_timeout: c_avl_remove (%s) failed.", keys[i]);
-      }
-      sfree (keys[i]);
-      sfree (key);
-      if (ce != NULL)
-        cache_free (ce);
+      ERROR ("uc_check_timeout: realloc failed.");
       continue;
     }
+    keys_time = tmp_time;
 
-    /* If we get here, the value is ``interesting''. Query the record from the
-     * cache and update the state field. */
-    if (c_avl_get (cache_tree, keys[i], (void *) &ce) != 0)
+    tmp_time = realloc (keys_interval, (keys_len + 1) * sizeof (*keys_interval));
+    if (tmp_time == NULL)
     {
-      ERROR ("uc_check_timeout: cannot get data for %s from cache", keys[i]);
-      /* Do not free `keys[i]' so a notification is sent further down. */
+      ERROR ("uc_check_timeout: realloc failed.");
       continue;
     }
-    assert (ce != NULL);
+    keys_interval = tmp_time;
 
-    if (status == 2) /* persist */
-    {
-      DEBUG ("uc_check_timeout: %s is missing, sending notification.",
-         keys[i]);
-      ce->state = STATE_MISSING;
-      /* Do not free `keys[i]' so a notification is sent further down. */
-    }
-    else if (status == 1) /* do not persist */
-    {
-      if (ce->state == STATE_MISSING)
-      {
-       DEBUG ("uc_check_timeout: %s is missing but "
-           "notification has already been sent.",
-           keys[i]);
-       /* Set `keys[i]' to NULL to no notification is sent. */
-       sfree (keys[i]);
-      }
-      else /* (ce->state != STATE_MISSING) */
-      {
-       DEBUG ("uc_check_timeout: %s is missing, sending one notification.",
-           keys[i]);
-       ce->state = STATE_MISSING;
-       /* Do not free `keys[i]' so a notification is sent further down. */
-      }
-    }
-    else
+    keys[keys_len] = strdup (key);
+    if (keys[keys_len] == NULL)
     {
-      WARNING ("uc_check_timeout: ut_check_interesting (%s) returned "
-         "invalid status %i.",
-         keys[i], status);
-      sfree (keys[i]);
+      ERROR ("uc_check_timeout: strdup failed.");
+      continue;
     }
+    keys_time[keys_len] = ce->last_time;
+    keys_interval[keys_len] = ce->interval;
 
-    /* Make really sure the next iteration doesn't work with this pointer.
-     * There have been too many bugs in the past.. :/  -- octo */
-    ce = NULL;
-  } /* for (keys[i]) */
+    keys_len++;
+  } /* while (c_avl_iterator_next) */
 
   c_avl_iterator_destroy (iter);
-
   pthread_mutex_unlock (&cache_lock);
 
+  if (keys_len == 0)
+    return (0);
+
+  /* Call the "missing" callback for each value. Do this before removing the
+   * value from the cache, so that callbacks can still access the data stored,
+   * including plugin specific meta data, rates, history, …. This must be done
+   * without holding the lock, otherwise we will run into a deadlock if a
+   * plugin calls the cache interface. */
   for (i = 0; i < keys_len; i++)
   {
-    if (keys[i] == NULL)
+    value_list_t vl = VALUE_LIST_INIT;
+
+    vl.values = NULL;
+    vl.values_len = 0;
+    vl.meta = NULL;
+
+    status = parse_identifier_vl (keys[i], &vl);
+    if (status != 0)
+    {
+      ERROR ("uc_check_timeout: parse_identifier_vl (\"%s\") failed.", keys[i]);
+      cache_free (ce);
+      continue;
+    }
+
+    vl.time = keys_time[i];
+    vl.interval = keys_interval[i];
+
+    plugin_dispatch_missing (&vl);
+  } /* for (i = 0; i < keys_len; i++) */
+
+  /* Now actually remove all the values from the cache. We don't re-evaluate
+   * the timestamp again, so in theory it is possible we remove a value after
+   * it is updated here. */
+  pthread_mutex_lock (&cache_lock);
+  for (i = 0; i < keys_len; i++)
+  {
+    key = NULL;
+    ce = NULL;
+
+    status = c_avl_remove (cache_tree, keys[i],
+       (void *) &key, (void *) &ce);
+    if (status != 0)
+    {
+      ERROR ("uc_check_timeout: c_avl_remove (\"%s\") failed.", keys[i]);
+      sfree (keys[i]);
       continue;
+    }
 
-    uc_send_notification (keys[i]);
     sfree (keys[i]);
-  }
+    sfree (key);
+    cache_free (ce);
+  } /* for (i = 0; i < keys_len; i++) */
+  pthread_mutex_unlock (&cache_lock);
 
   sfree (keys);
+  sfree (keys_time);
+  sfree (keys_interval);
 
   return (0);
 } /* int uc_check_timeout */
@@ -447,9 +360,6 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
 {
   char name[6 * DATA_MAX_NAME_LEN];
   cache_entry_t *ce = NULL;
-  int send_okay_notification = 0;
-  time_t update_delay = 0;
-  notification_t n;
   int status;
   int i;
 
@@ -475,21 +385,14 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
   if (ce->last_time >= vl->time)
   {
     pthread_mutex_unlock (&cache_lock);
-    NOTICE ("uc_update: Value too old: name = %s; value time = %u; "
-       "last cache update = %u;",
-       name, (unsigned int) vl->time, (unsigned int) ce->last_time);
+    NOTICE ("uc_update: Value too old: name = %s; value time = %.3f; "
+       "last cache update = %.3f;",
+       name,
+       CDTIME_T_TO_DOUBLE (vl->time),
+       CDTIME_T_TO_DOUBLE (ce->last_time));
     return (-1);
   }
 
-  /* Send a notification (after the lock has been released) if we switch the
-   * state from something else to `okay'. */
-  if (ce->state == STATE_MISSING)
-  {
-    send_okay_notification = 1;
-    ce->state = STATE_OKAY;
-    update_delay = time (NULL) - ce->last_update;
-  }
-
   for (i = 0; i < ds->ds_num; i++)
   {
     switch (ds->ds[i].type)
@@ -514,7 +417,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
          }
 
          ce->values_gauge[i] = ((double) diff)
-           / ((double) (vl->time - ce->last_time));
+           / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
          ce->values_raw[i].counter = vl->values[i].counter;
        }
        break;
@@ -531,14 +434,14 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
          diff = vl->values[i].derive - ce->values_raw[i].derive;
 
          ce->values_gauge[i] = ((double) diff)
-           / ((double) (vl->time - ce->last_time));
+           / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
          ce->values_raw[i].derive = vl->values[i].derive;
        }
        break;
 
       case DS_TYPE_ABSOLUTE:
        ce->values_gauge[i] = ((double) vl->values[i].absolute)
-         / ((double) (vl->time - ce->last_time));
+         / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
        ce->values_raw[i].absolute = vl->values[i].absolute;
        break;
 
@@ -571,33 +474,11 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
   uc_check_range (ds, ce);
 
   ce->last_time = vl->time;
-  ce->last_update = time (NULL);
+  ce->last_update = cdtime ();
   ce->interval = vl->interval;
 
   pthread_mutex_unlock (&cache_lock);
 
-  if (send_okay_notification == 0)
-    return (0);
-
-  /* Do not send okay notifications for uninteresting values, i. e. values for
-   * which no threshold is configured. */
-  status = ut_check_interesting (name);
-  if (status <= 0)
-    return (0);
-
-  /* Initialize the notification */
-  memset (&n, '\0', sizeof (n));
-  NOTIFICATION_INIT_VL (&n, vl, ds);
-
-  n.severity = NOTIF_OKAY;
-  n.time = vl->time;
-
-  ssnprintf (n.message, sizeof (n.message),
-      "Received a value for %s. It was missing for %u seconds.",
-      name, (unsigned int) update_delay);
-
-  plugin_dispatch_notification (&n);
-
   return (0);
 } /* int uc_update */
 
@@ -682,14 +563,14 @@ gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
   return (ret);
 } /* gauge_t *uc_get_rate */
 
-int uc_get_names (char ***ret_names, time_t **ret_times, size_t *ret_number)
+int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number)
 {
   c_avl_iterator_t *iter;
   char *key;
   cache_entry_t *value;
 
   char **names = NULL;
-  time_t *times = NULL;
+  cdtime_t *times = NULL;
   size_t number = 0;
 
   int status = 0;
@@ -710,9 +591,9 @@ int uc_get_names (char ***ret_names, time_t **ret_times, size_t *ret_number)
 
     if (ret_times != NULL)
     {
-      time_t *tmp_times;
+      cdtime_t *tmp_times;
 
-      tmp_times = (time_t *) realloc (times, sizeof (time_t) * (number + 1));
+      tmp_times = (cdtime_t *) realloc (times, sizeof (cdtime_t) * (number + 1));
       if (tmp_times == NULL)
       {
        status = -1;
index f8059ec..87f93c0 100644 (file)
@@ -35,7 +35,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl);
 int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_values_num);
 gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl);
 
-int uc_get_names (char ***ret_names, time_t **ret_times, size_t *ret_number);
+int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number);
 
 int uc_get_state (const data_set_t *ds, const value_list_t *vl);
 int uc_set_state (const data_set_t *ds, const value_list_t *vl, int state);
index 0e7b350..3584f3b 100644 (file)
@@ -54,7 +54,7 @@ int handle_flush (FILE *fh, char *buffer)
        int success = 0;
        int error   = 0;
 
-       int timeout = -1;
+       double timeout = 0.0;
        char **plugins = NULL;
        int plugins_num = 0;
        char **identifiers = NULL;
@@ -106,9 +106,9 @@ int handle_flush (FILE *fh, char *buffer)
                        
                        errno = 0;
                        endptr = NULL;
-                       timeout = strtol (opt_value, &endptr, 0);
+                       timeout = strtod (opt_value, &endptr);
 
-                       if ((endptr == opt_value) || (errno != 0))
+                       if ((endptr == opt_value) || (errno != 0) || (!isfinite (timeout)))
                        {
                                print_to_socket (fh, "-1 Invalid value for option `timeout': "
                                                "%s\n", opt_value);
@@ -116,8 +116,10 @@ int handle_flush (FILE *fh, char *buffer)
                                sfree (identifiers);
                                return (-1);
                        }
-                       else if (timeout <= 0)
-                               timeout = -1;
+                       else if (timeout < 0.0)
+                       {
+                               timeout = 0.0;
+                       }
                }
                else
                {
@@ -149,7 +151,9 @@ int handle_flush (FILE *fh, char *buffer)
                        int status;
 
                        identifier = identifiers[j];
-                       status = plugin_flush (plugin, timeout, identifier);
+                       status = plugin_flush (plugin,
+                                       DOUBLE_TO_CDTIME_T (timeout),
+                                       identifier);
                        if (status == 0)
                                success++;
                        else
index 4ca9646..ef66af5 100644 (file)
@@ -50,7 +50,7 @@ int handle_listval (FILE *fh, char *buffer)
 {
   char *command;
   char **names = NULL;
-  time_t *times = NULL;
+  cdtime_t *times = NULL;
   size_t number = 0;
   size_t i;
   int status;
@@ -90,7 +90,8 @@ int handle_listval (FILE *fh, char *buffer)
   print_to_socket (fh, "%i Value%s found\n",
       (int) number, (number == 1) ? "" : "s");
   for (i = 0; i < number; i++)
-    print_to_socket (fh, "%u %s\n", (unsigned int) times[i], names[i]);
+    print_to_socket (fh, "%.3f %s\n", CDTIME_T_TO_DOUBLE (times[i]),
+               names[i]);
 
   free_everything_and_return (0);
 } /* int handle_listval */
index ec2b5f8..dd43337 100644 (file)
@@ -56,16 +56,16 @@ static int set_option (value_list_t *vl, const char *key, const char *value)
 
        if (strcasecmp ("interval", key) == 0)
        {
-               int tmp;
+               double tmp;
                char *endptr;
 
                endptr = NULL;
                errno = 0;
-               tmp = strtol (value, &endptr, 0);
+               tmp = strtod (value, &endptr);
 
                if ((errno == 0) && (endptr != NULL)
-                               && (endptr != value) && (tmp > 0))
-                       vl->interval = tmp;
+                               && (endptr != value) && (tmp > 0.0))
+                       vl->interval = DOUBLE_TO_CDTIME_T (tmp);
        }
        else
                return (1);
@@ -227,3 +227,31 @@ int handle_putval (FILE *fh, char *buffer)
        return (0);
 } /* int handle_putval */
 
+int create_putval (char *ret, size_t ret_len, /* {{{ */
+       const data_set_t *ds, const value_list_t *vl)
+{
+       char buffer_ident[6 * DATA_MAX_NAME_LEN];
+       char buffer_values[1024];
+       int status;
+
+       status = FORMAT_VL (buffer_ident, sizeof (buffer_ident), vl);
+       if (status != 0)
+               return (status);
+       escape_string (buffer_ident, sizeof (buffer_ident));
+
+       status = format_values (buffer_values, sizeof (buffer_values),
+                       ds, vl, /* store rates = */ 0);
+       if (status != 0)
+               return (status);
+       escape_string (buffer_values, sizeof (buffer_values));
+
+       ssnprintf (ret, ret_len,
+                       "PUTVAL %s interval=%.3f %s",
+                       buffer_ident,
+                       (vl->interval > 0)
+                       ? CDTIME_T_TO_DOUBLE (vl->interval)
+                       : CDTIME_T_TO_DOUBLE (interval_g),
+                       buffer_values);
+
+       return (0);
+} /* }}} int create_putval */
index 8460b13..9c92fd3 100644 (file)
 
 #include <stdio.h>
 
+#include "plugin.h"
+
 int handle_putval (FILE *fh, char *buffer);
 
+int create_putval (char *ret, size_t ret_len,
+               const data_set_t *ds, const value_list_t *vl);
+
 #endif /* UTILS_CMD_PUTVAL_H */
index 675272c..aadf9c5 100644 (file)
@@ -39,15 +39,6 @@ struct udb_result_s
   char   **values;
   size_t   values_num;
 
-  /* Legacy data */
-  int legacy_mode;
-  size_t legacy_position;
-  /* When in legacy mode:
-   * - type/ds hold the format of the data
-   * - instance_prefix is used as type-instance if non-NULL
-   * - legacy_position holds the index of the column to use as value.
-   */
-
   udb_result_t *next;
 }; /* }}} */
 
@@ -57,8 +48,6 @@ struct udb_query_s /* {{{ */
   char *statement;
   void *user_data;
 
-  int legacy_mode;
-
   unsigned int min_version;
   unsigned int max_version;
 
@@ -84,7 +73,7 @@ struct udb_query_preparation_area_s /* {{{ */
   char *plugin;
   char *db_name;
 
-  int interval;
+  cdtime_t interval;
 
   udb_result_preparation_area_t *result_prep_areas;
 }; /* }}} */
@@ -191,173 +180,6 @@ static int udb_config_set_uint (unsigned int *ret_value, /* {{{ */
 } /* }}} int udb_config_set_uint */
 
 /*
- * Legacy result private functions
- */
-static void udb_legacy_result_finish_result (udb_result_t const *r, /* {{{ */
-    udb_result_preparation_area_t *prep_area)
-{
-  if ((r == NULL) || (prep_area))
-    return;
-
-  assert (r->legacy_mode == 1);
-
-  prep_area->ds = NULL;
-} /* }}} void udb_legacy_result_finish_result */
-
-static int udb_legacy_result_handle_result (udb_result_t *r, /* {{{ */
-    udb_query_preparation_area_t *q_area,
-    udb_result_preparation_area_t *r_area,
-    udb_query_t const *q, char **column_values)
-{
-  value_list_t vl = VALUE_LIST_INIT;
-  value_t value;
-  char *value_str;
-
-  assert (r->legacy_mode == 1);
-  assert (r_area->ds != NULL);
-  assert (r_area->ds->ds_num == 1);
-
-  vl.values = &value;
-  vl.values_len = 1;
-
-  value_str = column_values[r->legacy_position];
-  if (0 != parse_value (value_str, &vl.values[0], r_area->ds->ds[0].type))
-  {
-    ERROR ("db query utils: udb_legacy_result_handle_result: "
-        "Parsing `%s' as %s failed.", value_str,
-        DS_TYPE_TO_STRING (r_area->ds->ds[0].type));
-    errno = EINVAL;
-    return (-1);
-  }
-
-  if (q_area->interval > 0)
-    vl.interval = q_area->interval;
-
-  sstrncpy (vl.host, q_area->host, sizeof (vl.host));
-  sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
-  sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
-  sstrncpy (vl.type, r->type, sizeof (vl.type));
-
-  if (r->instance_prefix != NULL)
-    sstrncpy (vl.type_instance, r->instance_prefix,
-        sizeof (vl.type_instance));
-
-  plugin_dispatch_values (&vl);
-
-  return (0);
-} /* }}} int udb_legacy_result_handle_result */
-
-static int udb_legacy_result_prepare_result (udb_result_t const *r, /* {{{ */
-    udb_result_preparation_area_t *prep_area,
-    char **column_names, size_t column_num)
-{
-  if (r == NULL)
-    return (-EINVAL);
-
-  assert (r->legacy_mode == 1);
-
-  /* Make sure previous preparations are cleaned up. */
-  udb_legacy_result_finish_result (r, prep_area);
-
-  if (r->legacy_position >= column_num)
-  {
-    ERROR ("db query utils: The legacy configuration specified (at least) "
-        "%zu `Column's, but the query returned only %zu columns!",
-        r->legacy_position + 1, column_num);
-    return (-ENOENT);
-  }
-
-  /* Read `ds' and check number of values {{{ */
-  prep_area->ds = plugin_get_ds (r->type);
-  if (prep_area->ds == NULL)
-  {
-    ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not "
-        "known by the daemon. See types.db(5) for details.",
-        r->type);
-    return (-1);
-  }
-
-  if (prep_area->ds->ds_num != 1)
-  {
-    ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
-        "requires exactly %i values, but the legacy configuration "
-        "requires exactly one!",
-        r->type,
-        prep_area->ds->ds_num);
-    return (-1);
-  }
-  /* }}} */
-
-  return (0);
-} /* }}} int udb_legacy_result_prepare_result */
-
-static int udb_legacy_result_create (const char *query_name, /* {{{ */
-    udb_result_t **r_head, oconfig_item_t *ci, size_t position)
-{
-  udb_result_t *r;
-
-  if ((ci->values_num < 1) || (ci->values_num > 2)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING)
-      || ((ci->values_num == 2)
-        && (ci->values[1].type != OCONFIG_TYPE_STRING)))
-  {
-    WARNING ("db query utils: The `Column' block needs either one or two "
-        "string arguments.");
-    return (-1);
-  }
-
-  r = (udb_result_t *) malloc (sizeof (*r));
-  if (r == NULL)
-  {
-    ERROR ("db query utils: malloc failed.");
-    return (-1);
-  }
-  memset (r, 0, sizeof (*r));
-
-  r->legacy_mode = 1;
-  r->legacy_position = position;
-
-  r->type = strdup (ci->values[0].value.string);
-  if (r->type == NULL)
-  {
-    ERROR ("db query utils: strdup failed.");
-    free (r);
-    return (-1);
-  }
-
-  r->instance_prefix = NULL;
-  if (ci->values_num == 2)
-  {
-    r->instance_prefix = strdup (ci->values[1].value.string);
-    if (r->instance_prefix == NULL)
-    {
-      ERROR ("db query utils: strdup failed.");
-      free (r->type);
-      free (r);
-      return (-1);
-    }
-  }
-
-  /* If all went well, add this result to the list of results. */
-  if (*r_head == NULL)
-  {
-    *r_head = r;
-  }
-  else
-  {
-    udb_result_t *last;
-
-    last = *r_head;
-    while (last->next != NULL)
-      last = last->next;
-
-    last->next = r;
-  }
-
-  return (0);
-} /* }}} int udb_legacy_result_create */
-
-/*
  * Result private functions
  */
 static int udb_result_submit (udb_result_t *r, /* {{{ */
@@ -368,7 +190,6 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
   size_t i;
 
   assert (r != NULL);
-  assert (r->legacy_mode == 0);
   assert (r_area->ds != NULL);
   assert (((size_t) r_area->ds->ds_num) == r->values_num);
 
@@ -444,14 +265,6 @@ static void udb_result_finish_result (udb_result_t const *r, /* {{{ */
   if ((r == NULL) || (prep_area == NULL))
     return;
 
-  if (r->legacy_mode == 1)
-  {
-    udb_legacy_result_finish_result (r, prep_area);
-    return;
-  }
-
-  assert (r->legacy_mode == 0);
-
   prep_area->ds = NULL;
   sfree (prep_area->instances_pos);
   sfree (prep_area->values_pos);
@@ -468,12 +281,6 @@ static int udb_result_handle_result (udb_result_t *r, /* {{{ */
 
   assert (r && q_area && r_area);
 
-  if (r->legacy_mode == 1)
-    return (udb_legacy_result_handle_result (r, q_area, r_area,
-          q, column_values));
-
-  assert (r->legacy_mode == 0);
-
   for (i = 0; i < r->instances_num; i++)
     r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]];
 
@@ -492,12 +299,6 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
   if ((r == NULL) || (prep_area == NULL))
     return (-EINVAL);
 
-  if (r->legacy_mode == 1)
-    return (udb_legacy_result_prepare_result (r, prep_area,
-          column_names, column_num));
-
-  assert (r->legacy_mode == 0);
-
 #define BAIL_OUT(status) \
   prep_area->ds = NULL; \
   sfree (prep_area->instances_pos); \
@@ -759,7 +560,7 @@ void udb_query_free_one (udb_query_t *q) /* {{{ */
  */
 int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
     size_t *ret_query_list_len, oconfig_item_t *ci,
-    udb_query_create_callback_t cb, int legacy_mode)
+    udb_query_create_callback_t cb)
 {
   udb_query_t **query_list;
   size_t        query_list_len;
@@ -768,8 +569,6 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
   int status;
   int i;
 
-  size_t legacy_position;
-
   if ((ret_query_list == NULL) || (ret_query_list_len == NULL))
     return (-EINVAL);
   query_list     = *ret_query_list;
@@ -790,12 +589,9 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
     return (-1);
   }
   memset (q, 0, sizeof (*q));
-  q->legacy_mode = legacy_mode;
   q->min_version = 0;
   q->max_version = UINT_MAX;
 
-  legacy_position = 0;
-
   status = udb_config_set_string (&q->name, ci);
   if (status != 0)
   {
@@ -817,42 +613,6 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
     else if (strcasecmp ("MaxVersion", child->key) == 0)
       status = udb_config_set_uint (&q->max_version, child);
 
-    /* PostgreSQL compatibility code */
-    else if ((strcasecmp ("Query", child->key) == 0)
-        && (q->legacy_mode == 1))
-    {
-      WARNING ("db query utils: Query `%s': The `Query' option is "
-          "deprecated. Please use `Statement' instead.",
-          q->name);
-      status = udb_config_set_string (&q->statement, child);
-    }
-    else if ((strcasecmp ("Column", child->key) == 0)
-        && (q->legacy_mode == 1))
-    {
-      WARNING ("db query utils: Query `%s': The `Column' option is "
-          "deprecated. Please use the new syntax instead.",
-          q->name);
-      status = udb_legacy_result_create (q->name, &q->results, child,
-          legacy_position);
-      legacy_position++;
-    }
-    else if ((strcasecmp ("MinPGVersion", child->key) == 0)
-        && (q->legacy_mode == 1))
-    {
-      WARNING ("db query utils: Query `%s': The `MinPGVersion' option is "
-          "deprecated. Please use `MinVersion' instead.",
-          q->name);
-      status = udb_config_set_uint (&q->min_version, child);
-    }
-    else if ((strcasecmp ("MaxPGVersion", child->key) == 0)
-        && (q->legacy_mode == 1))
-    {
-      WARNING ("db query utils: Query `%s': The `MaxPGVersion' option is "
-          "deprecated. Please use `MaxVersion' instead.",
-          q->name);
-      status = udb_config_set_uint (&q->max_version, child);
-    }
-
     /* Call custom callbacks */
     else if (cb != NULL)
     {
@@ -1079,7 +839,7 @@ void udb_query_finish_result (udb_query_t const *q, /* {{{ */
   sfree (prep_area->plugin);
   sfree (prep_area->db_name);
 
-  prep_area->interval = -1;
+  prep_area->interval = 0;
 
   for (r = q->results, r_area = prep_area->result_prep_areas;
       r != NULL; r = r->next, r_area = r_area->next)
@@ -1147,7 +907,7 @@ int udb_query_handle_result (udb_query_t const *q, /* {{{ */
 int udb_query_prepare_result (udb_query_t const *q, /* {{{ */
     udb_query_preparation_area_t *prep_area,
     const char *host, const char *plugin, const char *db_name,
-    char **column_names, size_t column_num, int interval)
+    char **column_names, size_t column_num, cdtime_t interval)
 {
   udb_result_preparation_area_t *r_area;
   udb_result_t *r;
index 7856bdb..b6f4cea 100644 (file)
@@ -41,7 +41,7 @@ typedef int (*udb_query_create_callback_t) (udb_query_t *q,
  */
 int udb_query_create (udb_query_t ***ret_query_list,
     size_t *ret_query_list_len, oconfig_item_t *ci,
-    udb_query_create_callback_t cb, int legacy_mode);
+    udb_query_create_callback_t cb);
 void udb_query_free (udb_query_t **query_list, size_t query_list_len);
 
 int udb_query_pick_from_list_by_name (const char *name,
@@ -68,7 +68,7 @@ int udb_query_check_version (udb_query_t *q, unsigned int version);
 int udb_query_prepare_result (udb_query_t const *q,
     udb_query_preparation_area_t *prep_area,
     const char *host, const char *plugin, const char *db_name,
-    char **column_names, size_t column_num, int interval);
+    char **column_names, size_t column_num, cdtime_t interval);
 int udb_query_handle_result (udb_query_t const *q,
     udb_query_preparation_area_t *prep_area, char **column_values);
 void udb_query_finish_result (udb_query_t const *q,
index 2899bd4..80a2ee5 100644 (file)
 #if HAVE_NETINET_IN_H
 # include <netinet/in.h>
 #endif
+#if HAVE_NETINET_IP6_H
+# include <netinet/ip6.h>
+#endif
+#if HAVE_NETINET_IP_COMPAT_H
+# include <netinet/ip_compat.h>
+#endif
 #if HAVE_ARPA_INET_H
 # include <arpa/inet.h>
 #endif
@@ -291,13 +297,18 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
     off_t no = 0;
     unsigned char c;
     size_t len;
-    assert(ns > 0);
+    static int loop_detect = 0;
+    if (loop_detect > 2)
+       return 4;               /* compression loop */
+    if (ns <= 0)
+       return 4;               /* probably compression loop */
     do {
        if ((*off) >= sz)
            break;
        c = *(buf + (*off));
        if (c > 191) {
            /* blasted compression */
+           int rc;
            unsigned short s;
            off_t ptr;
            memcpy(&s, buf + (*off), sizeof(s));
@@ -305,18 +316,23 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
            (*off) += sizeof(s);
            /* Sanity check */
            if ((*off) >= sz)
-               return 1;
+               return 1;       /* message too short */
            ptr = s & 0x3FFF;
            /* Make sure the pointer is inside this message */
            if (ptr >= sz)
-               return 2;
-           return rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
+               return 2;       /* bad compression ptr */
+           if (ptr < DNS_MSG_HDR_SZ)
+               return 2;       /* bad compression ptr */
+           loop_detect++;
+           rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
+           loop_detect--;
+           return rc;
        } else if (c > RFC1035_MAXLABELSZ) {
            /*
             * "(The 10 and 01 combinations are reserved for future use.)"
             */
+           return 3;           /* reserved label/compression flags */
            break;
-           return 3;
        } else {
            (*off)++;
            len = (size_t) c;
@@ -324,15 +340,18 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
                break;
            if (len > (ns - 1))
                len = ns - 1;
-           if ((*off) + len > sz)      /* message is too short */
-               return 4;
+           if ((*off) + len > sz)
+               return 4;       /* message is too short */
+           if (no + len + 1 > ns)
+               return 5;       /* qname would overflow name buffer */
            memcpy(name + no, buf + (*off), len);
            (*off) += len;
            no += len;
            *(name + (no++)) = '.';
        }
     } while (c > 0);
-    *(name + no - 1) = '\0';
+    if (no > 0)
+       *(name + no - 1) = '\0';
     /* make sure we didn't allow someone to overflow the name buffer */
     assert(no <= ns);
     return 0;
@@ -345,10 +364,10 @@ handle_dns(const char *buf, int len)
     uint16_t us;
     off_t offset;
     char *t;
-    int x;
+    int status;
 
     /* The DNS header is 12 bytes long */
-    if (len < 12)
+    if (len < DNS_MSG_HDR_SZ)
        return 0;
 
     memcpy(&us, buf + 0, 2);
@@ -379,11 +398,15 @@ handle_dns(const char *buf, int len)
     memcpy(&us, buf + 10, 2);
     qh.arcount = ntohs(us);
 
-    offset = 12;
+    offset = DNS_MSG_HDR_SZ;
     memset(qh.qname, '\0', MAX_QNAME_SZ);
-    x = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ);
-    if (0 != x)
+    status = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ);
+    if (status != 0)
+    {
+       INFO ("utils_dns: handle_dns: rfc1035NameUnpack failed "
+               "with status %i.", status);
        return 0;
+    }
     if ('\0' == qh.qname[0])
        sstrncpy (qh.qname, ".", sizeof (qh.qname));
     while ((t = strchr(qh.qname, '\n')))
@@ -424,6 +447,7 @@ handle_udp(const struct udphdr *udp, int len)
     return 1;
 }
 
+#if HAVE_NETINET_IP6_H
 static int
 handle_ipv6 (struct ip6_hdr *ipv6, int len)
 {
@@ -492,6 +516,16 @@ handle_ipv6 (struct ip6_hdr *ipv6, int len)
 
     return (1); /* Success */
 } /* int handle_ipv6 */
+/* #endif HAVE_NETINET_IP6_H */
+
+#else /* if !HAVE_NETINET_IP6_H */
+static int
+handle_ipv6 (__attribute__((unused)) void *pkg,
+       __attribute__((unused)) int len)
+{
+    return (0);
+}
+#endif /* !HAVE_NETINET_IP6_H */
 
 static int
 handle_ip(const struct ip *ip, int len)
@@ -502,7 +536,7 @@ handle_ip(const struct ip *ip, int len)
     struct in6_addr c_dst_addr;
 
     if (ip->ip_v == 6)
-       return (handle_ipv6 ((struct ip6_hdr *) ip, len));
+       return (handle_ipv6 ((void *) ip, len));
 
     in6_addr_from_buffer (&c_src_addr, &ip->ip_src.s_addr, sizeof (ip->ip_src.s_addr), AF_INET);
     in6_addr_from_buffer (&c_dst_addr, &ip->ip_dst.s_addr, sizeof (ip->ip_dst.s_addr), AF_INET);
@@ -600,7 +634,7 @@ handle_ether(const u_char * pkt, int len)
        return 0;
     memcpy(buf, pkt, len);
     if (ETHERTYPE_IPV6 == etype)
-       return (handle_ipv6 ((struct ip6_hdr *) buf, len));
+       return (handle_ipv6 ((void *) buf, len));
     else
        return handle_ip((struct ip *) buf, len);
 }
@@ -633,7 +667,7 @@ handle_linux_sll (const u_char *pkt, int len)
        return 0;
 
     if (ETHERTYPE_IPV6 == etype)
-       return (handle_ipv6 ((struct ip6_hdr *) pkt, len));
+       return (handle_ipv6 ((void *) pkt, len));
     else
        return handle_ip((struct ip *) pkt, len);
 }
@@ -644,10 +678,6 @@ void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr, const u_char *pkt
 {
     int status;
 
-    DEBUG ("handle_pcap (udata = %p, hdr = %p, pkt = %p): hdr->caplen = %i\n",
-                   (void *) udata, (void *) hdr, (void *) pkt,
-                   hdr->caplen);
-
     if (hdr->caplen < ETHER_HDR_LEN)
        return;
 
@@ -681,7 +711,7 @@ void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr, const u_char *pkt
            break;
 
        default:
-           ERROR ("handle_pcap: unsupported data link type %d\n",
+           ERROR ("handle_pcap: unsupported data link type %d",
                    pcap_datalink(pcap_obj));
            status = 0;
            break;
index efc7903..56213af 100644 (file)
@@ -42,6 +42,8 @@
 # include <pcap.h>
 #endif
 
+#define DNS_MSG_HDR_SZ 12
+
 #define T_MAX 65536
 #define OP_MAX 16
 #define C_MAX 65536
index ac88c0f..2a5526b 100644 (file)
@@ -264,8 +264,8 @@ static int value_list_to_json (char *buffer, size_t buffer_size, /* {{{ */
     return (status);
   BUFFER_ADD (",\"dsnames\":%s", temp);
 
-  BUFFER_ADD (",\"time\":%lu", (unsigned long) vl->time);
-  BUFFER_ADD (",\"interval\":%i", vl->interval);
+  BUFFER_ADD (",\"time\":%.3f", CDTIME_T_TO_DOUBLE (vl->time));
+  BUFFER_ADD (",\"interval\":%.3f", CDTIME_T_TO_DOUBLE (vl->interval));
 
 #define BUFFER_ADD_KEYVAL(key, value) do { \
   status = escape_string (temp, sizeof (temp), (value)); \
index 47bf9f6..091b5fa 100644 (file)
@@ -103,7 +103,10 @@ static int rra_get (char ***ret, const value_list_t *vl, /* {{{ */
     return (-1);
   }
 
-  ss = (cfg->stepsize > 0) ? cfg->stepsize : vl->interval;
+  if (cfg->stepsize > 0)
+    ss = cfg->stepsize;
+  else
+    ss = (int) CDTIME_T_TO_TIME_T (vl->interval);
   if (ss <= 0)
   {
     *ret = NULL;
@@ -241,7 +244,9 @@ static int ds_get (char ***ret, /* {{{ */
     status = ssnprintf (buffer, sizeof (buffer),
         "DS:%s:%s:%i:%s:%s",
         d->name, type,
-        (cfg->heartbeat > 0) ? cfg->heartbeat : (2 * vl->interval),
+        (cfg->heartbeat > 0)
+        ? cfg->heartbeat
+        : (int) CDTIME_T_TO_TIME_T (2 * vl->interval),
         min, max);
     if ((status < 1) || ((size_t) status >= sizeof (buffer)))
       break;
@@ -323,7 +328,7 @@ static int srrd_create (const char *filename, /* {{{ */
     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);
+  ssnprintf (last_up_str, sizeof (last_up_str), "%lu", (unsigned long) last_up);
 
   new_argv[0] = "create";
   new_argv[1] = (void *) filename;
@@ -368,6 +373,8 @@ int cu_rrd_create_file (const char *filename, /* {{{ */
   char **ds_def;
   int ds_num;
   int status = 0;
+  time_t last_up;
+  unsigned long stepsize;
 
   if (check_create_dir (filename))
     return (-1);
@@ -398,9 +405,17 @@ int cu_rrd_create_file (const char *filename, /* {{{ */
   memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
   argv[ds_num + rra_num] = NULL;
 
-  status = srrd_create (filename,
-      (cfg->stepsize > 0) ? cfg->stepsize : vl->interval,
-      (vl->time > 10) ? (vl->time - 10) : vl->time,
+  last_up = CDTIME_T_TO_TIME_T (vl->time);
+  if (last_up <= 0)
+    last_up = time (NULL);
+  last_up -= 1;
+
+  if (cfg->stepsize > 0)
+    stepsize = cfg->stepsize;
+  else
+    stepsize = (unsigned long) CDTIME_T_TO_TIME_T (vl->interval);
+
+  status = srrd_create (filename, stepsize, last_up,
       argc, (const char **) argv);
 
   free (argv);
index 935e4e0..103ca57 100644 (file)
@@ -28,7 +28,7 @@
 
 struct rrdcreate_config_s
 {
-  int    stepsize;
+  unsigned long stepsize;
   int    heartbeat;
   int    rrarows;
   double xff;
diff --git a/src/utils_threshold.c b/src/utils_threshold.c
deleted file mode 100644 (file)
index b14c79b..0000000
+++ /dev/null
@@ -1,1080 +0,0 @@
-/**
- * collectd - src/utils_threshold.c
- * Copyright (C) 2007-2009  Florian octo Forster
- * Copyright (C) 2008-2009  Sebastian Harl
- * Copyright (C) 2009       Andrés J. Díaz
- *
- *
- * 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; only version 2 of the License is applicable.
- *
- * 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
- *
- * Author:
- *   Florian octo Forster <octo at verplant.org>
- *   Sebastian Harl <sh at tokkee.org>
- *   Andrés J. Díaz <ajdiaz at connectical.com>
- **/
-
-#include "collectd.h"
-#include "common.h"
-#include "plugin.h"
-#include "utils_avltree.h"
-#include "utils_cache.h"
-#include "utils_threshold.h"
-
-#include <assert.h>
-#include <pthread.h>
-
-/*
- * Private data structures
- * {{{ */
-#define UT_FLAG_INVERT  0x01
-#define UT_FLAG_PERSIST 0x02
-#define UT_FLAG_PERCENTAGE 0x04
-/* }}} */
-
-/*
- * Private (static) variables
- * {{{ */
-static c_avl_tree_t   *threshold_tree = NULL;
-static pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER;
-/* }}} */
-
-/*
- * Threshold management
- * ====================
- * The following functions add, delete, search, etc. configured thresholds to
- * the underlying AVL trees.
- * {{{ */
-static threshold_t *threshold_get (const char *hostname,
-    const char *plugin, const char *plugin_instance,
-    const char *type, const char *type_instance)
-{
-  char name[6 * DATA_MAX_NAME_LEN];
-  threshold_t *th = NULL;
-
-  format_name (name, sizeof (name),
-      (hostname == NULL) ? "" : hostname,
-      (plugin == NULL) ? "" : plugin, plugin_instance,
-      (type == NULL) ? "" : type, type_instance);
-  name[sizeof (name) - 1] = '\0';
-
-  if (c_avl_get (threshold_tree, name, (void *) &th) == 0)
-    return (th);
-  else
-    return (NULL);
-} /* threshold_t *threshold_get */
-
-static int ut_threshold_add (const threshold_t *th)
-{
-  char name[6 * DATA_MAX_NAME_LEN];
-  char *name_copy;
-  threshold_t *th_copy;
-  threshold_t *th_ptr;
-  int status = 0;
-
-  if (format_name (name, sizeof (name), th->host,
-       th->plugin, th->plugin_instance,
-       th->type, th->type_instance) != 0)
-  {
-    ERROR ("ut_threshold_add: format_name failed.");
-    return (-1);
-  }
-
-  name_copy = strdup (name);
-  if (name_copy == NULL)
-  {
-    ERROR ("ut_threshold_add: strdup failed.");
-    return (-1);
-  }
-
-  th_copy = (threshold_t *) malloc (sizeof (threshold_t));
-  if (th_copy == NULL)
-  {
-    sfree (name_copy);
-    ERROR ("ut_threshold_add: malloc failed.");
-    return (-1);
-  }
-  memcpy (th_copy, th, sizeof (threshold_t));
-  th_ptr = NULL;
-
-  DEBUG ("ut_threshold_add: Adding entry `%s'", name);
-
-  pthread_mutex_lock (&threshold_lock);
-
-  th_ptr = threshold_get (th->host, th->plugin, th->plugin_instance,
-      th->type, th->type_instance);
-
-  while ((th_ptr != NULL) && (th_ptr->next != NULL))
-    th_ptr = th_ptr->next;
-
-  if (th_ptr == NULL) /* no such threshold yet */
-  {
-    status = c_avl_insert (threshold_tree, name_copy, th_copy);
-  }
-  else /* th_ptr points to the last threshold in the list */
-  {
-    th_ptr->next = th_copy;
-    /* name_copy isn't needed */
-    sfree (name_copy);
-  }
-
-  pthread_mutex_unlock (&threshold_lock);
-
-  if (status != 0)
-  {
-    ERROR ("ut_threshold_add: c_avl_insert (%s) failed.", name);
-    sfree (name_copy);
-    sfree (th_copy);
-  }
-
-  return (status);
-} /* int ut_threshold_add */
-/*
- * End of the threshold management functions
- * }}} */
-
-/*
- * Configuration
- * =============
- * The following approximately two hundred functions are used to handle the
- * configuration and fill the threshold list.
- * {{{ */
-static int ut_config_type_datasource (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("threshold values: The `DataSource' option needs exactly one "
-       "string argument.");
-    return (-1);
-  }
-
-  sstrncpy (th->data_source, ci->values[0].value.string,
-      sizeof (th->data_source));
-
-  return (0);
-} /* int ut_config_type_datasource */
-
-static int ut_config_type_instance (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("threshold values: The `Instance' option needs exactly one "
-       "string argument.");
-    return (-1);
-  }
-
-  sstrncpy (th->type_instance, ci->values[0].value.string,
-      sizeof (th->type_instance));
-
-  return (0);
-} /* int ut_config_type_instance */
-
-static int ut_config_type_max (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("threshold values: The `%s' option needs exactly one "
-       "number argument.", ci->key);
-    return (-1);
-  }
-
-  if (strcasecmp (ci->key, "WarningMax") == 0)
-    th->warning_max = ci->values[0].value.number;
-  else
-    th->failure_max = ci->values[0].value.number;
-
-  return (0);
-} /* int ut_config_type_max */
-
-static int ut_config_type_min (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("threshold values: The `%s' option needs exactly one "
-       "number argument.", ci->key);
-    return (-1);
-  }
-
-  if (strcasecmp (ci->key, "WarningMin") == 0)
-    th->warning_min = ci->values[0].value.number;
-  else
-    th->failure_min = ci->values[0].value.number;
-
-  return (0);
-} /* int ut_config_type_min */
-
-static int ut_config_type_invert (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
-  {
-    WARNING ("threshold values: The `Invert' option needs exactly one "
-       "boolean argument.");
-    return (-1);
-  }
-
-  if (ci->values[0].value.boolean)
-    th->flags |= UT_FLAG_INVERT;
-  else
-    th->flags &= ~UT_FLAG_INVERT;
-
-  return (0);
-} /* int ut_config_type_invert */
-
-static int ut_config_type_persist (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
-  {
-    WARNING ("threshold values: The `Persist' option needs exactly one "
-       "boolean argument.");
-    return (-1);
-  }
-
-  if (ci->values[0].value.boolean)
-    th->flags |= UT_FLAG_PERSIST;
-  else
-    th->flags &= ~UT_FLAG_PERSIST;
-
-  return (0);
-} /* int ut_config_type_persist */
-
-static int ut_config_type_percentage(threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
-  {
-    WARNING ("threshold values: The `Percentage' option needs exactly one "
-       "boolean argument.");
-    return (-1);
-  }
-
-  if (ci->values[0].value.boolean)
-    th->flags |= UT_FLAG_PERCENTAGE;
-  else
-    th->flags &= ~UT_FLAG_PERCENTAGE;
-
-  return (0);
-} /* int ut_config_type_percentage */
-
-static int ut_config_type_hits (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("threshold values: The `%s' option needs exactly one "
-      "number argument.", ci->key);
-    return (-1);
-  }
-
-  th->hits = ci->values[0].value.number;
-
-  return (0);
-} /* int ut_config_type_hits */
-
-static int ut_config_type_hysteresis (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("threshold values: The `%s' option needs exactly one "
-      "number argument.", ci->key);
-    return (-1);
-  }
-
-  th->hysteresis = ci->values[0].value.number;
-
-  return (0);
-} /* int ut_config_type_hysteresis */
-
-static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
-{
-  int i;
-  threshold_t th;
-  int status = 0;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("threshold values: The `Type' block needs exactly one string "
-       "argument.");
-    return (-1);
-  }
-
-  if (ci->children_num < 1)
-  {
-    WARNING ("threshold values: The `Type' block needs at least one option.");
-    return (-1);
-  }
-
-  memcpy (&th, th_orig, sizeof (th));
-  sstrncpy (th.type, ci->values[0].value.string, sizeof (th.type));
-
-  th.warning_min = NAN;
-  th.warning_max = NAN;
-  th.failure_min = NAN;
-  th.failure_max = NAN;
-  th.hits = 0;
-  th.hysteresis = 0;
-
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *option = ci->children + i;
-    status = 0;
-
-    if (strcasecmp ("Instance", option->key) == 0)
-      status = ut_config_type_instance (&th, option);
-    else if (strcasecmp ("DataSource", option->key) == 0)
-      status = ut_config_type_datasource (&th, option);
-    else if ((strcasecmp ("WarningMax", option->key) == 0)
-       || (strcasecmp ("FailureMax", option->key) == 0))
-      status = ut_config_type_max (&th, option);
-    else if ((strcasecmp ("WarningMin", option->key) == 0)
-       || (strcasecmp ("FailureMin", option->key) == 0))
-      status = ut_config_type_min (&th, option);
-    else if (strcasecmp ("Invert", option->key) == 0)
-      status = ut_config_type_invert (&th, option);
-    else if (strcasecmp ("Persist", option->key) == 0)
-      status = ut_config_type_persist (&th, option);
-    else if (strcasecmp ("Percentage", option->key) == 0)
-      status = ut_config_type_percentage (&th, option);
-    else if (strcasecmp ("Hits", option->key) == 0)
-      status = ut_config_type_hits (&th, option);
-    else if (strcasecmp ("Hysteresis", option->key) == 0)
-      status = ut_config_type_hysteresis (&th, option);
-    else
-    {
-      WARNING ("threshold values: Option `%s' not allowed inside a `Type' "
-         "block.", option->key);
-      status = -1;
-    }
-
-    if (status != 0)
-      break;
-  }
-
-  if (status == 0)
-  {
-    status = ut_threshold_add (&th);
-  }
-
-  return (status);
-} /* int ut_config_type */
-
-static int ut_config_plugin_instance (threshold_t *th, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("threshold values: The `Instance' option needs exactly one "
-       "string argument.");
-    return (-1);
-  }
-
-  sstrncpy (th->plugin_instance, ci->values[0].value.string,
-      sizeof (th->plugin_instance));
-
-  return (0);
-} /* int ut_config_plugin_instance */
-
-static int ut_config_plugin (const threshold_t *th_orig, oconfig_item_t *ci)
-{
-  int i;
-  threshold_t th;
-  int status = 0;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("threshold values: The `Plugin' block needs exactly one string "
-       "argument.");
-    return (-1);
-  }
-
-  if (ci->children_num < 1)
-  {
-    WARNING ("threshold values: The `Plugin' block needs at least one nested "
-       "block.");
-    return (-1);
-  }
-
-  memcpy (&th, th_orig, sizeof (th));
-  sstrncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
-
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *option = ci->children + i;
-    status = 0;
-
-    if (strcasecmp ("Type", option->key) == 0)
-      status = ut_config_type (&th, option);
-    else if (strcasecmp ("Instance", option->key) == 0)
-      status = ut_config_plugin_instance (&th, option);
-    else
-    {
-      WARNING ("threshold values: Option `%s' not allowed inside a `Plugin' "
-         "block.", option->key);
-      status = -1;
-    }
-
-    if (status != 0)
-      break;
-  }
-
-  return (status);
-} /* int ut_config_plugin */
-
-static int ut_config_host (const threshold_t *th_orig, oconfig_item_t *ci)
-{
-  int i;
-  threshold_t th;
-  int status = 0;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("threshold values: The `Host' block needs exactly one string "
-       "argument.");
-    return (-1);
-  }
-
-  if (ci->children_num < 1)
-  {
-    WARNING ("threshold values: The `Host' block needs at least one nested "
-       "block.");
-    return (-1);
-  }
-
-  memcpy (&th, th_orig, sizeof (th));
-  sstrncpy (th.host, ci->values[0].value.string, sizeof (th.host));
-
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *option = ci->children + i;
-    status = 0;
-
-    if (strcasecmp ("Type", option->key) == 0)
-      status = ut_config_type (&th, option);
-    else if (strcasecmp ("Plugin", option->key) == 0)
-      status = ut_config_plugin (&th, option);
-    else
-    {
-      WARNING ("threshold values: Option `%s' not allowed inside a `Host' "
-         "block.", option->key);
-      status = -1;
-    }
-
-    if (status != 0)
-      break;
-  }
-
-  return (status);
-} /* int ut_config_host */
-
-int ut_config (const oconfig_item_t *ci)
-{
-  int i;
-  int status = 0;
-
-  threshold_t th;
-
-  if (ci->values_num != 0)
-  {
-    ERROR ("threshold values: The `Threshold' block may not have any "
-       "arguments.");
-    return (-1);
-  }
-
-  if (threshold_tree == NULL)
-  {
-    threshold_tree = c_avl_create ((void *) strcmp);
-    if (threshold_tree == NULL)
-    {
-      ERROR ("ut_config: c_avl_create failed.");
-      return (-1);
-    }
-  }
-
-  memset (&th, '\0', sizeof (th));
-  th.warning_min = NAN;
-  th.warning_max = NAN;
-  th.failure_min = NAN;
-  th.failure_max = NAN;
-
-  th.hits = 0;
-  th.hysteresis = 0;
-    
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *option = ci->children + i;
-    status = 0;
-
-    if (strcasecmp ("Type", option->key) == 0)
-      status = ut_config_type (&th, option);
-    else if (strcasecmp ("Plugin", option->key) == 0)
-      status = ut_config_plugin (&th, option);
-    else if (strcasecmp ("Host", option->key) == 0)
-      status = ut_config_host (&th, option);
-    else
-    {
-      WARNING ("threshold values: Option `%s' not allowed here.", option->key);
-      status = -1;
-    }
-
-    if (status != 0)
-      break;
-  }
-
-  return (status);
-} /* int um_config */
-/*
- * End of the functions used to configure threshold values.
- */
-/* }}} */
-
-static threshold_t *threshold_search (const value_list_t *vl)
-{
-  threshold_t *th;
-
-  if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
-         vl->type, vl->type_instance)) != NULL)
-    return (th);
-  else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
-         vl->type, NULL)) != NULL)
-    return (th);
-  else if ((th = threshold_get (vl->host, vl->plugin, NULL,
-         vl->type, vl->type_instance)) != NULL)
-    return (th);
-  else if ((th = threshold_get (vl->host, vl->plugin, NULL,
-         vl->type, NULL)) != NULL)
-    return (th);
-  else if ((th = threshold_get (vl->host, "", NULL,
-         vl->type, vl->type_instance)) != NULL)
-    return (th);
-  else if ((th = threshold_get (vl->host, "", NULL,
-         vl->type, NULL)) != NULL)
-    return (th);
-  else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
-         vl->type, vl->type_instance)) != NULL)
-    return (th);
-  else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
-         vl->type, NULL)) != NULL)
-    return (th);
-  else if ((th = threshold_get ("", vl->plugin, NULL,
-         vl->type, vl->type_instance)) != NULL)
-    return (th);
-  else if ((th = threshold_get ("", vl->plugin, NULL,
-         vl->type, NULL)) != NULL)
-    return (th);
-  else if ((th = threshold_get ("", "", NULL,
-         vl->type, vl->type_instance)) != NULL)
-    return (th);
-  else if ((th = threshold_get ("", "", NULL,
-         vl->type, NULL)) != NULL)
-    return (th);
-
-  return (NULL);
-} /* threshold_t *threshold_search */
-
-/*
- * int ut_report_state
- *
- * Checks if the `state' differs from the old state and creates a notification
- * if appropriate.
- * Does not fail.
- */
-static int ut_report_state (const data_set_t *ds,
-    const value_list_t *vl,
-    const threshold_t *th,
-    const gauge_t *values,
-    int ds_index,
-    int state)
-{ /* {{{ */
-  int state_old;
-  notification_t n;
-
-  char *buf;
-  size_t bufsize;
-
-  int status;
-
-  /* Check if hits matched */
-  if ( (th->hits != 0) )
-  {
-    int hits = uc_get_hits(ds,vl);
-    /* The STATE_OKAY always reset hits, or if hits reaise the limit */
-    if ( (state == STATE_OKAY) || (hits > th->hits) )
-    {
-        DEBUG("ut_report_state: reset uc_get_hits = 0");
-        uc_set_hits(ds,vl,0); /* reset hit counter and notify */
-    } else {
-      DEBUG("ut_report_state: th->hits = %d, uc_get_hits = %d",th->hits,uc_get_hits(ds,vl));
-      (void) uc_inc_hits(ds,vl,1); /* increase hit counter */
-      return (0);
-    }
-  } /* end check hits */
-
-  state_old = uc_get_state (ds, vl);
-
-  /* If the state didn't change, only report if `persistent' is specified and
-   * the state is not `okay'. */
-  if (state == state_old)
-  {
-    if ((th->flags & UT_FLAG_PERSIST) == 0)
-      return (0);
-    else if (state == STATE_OKAY)
-      return (0);
-  }
-
-  if (state != state_old)
-    uc_set_state (ds, vl, state);
-
-  NOTIFICATION_INIT_VL (&n, vl, ds);
-
-  buf = n.message;
-  bufsize = sizeof (n.message);
-
-  if (state == STATE_OKAY)
-    n.severity = NOTIF_OKAY;
-  else if (state == STATE_WARNING)
-    n.severity = NOTIF_WARNING;
-  else
-    n.severity = NOTIF_FAILURE;
-
-  n.time = vl->time;
-
-  status = ssnprintf (buf, bufsize, "Host %s, plugin %s",
-      vl->host, vl->plugin);
-  buf += status;
-  bufsize -= status;
-
-  if (vl->plugin_instance[0] != '\0')
-  {
-    status = ssnprintf (buf, bufsize, " (instance %s)",
-       vl->plugin_instance);
-    buf += status;
-    bufsize -= status;
-  }
-
-  status = ssnprintf (buf, bufsize, " type %s", vl->type);
-  buf += status;
-  bufsize -= status;
-
-  if (vl->type_instance[0] != '\0')
-  {
-    status = ssnprintf (buf, bufsize, " (instance %s)",
-       vl->type_instance);
-    buf += status;
-    bufsize -= status;
-  }
-
-  plugin_notification_meta_add_string (&n, "DataSource",
-      ds->ds[ds_index].name);
-  plugin_notification_meta_add_double (&n, "CurrentValue", values[ds_index]);
-  plugin_notification_meta_add_double (&n, "WarningMin", th->warning_min);
-  plugin_notification_meta_add_double (&n, "WarningMax", th->warning_max);
-  plugin_notification_meta_add_double (&n, "FailureMin", th->failure_min);
-  plugin_notification_meta_add_double (&n, "FailureMax", th->failure_max);
-
-  /* Send an okay notification */
-  if (state == STATE_OKAY)
-  {
-    status = ssnprintf (buf, bufsize, ": All data sources are within range again.");
-    buf += status;
-    bufsize -= status;
-  }
-  else
-  {
-    double min;
-    double max;
-
-    min = (state == STATE_ERROR) ? th->failure_min : th->warning_min;
-    max = (state == STATE_ERROR) ? th->failure_max : th->warning_max;
-
-    if (th->flags & UT_FLAG_INVERT)
-    {
-      if (!isnan (min) && !isnan (max))
-      {
-        status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
-            "%f. That is within the %s region of %f%s and %f%s.",
-            ds->ds[ds_index].name, values[ds_index],
-            (state == STATE_ERROR) ? "failure" : "warning",
-            min, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "",
-            max, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
-      }
-      else
-      {
-       status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
-           "%f. That is %s the %s threshold of %f%s.",
-           ds->ds[ds_index].name, values[ds_index],
-           isnan (min) ? "below" : "above",
-           (state == STATE_ERROR) ? "failure" : "warning",
-           isnan (min) ? max : min,
-           ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
-      }
-    }
-    else if (th->flags & UT_FLAG_PERCENTAGE)
-    {
-      gauge_t value;
-      gauge_t sum;
-      int i;
-
-      sum = 0.0;
-      for (i = 0; i < vl->values_len; i++)
-      {
-        if (isnan (values[i]))
-          continue;
-
-        sum += values[i];
-      }
-
-      if (sum == 0.0)
-        value = NAN;
-      else
-        value = 100.0 * values[ds_index] / sum;
-
-      status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
-          "%g (%.2f%%). That is %s the %s threshold of %.2f%%.",
-          ds->ds[ds_index].name, values[ds_index], value,
-          (value < min) ? "below" : "above",
-          (state == STATE_ERROR) ? "failure" : "warning",
-          (value < min) ? min : max);
-    }
-    else /* is not inverted */
-    {
-      status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
-         "%f. That is %s the %s threshold of %f.",
-         ds->ds[ds_index].name, values[ds_index],
-         (values[ds_index] < min) ? "below" : "above",
-         (state == STATE_ERROR) ? "failure" : "warning",
-         (values[ds_index] < min) ? min : max);
-    }
-    buf += status;
-    bufsize -= status;
-  }
-
-  plugin_dispatch_notification (&n);
-
-  plugin_notification_meta_free (n.meta);
-  return (0);
-} /* }}} int ut_report_state */
-
-/*
- * int ut_check_one_data_source
- *
- * Checks one data source against the given threshold configuration. If the
- * `DataSource' option is set in the threshold, and the name does NOT match,
- * `okay' is returned. If the threshold does match, its failure and warning
- * min and max values are checked and `failure' or `warning' is returned if
- * appropriate.
- * Does not fail.
- */
-static int ut_check_one_data_source (const data_set_t *ds,
-    const value_list_t __attribute__((unused)) *vl,
-    const threshold_t *th,
-    const gauge_t *values,
-    int ds_index)
-{ /* {{{ */
-  const char *ds_name;
-  int is_warning = 0;
-  int is_failure = 0;
-  int prev_state = STATE_OKAY;
-
-  /* check if this threshold applies to this data source */
-  if (ds != NULL)
-  {
-    ds_name = ds->ds[ds_index].name;
-    if ((th->data_source[0] != 0)
-       && (strcmp (ds_name, th->data_source) != 0))
-      return (STATE_OKAY);
-  }
-
-  if ((th->flags & UT_FLAG_INVERT) != 0)
-  {
-    is_warning--;
-    is_failure--;
-  }
-
-  /* XXX: This is an experimental code, not optimized, not fast, not reliable,
-   * and probably, do not work as you expect. Enjoy! :D */
-  if ( (th->hysteresis > 0) && ((prev_state = uc_get_state(ds,vl)) != STATE_OKAY) )
-  {
-    switch(prev_state)
-    {
-      case STATE_ERROR:
-       if ( (!isnan (th->failure_min) && ((th->failure_min + th->hysteresis) < values[ds_index])) ||
-            (!isnan (th->failure_max) && ((th->failure_max - th->hysteresis) > values[ds_index])) )
-         return (STATE_OKAY);
-       else
-         is_failure++;
-      case STATE_WARNING:
-       if ( (!isnan (th->warning_min) && ((th->warning_min + th->hysteresis) < values[ds_index])) ||
-            (!isnan (th->warning_max) && ((th->warning_max - th->hysteresis) > values[ds_index])) )
-         return (STATE_OKAY);
-       else
-         is_warning++;
-     }
-  }
-  else { /* no hysteresis */
-    if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
-       || (!isnan (th->failure_max) && (th->failure_max < values[ds_index])))
-      is_failure++;
-
-    if ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
-       || (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
-      is_warning++;
- }
-
-  if (is_failure != 0)
-    return (STATE_ERROR);
-
-  if (is_warning != 0)
-    return (STATE_WARNING);
-
-  return (STATE_OKAY);
-} /* }}} int ut_check_one_data_source */
-
-/*
- * int ut_check_one_threshold
- *
- * Checks all data sources of a value list against the given threshold, using
- * the ut_check_one_data_source function above. Returns the worst status,
- * which is `okay' if nothing has failed.
- * Returns less than zero if the data set doesn't have any data sources.
- */
-static int ut_check_one_threshold (const data_set_t *ds,
-    const value_list_t *vl,
-    const threshold_t *th,
-    const gauge_t *values,
-    int *ret_ds_index)
-{ /* {{{ */
-  int ret = -1;
-  int ds_index = -1;
-  int i;
-  gauge_t values_copy[ds->ds_num];
-
-  memcpy (values_copy, values, sizeof (values_copy));
-
-  if ((th->flags & UT_FLAG_PERCENTAGE) != 0)
-  {
-    int num = 0;
-    gauge_t sum=0.0;
-
-    if (ds->ds_num == 1)
-    {
-      WARNING ("ut_check_one_threshold: The %s type has only one data "
-          "source, but you have configured to check this as a percentage. "
-          "That doesn't make much sense, because the percentage will always "
-          "be 100%%!", ds->type);
-    }
-
-    /* Prepare `sum' and `num'. */
-    for (i = 0; i < ds->ds_num; i++)
-      if (!isnan (values[i]))
-      {
-        num++;
-       sum += values[i];
-      }
-
-    if ((num == 0) /* All data sources are undefined. */
-        || (sum == 0.0)) /* Sum is zero, cannot calculate percentage. */
-    {
-      for (i = 0; i < ds->ds_num; i++)
-        values_copy[i] = NAN;
-    }
-    else /* We can actually calculate the percentage. */
-    {
-      for (i = 0; i < ds->ds_num; i++)
-        values_copy[i] = 100.0 * values[i] / sum;
-    }
-  } /* if (UT_FLAG_PERCENTAGE) */
-
-  for (i = 0; i < ds->ds_num; i++)
-  {
-    int status;
-
-    status = ut_check_one_data_source (ds, vl, th, values_copy, i);
-    if (ret < status)
-    {
-      ret = status;
-      ds_index = i;
-    }
-  } /* for (ds->ds_num) */
-
-  if (ret_ds_index != NULL)
-    *ret_ds_index = ds_index;
-
-  return (ret);
-} /* }}} int ut_check_one_threshold */
-
-/*
- * int ut_check_threshold (PUBLIC)
- *
- * Gets a list of matching thresholds and searches for the worst status by one
- * of the thresholds. Then reports that status using the ut_report_state
- * function above. 
- * Returns zero on success and if no threshold has been configured. Returns
- * less than zero on failure.
- */
-int ut_check_threshold (const data_set_t *ds, const value_list_t *vl)
-{ /* {{{ */
-  threshold_t *th;
-  gauge_t *values;
-  int status;
-
-  int worst_state = -1;
-  threshold_t *worst_th = NULL;
-  int worst_ds_index = -1;
-
-  if (threshold_tree == NULL)
-    return (0);
-
-  /* Is this lock really necessary? So far, thresholds are only inserted at
-   * startup. -octo */
-  pthread_mutex_lock (&threshold_lock);
-  th = threshold_search (vl);
-  pthread_mutex_unlock (&threshold_lock);
-  if (th == NULL)
-    return (0);
-
-  DEBUG ("ut_check_threshold: Found matching threshold(s)");
-
-  values = uc_get_rate (ds, vl);
-  if (values == NULL)
-    return (0);
-
-  while (th != NULL)
-  {
-    int ds_index = -1;
-
-    status = ut_check_one_threshold (ds, vl, th, values, &ds_index);
-    if (status < 0)
-    {
-      ERROR ("ut_check_threshold: ut_check_one_threshold failed.");
-      sfree (values);
-      return (-1);
-    }
-
-    if (worst_state < status)
-    {
-      worst_state = status;
-      worst_th = th;
-      worst_ds_index = ds_index;
-    }
-
-    th = th->next;
-  } /* while (th) */
-
-  status = ut_report_state (ds, vl, worst_th, values,
-      worst_ds_index, worst_state);
-  if (status != 0)
-  {
-    ERROR ("ut_check_threshold: ut_report_state failed.");
-    sfree (values);
-    return (-1);
-  }
-
-  sfree (values);
-
-  return (0);
-} /* }}} int ut_check_threshold */
-
-/*
- * int ut_check_interesting (PUBLIC)
- *
- * Given an identification returns
- * 0: No threshold is defined.
- * 1: A threshold has been found. The flag `persist' is off.
- * 2: A threshold has been found. The flag `persist' is on.
- *    (That is, it is expected that many notifications are sent until the
- *    problem disappears.)
- */
-int ut_check_interesting (const char *name)
-{ /* {{{ */
-  char *name_copy = NULL;
-  char *host = NULL;
-  char *plugin = NULL;
-  char *plugin_instance = NULL;
-  char *type = NULL;
-  char *type_instance = NULL;
-  int status;
-  data_set_t ds;
-  value_list_t vl;
-  threshold_t *th;
-
-  /* If there is no tree nothing is interesting. */
-  if (threshold_tree == NULL)
-    return (0);
-
-  name_copy = strdup (name);
-  if (name_copy == NULL)
-  {
-    ERROR ("ut_check_interesting: strdup failed.");
-    return (-1);
-  }
-
-  status = parse_identifier (name_copy, &host,
-      &plugin, &plugin_instance, &type, &type_instance);
-  if (status != 0)
-  {
-    ERROR ("ut_check_interesting: parse_identifier failed.");
-    sfree (name_copy);
-    return (-1);
-  }
-
-  memset (&ds, '\0', sizeof (ds));
-  memset (&vl, '\0', sizeof (vl));
-
-  sstrncpy (vl.host, host, sizeof (vl.host));
-  sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
-  if (plugin_instance != NULL)
-    sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
-  sstrncpy (ds.type, type, sizeof (ds.type));
-  sstrncpy (vl.type, type, sizeof (vl.type));
-  if (type_instance != NULL)
-    sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
-
-  sfree (name_copy);
-  host = plugin = plugin_instance = type = type_instance = NULL;
-
-  th = threshold_search (&vl);
-  if (th == NULL)
-    return (0);
-  if ((th->flags & UT_FLAG_PERSIST) == 0)
-    return (1);
-  return (2);
-} /* }}} int ut_check_interesting */
-
-int ut_search_threshold (const value_list_t *vl, /* {{{ */
-    threshold_t *ret_threshold)
-{
-  threshold_t *t;
-
-  if (vl == NULL)
-    return (EINVAL);
-
-  t = threshold_search (vl);
-  if (t == NULL)
-    return (ENOENT);
-
-  memcpy (ret_threshold, t, sizeof (*ret_threshold));
-  ret_threshold->next = NULL;
-
-  return (0);
-} /* }}} int ut_search_threshold */
-
-/* vim: set sw=2 ts=8 sts=2 tw=78 et fdm=marker : */
diff --git a/src/utils_threshold.h b/src/utils_threshold.h
deleted file mode 100644 (file)
index 8aaf34c..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * collectd - src/utils_threshold.h
- * Copyright (C) 2007-2009  Florian octo Forster
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; only version 2 of the License is applicable.
- *
- * 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
- *
- * Author:
- *   Florian octo Forster <octo at verplant.org>
- **/
-
-#ifndef UTILS_THRESHOLD_H
-#define UTILS_THRESHOLD_H 1
-
-#include "collectd.h"
-#include "liboconfig/oconfig.h"
-#include "plugin.h"
-
-typedef struct threshold_s
-{
-  char host[DATA_MAX_NAME_LEN];
-  char plugin[DATA_MAX_NAME_LEN];
-  char plugin_instance[DATA_MAX_NAME_LEN];
-  char type[DATA_MAX_NAME_LEN];
-  char type_instance[DATA_MAX_NAME_LEN];
-  char data_source[DATA_MAX_NAME_LEN];
-  gauge_t warning_min;
-  gauge_t warning_max;
-  gauge_t failure_min;
-  gauge_t failure_max;
-  gauge_t hysteresis;
-  int flags;
-  int hits;
-  struct threshold_s *next;
-} threshold_t;
-
-/*
- * ut_config
- *
- * Parses the configuration and sets up the module. This is called from
- * `src/configfile.c'.
- */
-int ut_config (const oconfig_item_t *ci);
-
-/*
- * ut_check_threshold
- *
- * Checks if a threshold is defined for this value and if such a threshold is
- * configured, check if the value within the acceptable range. If it is not, a
- * notification is dispatched to inform the user that a problem exists. This is
- * called from `plugin_read_all'.
- */
-int ut_check_threshold (const data_set_t *ds, const value_list_t *vl);
-
-/*
- * Given an identification returns
- * 0: No threshold is defined.
- * 1: A threshold has been found. The flag `persist' is off.
- * 2: A threshold has been found. The flag `persist' is on.
- *    (That is, it is expected that many notifications are sent until the
- *    problem disappears.)
- */
-int ut_check_interesting (const char *name);
-
-/* 
- * Given an identifier in form of a `value_list_t', searches for the best
- * matching threshold configuration. `ret_threshold' may be NULL.
- *
- * Returns:
- *        0: Success. Threshold configuration has been copied to
- *           `ret_threshold' (if it is non-NULL).
- *   ENOENT: No configuration for this identifier found.
- *     else: Error.
- */
-int ut_search_threshold (const value_list_t *vl, threshold_t *ret_threshold);
-
-#endif /* UTILS_THRESHOLD_H */
diff --git a/src/utils_time.c b/src/utils_time.c
new file mode 100644 (file)
index 0000000..aac6135
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * collectd - src/utils_time.h
+ * Copyright (C) 2010  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; only version 2 of the License is applicable.
+ *
+ * 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 <ff at octo.it>
+ **/
+
+#include "collectd.h"
+#include "utils_time.h"
+#include "plugin.h"
+#include "common.h"
+
+#if HAVE_CLOCK_GETTIME
+cdtime_t cdtime (void) /* {{{ */
+{
+  int status;
+  struct timespec ts = { 0, 0 };
+
+  status = clock_gettime (CLOCK_REALTIME, &ts);
+  if (status != 0)
+  {
+    char errbuf[1024];
+    ERROR ("cdtime: clock_gettime failed: %s",
+        sstrerror (errno, errbuf, sizeof (errbuf)));
+    return (0);
+  }
+
+  return (TIMESPEC_TO_CDTIME_T (&ts));
+} /* }}} cdtime_t cdtime */
+#else
+/* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */
+cdtime_t cdtime (void) /* {{{ */
+{
+  int status;
+  struct timeval tv = { 0, 0 };
+
+  status = gettimeofday (&tv, /* struct timezone = */ NULL);
+  if (status != 0)
+  {
+    char errbuf[1024];
+    ERROR ("cdtime: gettimeofday failed: %s",
+        sstrerror (errno, errbuf, sizeof (errbuf)));
+    return (0);
+  }
+
+  return (TIMEVAL_TO_CDTIME_T (&tv));
+} /* }}} cdtime_t cdtime */
+#endif
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_time.h b/src/utils_time.h
new file mode 100644 (file)
index 0000000..0fd809a
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * collectd - src/utils_time.h
+ * Copyright (C) 2010  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; only version 2 of the License is applicable.
+ *
+ * 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 <ff at octo.it>
+ **/
+
+#ifndef UTILS_TIME_H
+#define UTILS_TIME_H 1
+
+#include "collectd.h"
+
+/*
+ * "cdtime_t" is a 64bit unsigned integer. The time is stored at a 2^-30 second
+ * resolution, i.e. the most significant 34 bit are used to store the time in
+ * seconds, the least significant bits store the sub-second part in something
+ * very close to nanoseconds. *The* big advantage of storing time in this
+ * manner is that comparing times and calculating differences is as simple as
+ * it is with "time_t", i.e. a simple integer comparison / subtraction works.
+ */
+/* 
+ * cdtime_t is defined in "collectd.h" */
+/* typedef uint64_t cdtime_t; */
+
+/* 2^30 = 1073741824 */
+#define TIME_T_TO_CDTIME_T(t) (((cdtime_t) (t)) * 1073741824)
+#define CDTIME_T_TO_TIME_T(t) ((time_t) ((t) / 1073741824))
+
+#define CDTIME_T_TO_DOUBLE(t) (((double) (t)) / 1073741824.0)
+#define DOUBLE_TO_CDTIME_T(d) ((cdtime_t) ((d) * 1073741824.0))
+
+#define MS_TO_CDTIME_T(ms) ((cdtime_t)    (((double) (ms)) * 1073741.824))
+#define CDTIME_T_TO_MS(t)  ((long)        (((double) (t))  / 1073741.824))
+#define US_TO_CDTIME_T(us) ((cdtime_t)    (((double) (us)) * 1073.741824))
+#define CDTIME_T_TO_US(t)  ((suseconds_t) (((double) (t))  / 1073.741824))
+#define NS_TO_CDTIME_T(ns) ((cdtime_t)    (((double) (ns)) * 1.073741824))
+#define CDTIME_T_TO_NS(t)  ((long)        (((double) (t))  / 1.073741824))
+
+#define CDTIME_T_TO_TIMEVAL(cdt,tvp) do {                                    \
+        (tvp)->tv_sec = CDTIME_T_TO_TIME_T (cdt);                            \
+        (tvp)->tv_usec = CDTIME_T_TO_US ((cdt) % 1073741824);                \
+} while (0)
+#define TIMEVAL_TO_CDTIME_T(tv) (TIME_T_TO_CDTIME_T ((tv)->tv_sec)           \
+    + US_TO_CDTIME_T ((tv)->tv_usec))
+
+#define CDTIME_T_TO_TIMESPEC(cdt,tsp) do {                                   \
+  (tsp)->tv_sec = CDTIME_T_TO_TIME_T (cdt);                                  \
+  (tsp)->tv_nsec = CDTIME_T_TO_NS ((cdt) % 1073741824);                      \
+} while (0)
+#define TIMESPEC_TO_CDTIME_T(ts) (TIME_T_TO_CDTIME_T ((ts)->tv_sec)           \
+    + NS_TO_CDTIME_T ((ts)->tv_nsec))
+
+cdtime_t cdtime (void);
+
+#endif /* UTILS_TIME_H */
+/* vim: set sw=2 sts=2 et : */
diff --git a/src/varnish.c b/src/varnish.c
new file mode 100644 (file)
index 0000000..37fd4bb
--- /dev/null
@@ -0,0 +1,603 @@
+/**
+ * collectd - src/varnish.c
+ * Copyright (C) 2010 Jérôme Renard
+ * Copyright (C) 2010 Marc Fournier
+ * Copyright (C) 2010 Florian 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; only version 2 of the License is applicable.
+ *
+ * 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:
+ *   Jérôme Renard <jerome.renard at gmail.com>
+ *   Marc Fournier <marc.fournier at camptocamp.com>
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+/**
+ * Current list of what is monitored and what is not monitored (yet)
+ * {{{
+ * Field name           Description                           Monitored
+ * ----------           -----------                           ---------
+ * uptime               Child uptime                              N
+ * client_conn          Client connections accepted               Y
+ * client_drop          Connection dropped, no sess               Y
+ * client_req           Client requests received                  Y
+ * cache_hit            Cache hits                                Y
+ * cache_hitpass        Cache hits for pass                       Y
+ * cache_miss           Cache misses                              Y
+ * backend_conn         Backend conn. success                     Y
+ * backend_unhealthy    Backend conn. not attempted               Y
+ * backend_busy         Backend conn. too many                    Y
+ * backend_fail         Backend conn. failures                    Y
+ * backend_reuse        Backend conn. reuses                      Y
+ * backend_toolate      Backend conn. was closed                  Y
+ * backend_recycle      Backend conn. recycles                    Y
+ * backend_unused       Backend conn. unused                      Y
+ * fetch_head           Fetch head                                Y
+ * fetch_length         Fetch with Length                         Y
+ * fetch_chunked        Fetch chunked                             Y
+ * fetch_eof            Fetch EOF                                 Y
+ * fetch_bad            Fetch had bad headers                     Y
+ * fetch_close          Fetch wanted close                        Y
+ * fetch_oldhttp        Fetch pre HTTP/1.1 closed                 Y
+ * fetch_zero           Fetch zero len                            Y
+ * fetch_failed         Fetch failed                              Y
+ * n_sess_mem           N struct sess_mem                         N
+ * n_sess               N struct sess                             N
+ * n_object             N struct object                           N
+ * n_vampireobject      N unresurrected objects                   N
+ * n_objectcore         N struct objectcore                       N
+ * n_objecthead         N struct objecthead                       N
+ * n_smf                N struct smf                              N
+ * n_smf_frag           N small free smf                          N
+ * n_smf_large          N large free smf                          N
+ * n_vbe_conn           N struct vbe_conn                         N
+ * n_wrk                N worker threads                          Y
+ * n_wrk_create         N worker threads created                  Y
+ * n_wrk_failed         N worker threads not created              Y
+ * n_wrk_max            N worker threads limited                  Y
+ * n_wrk_queue          N queued work requests                    Y
+ * n_wrk_overflow       N overflowed work requests                Y
+ * n_wrk_drop           N dropped work requests                   Y
+ * n_backend            N backends                                N
+ * n_expired            N expired objects                         N
+ * n_lru_nuked          N LRU nuked objects                       N
+ * n_lru_saved          N LRU saved objects                       N
+ * n_lru_moved          N LRU moved objects                       N
+ * n_deathrow           N objects on deathrow                     N
+ * losthdr              HTTP header overflows                     N
+ * n_objsendfile        Objects sent with sendfile                N
+ * n_objwrite           Objects sent with write                   N
+ * n_objoverflow        Objects overflowing workspace             N
+ * s_sess               Total Sessions                            Y
+ * s_req                Total Requests                            Y
+ * s_pipe               Total pipe                                Y
+ * s_pass               Total pass                                Y
+ * s_fetch              Total fetch                               Y
+ * s_hdrbytes           Total header bytes                        Y
+ * s_bodybytes          Total body bytes                          Y
+ * sess_closed          Session Closed                            N
+ * sess_pipeline        Session Pipeline                          N
+ * sess_readahead       Session Read Ahead                        N
+ * sess_linger          Session Linger                            N
+ * sess_herd            Session herd                              N
+ * shm_records          SHM records                               Y
+ * shm_writes           SHM writes                                Y
+ * shm_flushes          SHM flushes due to overflow               Y
+ * shm_cont             SHM MTX contention                        Y
+ * shm_cycles           SHM cycles through buffer                 Y
+ * sm_nreq              allocator requests                        Y
+ * sm_nobj              outstanding allocations                   Y
+ * sm_balloc            bytes allocated                           Y
+ * sm_bfree             bytes free                                Y
+ * sma_nreq             SMA allocator requests                    Y
+ * sma_nobj             SMA outstanding allocations               Y
+ * sma_nbytes           SMA outstanding bytes                     Y
+ * sma_balloc           SMA bytes allocated                       Y
+ * sma_bfree            SMA bytes free                            Y
+ * sms_nreq             SMS allocator requests                    Y
+ * sms_nobj             SMS outstanding allocations               Y
+ * sms_nbytes           SMS outstanding bytes                     Y
+ * sms_balloc           SMS bytes allocated                       Y
+ * sms_bfree            SMS bytes freed                           Y
+ * backend_req          Backend requests made                     N
+ * n_vcl                N vcl total                               N
+ * n_vcl_avail          N vcl available                           N
+ * n_vcl_discard        N vcl discarded                           N
+ * n_purge              N total active purges                     N
+ * n_purge_add          N new purges added                        N
+ * n_purge_retire       N old purges deleted                      N
+ * n_purge_obj_test     N objects tested                          N
+ * n_purge_re_test      N regexps tested against                  N
+ * n_purge_dups         N duplicate purges removed                N
+ * hcb_nolock           HCB Lookups without lock                  Y
+ * hcb_lock             HCB Lookups with lock                     Y
+ * hcb_insert           HCB Inserts                               Y
+ * esi_parse            Objects ESI parsed (unlock)               Y
+ * esi_errors           ESI parse errors (unlock)                 Y
+ * }}}
+ */
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <varnish/varnishapi.h>
+
+/* {{{ user_config_s */
+struct user_config_s {
+       char *instance;
+
+       _Bool collect_cache;
+       _Bool collect_connections;
+       _Bool collect_esi;
+       _Bool collect_backend;
+       _Bool collect_fetch;
+       _Bool collect_hcb;
+       _Bool collect_shm;
+       _Bool collect_sma;
+       _Bool collect_sms;
+       _Bool collect_sm;
+       _Bool collect_totals;
+       _Bool collect_workers;
+};
+typedef struct user_config_s user_config_t; /* }}} */
+
+static _Bool have_instance = 0;
+
+static int varnish_submit (const char *plugin_instance, /* {{{ */
+               const char *category, const char *type, const char *type_instance, value_t value)
+{
+       value_list_t vl = VALUE_LIST_INIT;
+
+       vl.values = &value;
+       vl.values_len = 1;
+
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+
+       sstrncpy (vl.plugin, "varnish", sizeof (vl.plugin));
+
+       if (plugin_instance == NULL)
+               plugin_instance = "default";
+
+       ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+               "%s-%s", plugin_instance, category);
+
+       sstrncpy (vl.type, type, sizeof (vl.type));
+
+       if (type_instance != NULL)
+               sstrncpy (vl.type_instance, type_instance,
+                               sizeof (vl.type_instance));
+
+       return (plugin_dispatch_values (&vl));
+} /* }}} int varnish_submit */
+
+static int varnish_submit_gauge (const char *plugin_instance, /* {{{ */
+               const char *category, const char *type, const char *type_instance,
+               uint64_t gauge_value)
+{
+       value_t value;
+
+       value.gauge = (gauge_t) gauge_value;
+
+       return (varnish_submit (plugin_instance, category, type, type_instance, value));
+} /* }}} int varnish_submit_gauge */
+
+static int varnish_submit_derive (const char *plugin_instance, /* {{{ */
+               const char *category, const char *type, const char *type_instance,
+               uint64_t derive_value)
+{
+       value_t value;
+
+       value.derive = (derive_t) derive_value;
+
+       return (varnish_submit (plugin_instance, category, type, type_instance, value));
+} /* }}} int varnish_submit_derive */
+
+static void varnish_monitor (const user_config_t *conf, struct varnish_stats *VSL_stats) /* {{{ */
+{
+       if (conf->collect_cache)
+       {
+               /* Cache hits */
+               varnish_submit_derive (conf->instance, "cache", "cache_result", "hit",     VSL_stats->cache_hit);
+               /* Cache misses */
+               varnish_submit_derive (conf->instance, "cache", "cache_result", "miss",    VSL_stats->cache_miss);
+               /* Cache hits for pass */
+               varnish_submit_derive (conf->instance, "cache", "cache_result", "hitpass", VSL_stats->cache_hitpass);
+       }
+
+       if (conf->collect_connections)
+       {
+               /* Client connections accepted */
+               varnish_submit_derive (conf->instance, "connections", "connections", "accepted", VSL_stats->client_conn);
+               /* Connection dropped, no sess */
+               varnish_submit_derive (conf->instance, "connections", "connections", "dropped" , VSL_stats->client_drop);
+               /* Client requests received    */
+               varnish_submit_derive (conf->instance, "connections", "connections", "received", VSL_stats->client_req);
+       }
+
+       if (conf->collect_esi)
+       {
+               /* Objects ESI parsed (unlock) */
+               varnish_submit_derive (conf->instance, "esi", "total_operations", "parsed", VSL_stats->esi_parse);
+               /* ESI parse errors (unlock)   */
+               varnish_submit_derive (conf->instance, "esi", "total_operations", "error",  VSL_stats->esi_errors);
+       }
+
+       if (conf->collect_backend)
+       {
+               /* Backend conn. success       */
+               varnish_submit_derive (conf->instance, "backend", "connections", "success"      , VSL_stats->backend_conn);
+               /* Backend conn. not attempted */
+               varnish_submit_derive (conf->instance, "backend", "connections", "not-attempted", VSL_stats->backend_unhealthy);
+               /* Backend conn. too many      */
+               varnish_submit_derive (conf->instance, "backend", "connections", "too-many"     , VSL_stats->backend_busy);
+               /* Backend conn. failures      */
+               varnish_submit_derive (conf->instance, "backend", "connections", "failures"     , VSL_stats->backend_fail);
+               /* Backend conn. reuses        */
+               varnish_submit_derive (conf->instance, "backend", "connections", "reuses"       , VSL_stats->backend_reuse);
+               /* Backend conn. was closed    */
+               varnish_submit_derive (conf->instance, "backend", "connections", "was-closed"   , VSL_stats->backend_toolate);
+               /* Backend conn. recycles      */
+               varnish_submit_derive (conf->instance, "backend", "connections", "recycled"     , VSL_stats->backend_recycle);
+               /* Backend conn. unused        */
+               varnish_submit_derive (conf->instance, "backend", "connections", "unused"       , VSL_stats->backend_unused);
+       }
+
+       if (conf->collect_fetch)
+       {
+               /* Fetch head                */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "head"       , VSL_stats->fetch_head);
+               /* Fetch with length         */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "length"     , VSL_stats->fetch_length);
+               /* Fetch chunked             */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "chunked"    , VSL_stats->fetch_chunked);
+               /* Fetch EOF                 */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "eof"        , VSL_stats->fetch_eof);
+               /* Fetch bad headers         */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "bad_headers", VSL_stats->fetch_bad);
+               /* Fetch wanted close        */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "close"      , VSL_stats->fetch_close);
+               /* Fetch pre HTTP/1.1 closed */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "oldhttp"    , VSL_stats->fetch_oldhttp);
+               /* Fetch zero len            */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "zero"       , VSL_stats->fetch_zero);
+               /* Fetch failed              */
+               varnish_submit_derive (conf->instance, "fetch", "http_requests", "failed"     , VSL_stats->fetch_failed);
+       }
+
+       if (conf->collect_hcb)
+       {
+               /* HCB Lookups without lock */
+               varnish_submit_derive (conf->instance, "hcb", "cache_operation", "lookup_nolock", VSL_stats->hcb_nolock);
+               /* HCB Lookups with lock    */
+               varnish_submit_derive (conf->instance, "hcb", "cache_operation", "lookup_lock",   VSL_stats->hcb_lock);
+               /* HCB Inserts              */
+               varnish_submit_derive (conf->instance, "hcb", "cache_operation", "insert",        VSL_stats->hcb_insert);
+       }
+
+       if (conf->collect_shm)
+       {
+               /* SHM records                 */
+               varnish_submit_derive (conf->instance, "shm", "total_operations", "records"   , VSL_stats->shm_records);
+               /* SHM writes                  */
+               varnish_submit_derive (conf->instance, "shm", "total_operations", "writes"    , VSL_stats->shm_writes);
+               /* SHM flushes due to overflow */
+               varnish_submit_derive (conf->instance, "shm", "total_operations", "flushes"   , VSL_stats->shm_flushes);
+               /* SHM MTX contention          */
+               varnish_submit_derive (conf->instance, "shm", "total_operations", "contention", VSL_stats->shm_cont);
+               /* SHM cycles through buffer   */
+               varnish_submit_derive (conf->instance, "shm", "total_operations", "cycles"    , VSL_stats->shm_cycles);
+       }
+
+       if (conf->collect_sm)
+       {
+               /* allocator requests */
+               varnish_submit_derive (conf->instance, "sm", "total_requests", "nreq",  VSL_stats->sm_nreq);
+               /* outstanding allocations */
+               varnish_submit_gauge (conf->instance,  "sm", "requests", "outstanding", VSL_stats->sm_nobj);
+               /* bytes allocated */
+               varnish_submit_derive (conf->instance,  "sm", "total_bytes", "allocated",      VSL_stats->sm_balloc);
+               /* bytes free */
+               varnish_submit_derive (conf->instance,  "sm", "total_bytes", "free",           VSL_stats->sm_bfree);
+       }
+
+       if (conf->collect_sma)
+       {
+               /* SMA allocator requests */
+               varnish_submit_derive (conf->instance, "sma", "total_requests", "nreq",  VSL_stats->sma_nreq);
+               /* SMA outstanding allocations */
+               varnish_submit_gauge (conf->instance,  "sma", "requests", "outstanding", VSL_stats->sma_nobj);
+               /* SMA outstanding bytes */
+               varnish_submit_gauge (conf->instance,  "sma", "bytes", "outstanding",    VSL_stats->sma_nbytes);
+               /* SMA bytes allocated */
+               varnish_submit_derive (conf->instance,  "sma", "total_bytes", "allocated",      VSL_stats->sma_balloc);
+               /* SMA bytes free */
+               varnish_submit_derive (conf->instance,  "sma", "total_bytes", "free" ,          VSL_stats->sma_bfree);
+       }
+
+       if (conf->collect_sms)
+       {
+               /* SMS allocator requests */
+               varnish_submit_derive (conf->instance, "sms", "total_requests", "allocator", VSL_stats->sms_nreq);
+               /* SMS outstanding allocations */
+               varnish_submit_gauge (conf->instance,  "sms", "requests", "outstanding",     VSL_stats->sms_nobj);
+               /* SMS outstanding bytes */
+               varnish_submit_gauge (conf->instance,  "sms", "bytes", "outstanding",        VSL_stats->sms_nbytes);
+               /* SMS bytes allocated */
+               varnish_submit_derive (conf->instance,  "sms", "total_bytes", "allocated",          VSL_stats->sms_balloc);
+               /* SMS bytes freed */
+               varnish_submit_derive (conf->instance,  "sms", "total_bytes", "free",               VSL_stats->sms_bfree);
+       }
+
+       if (conf->collect_totals)
+       {
+               /* Total Sessions */
+               varnish_submit_derive (conf->instance, "totals", "total_sessions", "sessions",  VSL_stats->s_sess);
+               /* Total Requests */
+               varnish_submit_derive (conf->instance, "totals", "total_requests", "requests",  VSL_stats->s_req);
+               /* Total pipe */
+               varnish_submit_derive (conf->instance, "totals", "total_operations", "pipe",    VSL_stats->s_pipe);
+               /* Total pass */
+               varnish_submit_derive (conf->instance, "totals", "total_operations", "pass",    VSL_stats->s_pass);
+               /* Total fetch */
+               varnish_submit_derive (conf->instance, "totals", "total_operations", "fetches", VSL_stats->s_fetch);
+               /* Total header bytes */
+               varnish_submit_derive (conf->instance, "totals", "total_bytes", "header-bytes", VSL_stats->s_hdrbytes);
+               /* Total body byte */
+               varnish_submit_derive (conf->instance, "totals", "total_bytes", "body-bytes",   VSL_stats->s_bodybytes);
+       }
+
+       if (conf->collect_workers)
+       {
+               /* worker threads */
+               varnish_submit_gauge (conf->instance, "workers", "threads", "worker",            VSL_stats->n_wrk);
+               /* worker threads created */
+               varnish_submit_derive (conf->instance, "workers", "total_threads", "created",     VSL_stats->n_wrk_create);
+               /* worker threads not created */
+               varnish_submit_derive (conf->instance, "workers", "total_threads", "failed",      VSL_stats->n_wrk_failed);
+               /* worker threads limited */
+               varnish_submit_derive (conf->instance, "workers", "total_threads", "limited",     VSL_stats->n_wrk_max);
+               /* queued work requests */
+               varnish_submit_derive (conf->instance, "workers", "total_requests", "queued",     VSL_stats->n_wrk_queue);
+               /* overflowed work requests */
+               varnish_submit_derive (conf->instance, "workers", "total_requests", "overflowed", VSL_stats->n_wrk_overflow);
+               /* dropped work requests */
+               varnish_submit_derive (conf->instance, "workers", "total_requests", "dropped",    VSL_stats->n_wrk_drop);
+       }
+} /* }}} void varnish_monitor */
+
+static int varnish_read (user_data_t *ud) /* {{{ */
+{
+       struct varnish_stats *VSL_stats;
+       user_config_t *conf;
+
+       if ((ud == NULL) || (ud->data == NULL))
+               return (EINVAL);
+
+       conf = ud->data;
+
+       VSL_stats = VSL_OpenStats (conf->instance);
+       if (VSL_stats == NULL)
+       {
+               ERROR ("Varnish plugin : unable to load statistics");
+
+               return (-1);
+       }
+
+       varnish_monitor (conf, VSL_stats);
+
+    return (0);
+} /* }}} */
+
+static void varnish_config_free (void *ptr) /* {{{ */
+{
+       user_config_t *conf = ptr;
+
+       if (conf == NULL)
+               return;
+
+       sfree (conf->instance);
+       sfree (conf);
+} /* }}} */
+
+static int varnish_config_apply_default (user_config_t *conf) /* {{{ */
+{
+       if (conf == NULL)
+               return (EINVAL);
+
+       conf->collect_backend     = 1;
+       conf->collect_cache       = 1;
+       conf->collect_connections = 1;
+       conf->collect_esi         = 0;
+       conf->collect_fetch       = 0;
+       conf->collect_hcb         = 0;
+       conf->collect_shm         = 1;
+       conf->collect_sm          = 0;
+       conf->collect_sma         = 0;
+       conf->collect_sms         = 0;
+       conf->collect_totals      = 0;
+       
+       return (0);
+} /* }}} int varnish_config_apply_default */
+
+static int varnish_init (void) /* {{{ */
+{
+       user_config_t *conf;
+       user_data_t ud;
+
+       if (have_instance)
+               return (0);
+
+       conf = malloc (sizeof (*conf));
+       if (conf == NULL)
+               return (ENOMEM);
+       memset (conf, 0, sizeof (*conf));
+
+       /* Default settings: */
+       conf->instance = NULL;
+
+       varnish_config_apply_default (conf);
+
+       ud.data = conf;
+       ud.free_func = varnish_config_free;
+
+       plugin_register_complex_read (/* group = */ "varnish",
+                       /* name      = */ "varnish/localhost",
+                       /* callback  = */ varnish_read,
+                       /* interval  = */ NULL,
+                       /* user data = */ &ud);
+
+       return (0);
+} /* }}} int varnish_init */
+
+static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */
+{
+       user_config_t *conf;
+       user_data_t ud;
+       char callback_name[DATA_MAX_NAME_LEN];
+       int i;
+
+       conf = malloc (sizeof (*conf));
+       if (conf == NULL)
+               return (ENOMEM);
+       memset (conf, 0, sizeof (*conf));
+       conf->instance = NULL;
+
+       varnish_config_apply_default (conf);
+
+       if (ci->values_num == 1)
+       {
+               int status;
+
+               status = cf_util_get_string (ci, &conf->instance);
+               if (status != 0)
+               {
+                       sfree (conf);
+                       return (status);
+               }
+               assert (conf->instance != NULL);
+
+               if (strcmp ("localhost", conf->instance) == 0)
+               {
+                       sfree (conf->instance);
+                       conf->instance = NULL;
+               }
+       }
+       else if (ci->values_num > 1)
+       {
+               WARNING ("Varnish plugin: \"Instance\" blocks accept only "
+                               "one argument.");
+               return (EINVAL);
+       }
+
+       for (i = 0; i < ci->children_num; i++)
+       {
+               oconfig_item_t *child = ci->children + i;
+
+               if (strcasecmp ("CollectCache", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_cache);
+               else if (strcasecmp ("CollectConnections", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_connections);
+               else if (strcasecmp ("CollectESI", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_esi);
+               else if (strcasecmp ("CollectBackend", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_backend);
+               else if (strcasecmp ("CollectFetch", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_fetch);
+               else if (strcasecmp ("CollectHCB", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_hcb);
+               else if (strcasecmp ("CollectSHM", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_shm);
+               else if (strcasecmp ("CollectSMA", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_sma);
+               else if (strcasecmp ("CollectSMS", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_sms);
+               else if (strcasecmp ("CollectSM", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_sm);
+               else if (strcasecmp ("CollectTotals", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_totals);
+               else if (strcasecmp ("CollectWorkers", child->key) == 0)
+                       cf_util_get_boolean (child, &conf->collect_workers);
+               else
+               {
+                       WARNING ("Varnish plugin: Ignoring unknown "
+                                       "configuration option: \"%s\"",
+                                       child->key);
+               }
+       }
+
+       if (!conf->collect_cache
+                       && !conf->collect_connections
+                       && !conf->collect_esi
+                       && !conf->collect_backend
+                       && !conf->collect_fetch
+                       && !conf->collect_hcb
+                       && !conf->collect_shm
+                       && !conf->collect_sma
+                       && !conf->collect_sms
+                       && !conf->collect_sm
+                       && !conf->collect_totals
+                       && !conf->collect_workers)
+       {
+               WARNING ("Varnish plugin: No metric has been configured for "
+                               "instance \"%s\". Disabling this instance.",
+                               (conf->instance == NULL) ? "localhost" : conf->instance);
+               return (EINVAL);
+       }
+
+       ssnprintf (callback_name, sizeof (callback_name), "varnish/%s",
+                       (conf->instance == NULL) ? "localhost" : conf->instance);
+
+       ud.data = conf;
+       ud.free_func = varnish_config_free;
+
+       plugin_register_complex_read (/* group = */ "varnish",
+                       /* name      = */ callback_name,
+                       /* callback  = */ varnish_read,
+                       /* interval  = */ NULL,
+                       /* user data = */ &ud);
+
+       have_instance = 1;
+
+       return (0);
+} /* }}} int varnish_config_instance */
+
+static int varnish_config (oconfig_item_t *ci) /* {{{ */
+{
+       int i;
+
+       for (i = 0; i < ci->children_num; i++)
+       {
+               oconfig_item_t *child = ci->children + i;
+
+               if (strcasecmp ("Instance", child->key) == 0)
+                       varnish_config_instance (child);
+               else
+               {
+                       WARNING ("Varnish plugin: Ignoring unknown "
+                                       "configuration option: \"%s\"",
+                                       child->key);
+               }
+       }
+
+       return (0);
+} /* }}} int varnish_config */
+
+void module_register (void) /* {{{ */
+{
+       plugin_register_complex_config ("varnish", varnish_config);
+       plugin_register_init ("varnish", varnish_init);
+} /* }}} */
+
+/* vim: set sw=8 noet fdm=marker : */
index d32f1db..56997bf 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/vmem.c
- * Copyright (C) 2008  Florian octo Forster
+ * Copyright (C) 2008-2010  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
@@ -57,12 +57,12 @@ static void submit (const char *plugin_instance, const char *type,
 } /* void vmem_submit */
 
 static void submit_two (const char *plugin_instance, const char *type,
-    const char *type_instance, counter_t c0, counter_t c1)
+    const char *type_instance, derive_t c0, derive_t c1)
 {
   value_t values[2];
 
-  values[0].counter = c0;
-  values[1].counter = c1;
+  values[0].derive = c0;
+  values[1].derive = c1;
 
   submit (plugin_instance, type, type_instance, values, 2);
 } /* void submit_one */
@@ -93,16 +93,16 @@ static int vmem_config (const char *key, const char *value)
 static int vmem_read (void)
 {
 #if KERNEL_LINUX
-  counter_t pgpgin = 0;
-  counter_t pgpgout = 0;
+  derive_t pgpgin = 0;
+  derive_t pgpgout = 0;
   int pgpgvalid = 0;
 
-  counter_t pswpin = 0;
-  counter_t pswpout = 0;
+  derive_t pswpin = 0;
+  derive_t pswpout = 0;
   int pswpvalid = 0;
 
-  counter_t pgfault = 0;
-  counter_t pgmajfault = 0;
+  derive_t pgfault = 0;
+  derive_t pgmajfault = 0;
   int pgfaultvalid = 0;
 
   FILE *fh;
@@ -123,7 +123,7 @@ static int vmem_read (void)
     int fields_num;
     char *key;
     char *endptr;
-    counter_t counter;
+    derive_t counter;
     gauge_t gauge;
 
     fields_num = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
@@ -205,31 +205,31 @@ static int vmem_read (void)
     else if (strncmp ("pgalloc_", key, strlen ("pgalloc_")) == 0)
     {
       char *inst = key + strlen ("pgalloc_");
-      value_t value  = { .counter = counter };
+      value_t value  = { .derive = counter };
       submit_one (inst, "vmpage_action", "alloc", value);
     }
     else if (strncmp ("pgrefill_", key, strlen ("pgrefill_")) == 0)
     {
       char *inst = key + strlen ("pgrefill_");
-      value_t value  = { .counter = counter };
+      value_t value  = { .derive = counter };
       submit_one (inst, "vmpage_action", "refill", value);
     }
     else if (strncmp ("pgsteal_", key, strlen ("pgsteal_")) == 0)
     {
       char *inst = key + strlen ("pgsteal_");
-      value_t value  = { .counter = counter };
+      value_t value  = { .derive = counter };
       submit_one (inst, "vmpage_action", "steal", value);
     }
     else if (strncmp ("pgscan_kswapd_", key, strlen ("pgscan_kswapd_")) == 0)
     {
       char *inst = key + strlen ("pgscan_kswapd_");
-      value_t value  = { .counter = counter };
+      value_t value  = { .derive = counter };
       submit_one (inst, "vmpage_action", "scan_kswapd", value);
     }
     else if (strncmp ("pgscan_direct_", key, strlen ("pgscan_direct_")) == 0)
     {
       char *inst = key + strlen ("pgscan_direct_");
-      value_t value  = { .counter = counter };
+      value_t value  = { .derive = counter };
       submit_one (inst, "vmpage_action", "scan_direct", value);
     }
 
@@ -241,17 +241,17 @@ static int vmem_read (void)
      */
     else if (strcmp ("pgfree", key) == 0)
     {
-      value_t value  = { .counter = counter };
+      value_t value  = { .derive = counter };
       submit_one (NULL, "vmpage_action", "free", value);
     }
     else if (strcmp ("pgactivate", key) == 0)
     {
-      value_t value  = { .counter = counter };
+      value_t value  = { .derive = counter };
       submit_one (NULL, "vmpage_action", "activate", value);
     }
     else if (strcmp ("pgdeactivate", key) == 0)
     {
-      value_t value  = { .counter = counter };
+      value_t value  = { .derive = counter };
       submit_one (NULL, "vmpage_action", "deactivate", value);
     }
   } /* while (fgets) */
index 1615ca0..d80717c 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * collectd - src/vserver.c
  * Copyright (C) 2006,2007  Sebastian Harl
- * Copyright (C) 2007,2008  Florian octo Forster
+ * Copyright (C) 2007-2010  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
@@ -48,13 +48,13 @@ static int vserver_init (void)
 } /* static void vserver_init(void) */
 
 static void traffic_submit (const char *plugin_instance,
-               const char *type_instance, counter_t rx, counter_t tx)
+               const char *type_instance, derive_t rx, derive_t tx)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
@@ -107,14 +107,21 @@ static void submit_gauge (const char *plugin_instance, const char *type,
        plugin_dispatch_values (&vl);
 } /* void submit_gauge */
 
-static inline long long __get_sock_bytes(const char *s)
+static derive_t vserver_get_sock_bytes(const char *s)
 {
+       value_t v;
+       int status;
+
        while (s[0] != '/')
                ++s;
 
        /* Remove '/' */
        ++s;
-       return atoll(s);
+
+       status = parse_value (s, &v, DS_TYPE_DERIVE);
+       if (status != 0)
+               return (-1);
+       return (v.derive);
 }
 
 static int vserver_read (void)
@@ -201,8 +208,8 @@ static int vserver_read (void)
 
                while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
                {
-                       counter_t rx;
-                       counter_t tx;
+                       derive_t rx;
+                       derive_t tx;
                        char *type_instance;
 
                        if (strsplit (buffer, cols, 4) < 4)
@@ -221,8 +228,8 @@ static int vserver_read (void)
                        else
                                continue;
 
-                       rx = __get_sock_bytes (cols[1]);
-                       tx = __get_sock_bytes (cols[2]);
+                       rx = vserver_get_sock_bytes (cols[1]);
+                       tx = vserver_get_sock_bytes (cols[2]);
                        /* cols[3] == errors */
 
                        traffic_submit (dent->d_name, type_instance, rx, tx);
index 22b5842..3035e43 100644 (file)
@@ -61,7 +61,7 @@ struct wh_callback_s
         char   send_buffer[4096];
         size_t send_buffer_free;
         size_t send_buffer_fill;
-        time_t send_buffer_init_time;
+        cdtime_t send_buffer_init_time;
 
         pthread_mutex_t send_lock;
 };
@@ -72,7 +72,7 @@ static void wh_reset_buffer (wh_callback_t *cb)  /* {{{ */
         memset (cb->send_buffer, 0, sizeof (cb->send_buffer));
         cb->send_buffer_free = sizeof (cb->send_buffer);
         cb->send_buffer_fill = 0;
-        cb->send_buffer_init_time = time (NULL);
+        cb->send_buffer_init_time = cdtime ();
 
         if (cb->format == WH_FORMAT_JSON)
         {
@@ -158,19 +158,21 @@ static int wh_callback_init (wh_callback_t *cb) /* {{{ */
         return (0);
 } /* }}} int wh_callback_init */
 
-static int wh_flush_nolock (int timeout, wh_callback_t *cb) /* {{{ */
+static int wh_flush_nolock (cdtime_t timeout, wh_callback_t *cb) /* {{{ */
 {
         int status;
 
-        DEBUG ("write_http plugin: wh_flush_nolock: timeout = %i; "
+        DEBUG ("write_http plugin: wh_flush_nolock: timeout = %.3f; "
                         "send_buffer_fill = %zu;",
-                        timeout, cb->send_buffer_fill);
+                        CDTIME_T_TO_DOUBLE (timeout),
+                        cb->send_buffer_fill);
 
+        /* timeout == 0  => flush unconditionally */
         if (timeout > 0)
         {
-                time_t now;
+                cdtime_t now;
 
-                now = time (NULL);
+                now = cdtime ();
                 if ((cb->send_buffer_init_time + timeout) > now)
                         return (0);
         }
@@ -179,7 +181,7 @@ static int wh_flush_nolock (int timeout, wh_callback_t *cb) /* {{{ */
         {
                 if (cb->send_buffer_fill <= 0)
                 {
-                        cb->send_buffer_init_time = time (NULL);
+                        cb->send_buffer_init_time = cdtime ();
                         return (0);
                 }
 
@@ -190,7 +192,7 @@ static int wh_flush_nolock (int timeout, wh_callback_t *cb) /* {{{ */
         {
                 if (cb->send_buffer_fill <= 2)
                 {
-                        cb->send_buffer_init_time = time (NULL);
+                        cb->send_buffer_init_time = cdtime ();
                         return (0);
                 }
 
@@ -219,7 +221,7 @@ static int wh_flush_nolock (int timeout, wh_callback_t *cb) /* {{{ */
         return (status);
 } /* }}} wh_flush_nolock */
 
-static int wh_flush (int timeout, /* {{{ */
+static int wh_flush (cdtime_t timeout, /* {{{ */
                 const char *identifier __attribute__((unused)),
                 user_data_t *user_data)
 {
@@ -259,7 +261,7 @@ static void wh_callback_free (void *data) /* {{{ */
 
         cb = data;
 
-        wh_flush_nolock (/* timeout = */ -1, cb);
+        wh_flush_nolock (/* timeout = */ 0, cb);
 
         curl_easy_cleanup (cb->curl);
         sfree (cb->location);
@@ -271,76 +273,6 @@ static void wh_callback_free (void *data) /* {{{ */
         sfree (cb);
 } /* }}} void wh_callback_free */
 
-static int wh_value_list_to_string (char *buffer, /* {{{ */
-                size_t buffer_size,
-                const data_set_t *ds, const value_list_t *vl,
-                wh_callback_t *cb)
-{
-        size_t offset = 0;
-        int status;
-        int i;
-        gauge_t *rates = NULL;
-
-        assert (0 == strcmp (ds->type, vl->type));
-
-        memset (buffer, 0, buffer_size);
-
-#define BUFFER_ADD(...) do { \
-        status = ssnprintf (buffer + offset, buffer_size - offset, \
-                        __VA_ARGS__); \
-        if (status < 1) \
-        { \
-                sfree (rates); \
-                return (-1); \
-        } \
-        else if (((size_t) status) >= (buffer_size - offset)) \
-        { \
-                sfree (rates); \
-                return (-1); \
-        } \
-        else \
-                offset += ((size_t) status); \
-} while (0)
-
-        BUFFER_ADD ("%lu", (unsigned long) vl->time);
-
-        for (i = 0; i < ds->ds_num; i++)
-        {
-                if (ds->ds[i].type == DS_TYPE_GAUGE)
-                        BUFFER_ADD (":%f", vl->values[i].gauge);
-                else if (cb->store_rates)
-                {
-                        if (rates == NULL)
-                                rates = uc_get_rate (ds, vl);
-                        if (rates == NULL)
-                        {
-                                WARNING ("write_http plugin: "
-                                                "uc_get_rate failed.");
-                                return (-1);
-                        }
-                        BUFFER_ADD (":%g", rates[i]);
-                }
-                else if (ds->ds[i].type == DS_TYPE_COUNTER)
-                        BUFFER_ADD (":%llu", vl->values[i].counter);
-                else if (ds->ds[i].type == DS_TYPE_DERIVE)
-                        BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
-                else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
-                        BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
-                else
-                {
-                        ERROR ("write_http plugin: Unknown data source type: %i",
-                                        ds->ds[i].type);
-                        sfree (rates);
-                        return (-1);
-                }
-        } /* for ds->ds_num */
-
-#undef BUFFER_ADD
-
-        sfree (rates);
-        return (0);
-} /* }}} int wh_value_list_to_string */
-
 static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{{ */
                 wh_callback_t *cb)
 {
@@ -367,7 +299,7 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
 
         /* Convert the values to an ASCII representation and put that into
          * `values'. */
-        status = wh_value_list_to_string (values, sizeof (values), ds, vl, cb);
+        status = format_values (values, sizeof (values), ds, vl, cb->store_rates);
         if (status != 0) {
                 ERROR ("write_http plugin: error with "
                                 "wh_value_list_to_string");
@@ -375,8 +307,10 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
         }
 
         command_len = (size_t) ssnprintf (command, sizeof (command),
-                        "PUTVAL %s interval=%i %s\r\n",
-                        key, vl->interval, values);
+                        "PUTVAL %s interval=%.3f %s\r\n",
+                        key,
+                        CDTIME_T_TO_DOUBLE (vl->interval),
+                        values);
         if (command_len >= sizeof (command)) {
                 ERROR ("write_http plugin: Command buffer too small: "
                                 "Need %zu bytes.", command_len + 1);
@@ -398,7 +332,7 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
 
         if (command_len >= cb->send_buffer_free)
         {
-                status = wh_flush_nolock (/* timeout = */ -1, cb);
+                status = wh_flush_nolock (/* timeout = */ 0, cb);
                 if (status != 0)
                 {
                         pthread_mutex_unlock (&cb->send_lock);
@@ -450,7 +384,7 @@ static int wh_write_json (const data_set_t *ds, const value_list_t *vl, /* {{{ *
                         ds, vl, cb->store_rates);
         if (status == (-ENOMEM))
         {
-                status = wh_flush_nolock (/* timeout = */ -1, cb);
+                status = wh_flush_nolock (/* timeout = */ 0, cb);
                 if (status != 0)
                 {
                         wh_reset_buffer (cb);
diff --git a/src/write_redis.c b/src/write_redis.c
new file mode 100644 (file)
index 0000000..58f2cae
--- /dev/null
@@ -0,0 +1,238 @@
+/**
+ * collectd - src/write_redis.c
+ * Copyright (C) 2010  Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Florian Forster <ff at octo.it>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "configfile.h"
+
+#include <pthread.h>
+#include <credis.h>
+
+struct wr_node_s
+{
+  char name[DATA_MAX_NAME_LEN];
+
+  char *host;
+  int port;
+  int timeout;
+
+  REDIS conn;
+  pthread_mutex_t lock;
+};
+typedef struct wr_node_s wr_node_t;
+
+/*
+ * Functions
+ */
+static int wr_write (const data_set_t *ds, /* {{{ */
+    const value_list_t *vl,
+    user_data_t *ud)
+{
+  wr_node_t *node = ud->data;
+  char ident[512];
+  char key[512];
+  char value[512];
+  size_t value_size;
+  char *value_ptr;
+  int status;
+  int i;
+
+  status = FORMAT_VL (ident, sizeof (ident), vl);
+  if (status != 0)
+    return (status);
+  ssnprintf (key, sizeof (key), "collectd/%s", ident);
+
+  memset (value, 0, sizeof (value));
+  value_size = sizeof (value);
+  value_ptr = &value[0];
+
+#define APPEND(...) do {                                             \
+  status = snprintf (value_ptr, value_size, __VA_ARGS__);            \
+  if (((size_t) status) > value_size)                                \
+  {                                                                  \
+    value_ptr += value_size;                                         \
+    value_size = 0;                                                  \
+  }                                                                  \
+  else                                                               \
+  {                                                                  \
+    value_ptr += status;                                             \
+    value_size -= status;                                            \
+  }                                                                  \
+} while (0)
+
+  APPEND ("%lu", (unsigned long) vl->time);
+  for (i = 0; i < ds->ds_num; i++)
+  {
+    if (ds->ds[i].type == DS_TYPE_COUNTER)
+      APPEND ("%llu", vl->values[i].counter);
+    else if (ds->ds[i].type == DS_TYPE_GAUGE)
+      APPEND ("%g", vl->values[i].gauge);
+    else if (ds->ds[i].type == DS_TYPE_DERIVE)
+      APPEND ("%"PRIi64, vl->values[i].derive);
+    else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+      APPEND ("%"PRIu64, vl->values[i].absolute);
+    else
+      assert (23 == 42);
+  }
+
+#undef APPEND
+
+  pthread_mutex_lock (&node->lock);
+
+  if (node->conn == NULL)
+  {
+    node->conn = credis_connect (node->host, node->port, node->timeout);
+    if (node->conn == NULL)
+    {
+      ERROR ("write_redis plugin: Connecting to host \"%s\" (port %i) failed.",
+          (node->host != NULL) ? node->host : "localhost",
+          (node->port != 0) ? node->port : 6379);
+      pthread_mutex_unlock (&node->lock);
+      return (-1);
+    }
+  }
+
+  /* "credis_zadd" doesn't handle a NULL pointer gracefully, so I'd rather
+   * have a meaningful assertion message than a normal segmentation fault. */
+  assert (node->conn != NULL);
+  status = credis_zadd (node->conn, key, (double) vl->time, value);
+
+  credis_sadd (node->conn, "collectd/values", ident);
+
+  pthread_mutex_unlock (&node->lock);
+
+  return (0);
+} /* }}} int wr_write */
+
+static void wr_config_free (void *ptr) /* {{{ */
+{
+  wr_node_t *node = ptr;
+
+  if (node == NULL)
+    return;
+
+  if (node->conn != NULL)
+  {
+    credis_close (node->conn);
+    node->conn = NULL;
+  }
+
+  sfree (node->host);
+  sfree (node);
+} /* }}} void wr_config_free */
+
+static int wr_config_node (oconfig_item_t *ci) /* {{{ */
+{
+  wr_node_t *node;
+  int status;
+  int i;
+
+  node = malloc (sizeof (*node));
+  if (node == NULL)
+    return (ENOMEM);
+  memset (node, 0, sizeof (*node));
+  node->host = NULL;
+  node->port = 0;
+  node->timeout = 1000;
+  node->conn = NULL;
+  pthread_mutex_init (&node->lock, /* attr = */ NULL);
+
+  status = cf_util_get_string_buffer (ci, node->name, sizeof (node->name));
+  if (status != 0)
+  {
+    sfree (node);
+    return (status);
+  }
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp ("Host", child->key) == 0)
+      status = cf_util_get_string (child, &node->host);
+    else if (strcasecmp ("Port", child->key) == 0)
+    {
+      status = cf_util_get_port_number (child);
+      if (status > 0)
+      {
+        node->port = status;
+        status = 0;
+      }
+    }
+    else if (strcasecmp ("Timeout", child->key) == 0)
+      status = cf_util_get_int (child, &node->timeout);
+    else
+      WARNING ("write_redis plugin: Ignoring unknown config option \"%s\".",
+          child->key);
+
+    if (status != 0)
+      break;
+  } /* for (i = 0; i < ci->children_num; i++) */
+
+  if (status == 0)
+  {
+    char cb_name[DATA_MAX_NAME_LEN];
+    user_data_t ud;
+
+    ssnprintf (cb_name, sizeof (cb_name), "write_redis/%s", node->name);
+
+    ud.data = node;
+    ud.free_func = wr_config_free;
+
+    status = plugin_register_write (cb_name, wr_write, &ud);
+  }
+
+  if (status != 0)
+    wr_config_free (node);
+
+  return (status);
+} /* }}} int wr_config_node */
+
+static int wr_config (oconfig_item_t *ci) /* {{{ */
+{
+  int i;
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp ("Node", child->key) == 0)
+      wr_config_node (child);
+    else
+      WARNING ("write_redis plugin: Ignoring unknown "
+          "configuration option \"%s\" at top level.", child->key);
+  }
+
+  return (0);
+} /* }}} int wr_config */
+
+void module_register (void)
+{
+  plugin_register_complex_config ("write_redis", wr_config);
+}
+
+/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */
index 79a234f..f886c86 100644 (file)
@@ -46,54 +46,48 @@ static void za_submit (const char* type, const char* type_instance, value_t* val
 
 static void za_submit_gauge (const char* type, const char* type_instance, gauge_t value)
 {
-       value_t values[1];
+       value_t vv;
 
-       values[0].gauge = value;
-
-       za_submit (type, type_instance, values, STATIC_ARRAY_SIZE(values));
+       vv.gauge = value;
+       za_submit (type, type_instance, &vv, 1);
 }
 
-static void za_submit_size (gauge_t size, gauge_t size_target, gauge_t limit_min, gauge_t limit_max)
+static void za_submit_derive (const char* type, const char* type_instance, derive_t dv)
 {
-       value_t values[4];
-
-       values[0].gauge = size;
-       values[1].gauge = size_target;
-       values[2].gauge = limit_min;
-       values[3].gauge = limit_max;
+       value_t vv;
 
-       za_submit ("arc_size", "", values, STATIC_ARRAY_SIZE(values));
+       vv.derive = dv;
+       za_submit (type, type_instance, &vv, 1);
 }
 
-static void za_submit_bytes (counter_t read, counter_t write)
+static void za_submit_ratio (const char* type_instance, gauge_t hits, gauge_t misses)
 {
-       value_t values[2];
+       gauge_t ratio = NAN;
 
-       values[0].counter = read;
-       values[1].counter = write;
+       if (!isfinite (hits) || (hits < 0.0))
+               hits = 0.0;
+       if (!isfinite (misses) || (misses < 0.0))
+               misses = 0.0;
 
-       za_submit ("arc_l2_bytes", "", values, STATIC_ARRAY_SIZE(values));
-}
-
-static void za_submit_counts (char *type_instance, counter_t demand_data, counter_t demand_metadata,
-       counter_t prefetch_data, counter_t prefetch_metadata)
-{
-       value_t values[4];
+       if ((hits != 0.0) || (misses != 0.0))
+               ratio = hits / (hits + misses);
 
-       values[0].counter = demand_data;
-       values[1].counter = demand_metadata;
-       values[2].counter = prefetch_data;
-       values[3].counter = prefetch_metadata;
-
-       za_submit ("arc_counts", type_instance, values, STATIC_ARRAY_SIZE(values));
+       za_submit_gauge ("cache_ratio", type_instance, ratio);
 }
 
 static int za_read (void)
 {
-       gauge_t   arcsize, targetsize, minlimit, maxlimit, hits, misses, l2_size, l2_hits, l2_misses;
-       counter_t demand_data_hits, demand_metadata_hits, prefetch_data_hits, prefetch_metadata_hits;
-       counter_t demand_data_misses, demand_metadata_misses, prefetch_data_misses, prefetch_metadata_misses;
-       counter_t l2_read_bytes, l2_write_bytes;
+       gauge_t  arc_size, l2_size;
+       derive_t demand_data_hits,
+                demand_metadata_hits,
+                prefetch_data_hits,
+                prefetch_metadata_hits,
+                demand_data_misses,
+                demand_metadata_misses,
+                prefetch_data_misses,
+                prefetch_metadata_misses;
+       gauge_t  arc_hits, arc_misses, l2_hits, l2_misses;
+       value_t  l2_io[2];
        kstat_t  *ksp   = NULL;
 
        get_kstat (&ksp, "zfs", 0, "arcstats");
@@ -103,11 +97,14 @@ static int za_read (void)
                return (-1);
        }
 
-       arcsize    = get_kstat_value(ksp, "size");
-       targetsize = get_kstat_value(ksp, "c");
-       minlimit   = get_kstat_value(ksp, "c_min");
-       maxlimit   = get_kstat_value(ksp, "c_max");
+       /* Sizes */
+       arc_size   = get_kstat_value(ksp, "size");
+       l2_size    = get_kstat_value(ksp, "l2_size");
+
+       za_submit_gauge ("cache_size", "arc", arc_size);
+       za_submit_gauge ("cache_size", "L2", l2_size);
 
+       /* Hits / misses */
        demand_data_hits       = get_kstat_value(ksp, "demand_data_hits");
        demand_metadata_hits   = get_kstat_value(ksp, "demand_metadata_hits");
        prefetch_data_hits     = get_kstat_value(ksp, "prefetch_data_hits");
@@ -118,31 +115,33 @@ static int za_read (void)
        prefetch_data_misses     = get_kstat_value(ksp, "prefetch_data_misses");
        prefetch_metadata_misses = get_kstat_value(ksp, "prefetch_metadata_misses");
 
-       hits   = get_kstat_value(ksp, "hits");
-       misses = get_kstat_value(ksp, "misses");
+       za_submit_derive ("cache_result", "demand_data-hit",       demand_data_hits);
+       za_submit_derive ("cache_result", "demand_metadata-hit",   demand_metadata_hits);
+       za_submit_derive ("cache_result", "prefetch_data-hit",     prefetch_data_hits);
+       za_submit_derive ("cache_result", "prefetch_metadata-hit", prefetch_metadata_hits);
 
-       l2_size        = get_kstat_value(ksp, "l2_size");
-       l2_read_bytes  = get_kstat_value(ksp, "l2_read_bytes");
-       l2_write_bytes = get_kstat_value(ksp, "l2_write_bytes");
-       l2_hits        = get_kstat_value(ksp, "l2_hits");
-       l2_misses      = get_kstat_value(ksp, "l2_misses");
+       za_submit_derive ("cache_result", "demand_data-miss",       demand_data_misses);
+       za_submit_derive ("cache_result", "demand_metadata-miss",   demand_metadata_misses);
+       za_submit_derive ("cache_result", "prefetch_data-miss",     prefetch_data_misses);
+       za_submit_derive ("cache_result", "prefetch_metadata-miss", prefetch_metadata_misses);
 
+       /* Ratios */
+       arc_hits   = (gauge_t) get_kstat_value(ksp, "hits");
+       arc_misses = (gauge_t) get_kstat_value(ksp, "misses");
+       l2_hits    = (gauge_t) get_kstat_value(ksp, "l2_hits");
+       l2_misses  = (gauge_t) get_kstat_value(ksp, "l2_misses");
 
-       za_submit_size (arcsize, targetsize, minlimit, maxlimit);
-       za_submit_gauge ("arc_l2_size", "", l2_size);
+       za_submit_ratio ("arc", arc_hits, arc_misses);
+       za_submit_ratio ("L2", l2_hits, l2_misses);
 
-       za_submit_counts ("hits",   demand_data_hits,     demand_metadata_hits,
-                                   prefetch_data_hits,   prefetch_metadata_hits);
-       za_submit_counts ("misses", demand_data_misses,   demand_metadata_misses,
-                                   prefetch_data_misses, prefetch_metadata_misses);
+       /* I/O */
+       l2_io[0].derive = get_kstat_value(ksp, "l2_read_bytes");
+       l2_io[1].derive = get_kstat_value(ksp, "l2_write_bytes");
 
-       za_submit_gauge ("arc_ratio", "L1", hits / (hits + misses));
-       za_submit_gauge ("arc_ratio", "L2", l2_hits / (l2_hits + l2_misses));
-
-       za_submit_bytes (l2_read_bytes, l2_write_bytes);
+       za_submit ("io_octets", "L2", l2_io, /* num values = */ 2);
 
        return (0);
-}
+} /* int za_read */
 
 static int za_init (void) /* {{{ */
 {
index 0e0d8d4..d554643 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-DEFAULT_VERSION="4.10.8.git"
+DEFAULT_VERSION="5.0.4.git"
 
 VERSION="`git describe 2> /dev/null | sed -e 's/^collectd-//'`"