Code

Merge branch 'collectd-4.10'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 27 Nov 2010 10:46:11 +0000 (11:46 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 27 Nov 2010 10:46:11 +0000 (11:46 +0100)
Conflicts:
src/utils_rrdcreate.c

103 files changed:
.gitignore
AUTHORS
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/exec-munin.px
contrib/exec-nagios.px
contrib/exec-smartctl
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.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/dns.c
src/exec.c
src/gmond.c
src/hddtemp.c
src/interface.c
src/ipmi.c
src/ipvs.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/match_timediff.c
src/memcachec.c
src/memcached.c
src/modbus.c
src/mysql.c
src/netapp.c
src/network.c
src/network.h
src/nginx.c
src/notify_email.c
src/onewire.c
src/oracle.c
src/perl.c
src/plugin.c
src/plugin.h
src/postgresql.c
src/powerdns.c
src/python.c
src/pyvalues.c
src/redis.c [new file with mode: 0644]
src/rrdcached.c
src/rrdtool.c
src/snmp.c
src/swap.c
src/target_notification.c
src/target_scale.c
src/target_v5upgrade.c [new file with mode: 0644]
src/ted.c
src/thermal.c
src/types.db
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_threshold.c
src/utils_threshold.h
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/write_http.c
src/write_redis.c [new file with mode: 0644]
src/zfs_arc.c

index e8f9af66d7879336910ff56dd76f8b70d796dd23..cbdd62f821579ae7369bbd1931b9bc4ef0bd60f2 100644 (file)
@@ -65,3 +65,9 @@ bindings/java/org/collectd/java/*.class
 
 # python stuff
 *.pyc
+
+# tag stuff
+src/tags
+
+# backup stuff
+*~
diff --git a/AUTHORS b/AUTHORS
index 45689652ab1eb1fbfc3df8c2677434d924212c57..c57f90b2d0c38aa625f48e280dac736570ec0284 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,
@@ -72,6 +76,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.
@@ -159,6 +166,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.
 
diff --git a/README b/README
index 5063069009e490e245e57e3498f07a61cb3c2cbf..2ed8934fc92e43842dcab3ed7df8808bc5aa4bfb 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
@@ -504,6 +519,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.
@@ -607,6 +626,10 @@ Prerequisites
     Used by the `python' plugin. Currently, only 2.3 ≦ Python < 3 is 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/>
@@ -653,6 +676,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 3e492ddffd9a7f404579b77ef119087c59fee24d..410c61c60ef21d2d350e29a699fe1c2e5630d42c 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 1baeff24ed7fb8e58e6a80df22c576f3adb3b78c..b8d6f40f86f604b56eb042eb413a11f6226fa58b 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 ffa9ded4fbdc874b32dc3c5e6472df5352c6c59d..0c81bc9ad941760f07021530d6663f32ee34b75f 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 1587bd5f9729009d13d72f8a31766439f33a6341..b1fbfb3ec18c14fadf0ae56c845d8ff76a0f5417 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 f1b5d859874c0affc08143e1a536ca6f99747dc6..ca3b5d2349805a505ae22df4faad8c7b9feda529 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 a47fed03a67237582cdb07f7c8c2e9ef4043da3f..3b46188a3e73ea9ac4cb7be49b3db4bd1dccc2d7 100644 (file)
@@ -108,9 +108,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")
 
@@ -568,6 +572,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,
@@ -577,8 +602,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"])
@@ -592,6 +618,55 @@ 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"])
+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
 
 # For load module
 AC_CHECK_FUNCS(getloadavg, [have_getloadavg="yes"], [have_getloadavg="no"])
@@ -1144,6 +1219,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")
 
@@ -1230,6 +1311,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=""
@@ -3002,6 +3141,57 @@ 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"
+])
+if test "x$with_librabbitmq" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
+
+       AC_CHECK_HEADERS(amqp.h, [with_librabbitmq="yes"], [with_librabbitmq="no (amqp.h not found)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_librabbitmq" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       SAVE_LDFLAGS="$LDFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
+       LDFLAGS="$LDFLAGS $with_librabbitmq_ldflags"
+
+       AC_CHECK_LIB(rabbitmq, amqp_basic_publish, [with_librabbitmq="yes"], [with_librabbitmq="no (Symbol 'amqp_basic_publish' not found)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+       LDFLAGS="$SAVE_LDFLAGS"
+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
+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.])],
 [
@@ -3641,6 +3831,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 -lvarnish -lvarnishcompat -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 library)"
+       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=""
@@ -4135,6 +4417,7 @@ then
 fi
 if test "x$have_sysctlbyname" = "xyes"
 then
+       plugin_contextswitch="yes"
        plugin_cpu="yes"
        plugin_memory="yes"
        plugin_tcpconns="yes"
@@ -4262,6 +4545,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])
@@ -4296,6 +4580,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])
@@ -4331,6 +4616,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])
@@ -4346,6 +4632,7 @@ 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])
@@ -4355,10 +4642,12 @@ 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])
 
@@ -4533,6 +4822,7 @@ Configuration:
   Libraries:
     libcurl . . . . . . . $with_libcurl
     libdbi  . . . . . . . $with_libdbi
+    libcredis . . . . . . $with_libcredis
     libesmtp  . . . . . . $with_libesmtp
     libganglia  . . . . . $with_libganglia
     libgcrypt . . . . . . $with_libgcrypt
@@ -4556,12 +4846,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
@@ -4579,6 +4871,7 @@ Configuration:
     perl  . . . . . . . . $with_perl_bindings
 
   Modules:
+    amqp    . . . . . . . $enable_amqp
     apache  . . . . . . . $enable_apache
     apcups  . . . . . . . $enable_apcups
     apple_sensors . . . . $enable_apple_sensors
@@ -4613,6 +4906,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
@@ -4647,6 +4941,7 @@ Configuration:
     processes . . . . . . $enable_processes
     protocols . . . . . . $enable_protocols
     python  . . . . . . . $enable_python
+    redis . . . . . . . . $enable_redis
     routeros  . . . . . . $enable_routeros
     rrdcached . . . . . . $enable_rrdcached
     rrdtool . . . . . . . $enable_rrdtool
@@ -4662,6 +4957,7 @@ 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
@@ -4671,10 +4967,12 @@ Configuration:
     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 907ea9bccac0ad3bc68b2779216500c311d1b558..3e62ce009ae71ef16bcfe2d4ee118628e65ef26f 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 938721fc55624977fa89d5ea3a1d289531573b6d..4b112f95139aa97fc0b04b3044c528f3218837f8 100755 (executable)
@@ -24,7 +24,8 @@ use Regexp::Common ('number');
 our $ConfigFile = '/etc/exec-nagios.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);
@@ -235,6 +236,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;
@@ -250,7 +252,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
@@ -260,7 +264,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 d469816037946d34ae2daf7df5f36b91da0bfb11..99b69860b99effc5f775e68e9fbb8acbf08b7515 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
index c6b0538d305a572b67a5ec06ff63c3506279793b..1a7ba5b1240eacbff8f3ec84eedb2747dd13e1e7 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 \
@@ -41,6 +41,7 @@ collectd_SOURCES = collectd.c collectd.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)
@@ -105,11 +106,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
@@ -499,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
@@ -885,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
@@ -1042,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
@@ -1143,6 +1196,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
@@ -1182,6 +1245,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
@@ -1206,6 +1279,7 @@ dist_man_MANS = collectd.1 \
                collectd.conf.5 \
                collectd-email.5 \
                collectd-exec.5 \
+               collectdctl.1 \
                collectd-java.5 \
                collectdmon.1 \
                collectd-nagios.1 \
@@ -1222,6 +1296,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 \
diff --git a/src/amqp.c b/src/amqp.c
new file mode 100644 (file)
index 0000000..f0abd44
--- /dev/null
@@ -0,0 +1,939 @@
+/**
+ * collectd - src/amqp.c
+ * Copyright (C) 2009  Sebastien Pahl
+ * 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:
+ *   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 (r.library_errno)
+                return (sstrerror (r.library_errno, buffer, buffer_size));
+            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 */
+
+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 */
+
+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);
+    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)
+        {
+            ERROR ("amqp plugin: camqp_connect failed. "
+                    "Will sleep for %i seconds.", interval_g);
+            sleep (interval_g);
+            continue;
+        }
+
+        status = amqp_simple_wait_frame (conf->connection, &frame);
+        if (status < 0)
+        {
+            ERROR ("amqp plugin: amqp_simple_wait_frame failed. "
+                    "Will sleep for %i seconds.", interval_g);
+            camqp_close_connection (conf);
+            sleep (interval_g);
+            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);
+} /* }}} 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 3d6d957c5c2a721a3ce328fd19e27c2439e39a8c..506ba84ec23e58d9396e9165454c3a08a6e33be3 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 */
@@ -420,6 +387,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);
index 6e0b907f1e89203150a554b76ea0fc93312de211..47215c74bae0b6422d058dd5697a9d1fc180f0b6 100644 (file)
@@ -241,7 +241,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) {
index 81b3a2ecc07ecb11302b7ede4d2e26f87e72f0d8..10f68290e9bbc8ae8c7479364068f0b3ccae5b30 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 9c0c6eba1646cf771bea4bdf80b327b203723980..9e2f81aa9b9f0056d3aefa215605688b47f8ae81 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 45162bd3de607170e3b34399e078b851fd4a58bd..b3c1855aba2be7d98a3c112b62b5ddbebe33f609 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 "config.h"
 #endif
 
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+
 #if !defined(__GNUC__) || !__GNUC__
 # define __attribute__(x) /**/
 #endif
 #include <string.h>
 #include <strings.h>
 #include <assert.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <math.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*/
-#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) */
-#endif /* NAN_ZERO_ZERO */
-
 #define RET_OKAY     0
 #define RET_WARNING  1
 #define RET_CRITICAL 2
@@ -96,6 +78,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 +237,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 +264,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 +326,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 +385,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 +446,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 +577,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 +637,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 c6347eac9361746c8f60b6b33713983d466da241..d7c749cd3391aefc86369c208193063111655fe6 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 5c11b65281cea66df6cf786f102e7abbb363ee0a..6b44722cfe808605603a549ac3690c5998bb1eb7 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
index 277d3b0dc9432917db2f0483ec812742148852e3..d33d1d6685ff4755d9ab460a526313b468d6f71d 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;
@@ -139,15 +141,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)
@@ -311,22 +323,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 ();
@@ -335,27 +339,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)
                        {
@@ -368,7 +365,6 @@ static int do_loop (void)
                }
        } /* while (loop == 0) */
 
-       DEBUG ("return (0);");
        return (0);
 } /* int do_loop */
 
index d8e39dbebb3c9b362d98827acd9ab05da1078186..12259098700110c2ae31f877c8e4084f21f73aa9 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
@@ -114,6 +116,7 @@ FQDNLookup   true
 #@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
 #@BUILD_PLUGIN_PROTOCOLS_TRUE@LoadPlugin protocols
 #@BUILD_PLUGIN_PYTHON_TRUE@LoadPlugin python
+#@BUILD_PLUGIN_REDIS_TRUE@LoadPlugin redis
 #@BUILD_PLUGIN_ROUTEROS_TRUE@LoadPlugin routeros
 #@BUILD_PLUGIN_RRDCACHED_TRUE@LoadPlugin rrdcached
 @LOAD_PLUGIN_RRDTOOL@LoadPlugin rrdtool
@@ -133,10 +136,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
 
@@ -147,11 +152,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>
@@ -390,6 +411,12 @@ FQDNLookup   true
 #      InterfaceDevice "name:device"
 #      IgnoreSelected false
 #      HostnameFormat name
+#      InterfaceFormat name
+#</Plugin>
+
+#<Plugin lpar>
+#      CpuPoolStats   false
+#      ReportBySerial false
 #</Plugin>
 
 #<Plugin madwifi>
@@ -737,6 +764,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"
@@ -884,12 +919,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>
@@ -906,6 +963,14 @@ FQDNLookup   true
 #      </URL>
 #</Plugin>
 
+#<Plugin write_redis>
+#      <Node "example">
+#              Host "localhost"
+#              Port "6379"
+#              Timeout 1000
+#      </Node>
+#</Plugin>
+
 ##############################################################################
 # Filter configuration                                                       #
 #----------------------------------------------------------------------------#
index bfb7309575f85ad8322f7859b34a2b265ebf3625..c1c9a253c31a3ce7d53fdfef28726158735d314e 100644 (file)
@@ -159,13 +159,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>
 
@@ -190,6 +185,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
@@ -208,7 +340,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
 
@@ -216,7 +366,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>
 
@@ -1030,22 +1180,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
@@ -1365,13 +1499,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>
@@ -1599,6 +1726,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>
@@ -1617,8 +1754,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>
 
@@ -1635,6 +1772,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.
@@ -1860,7 +2024,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,
@@ -2630,7 +2794,7 @@ 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.
 
 =item B<Forward> I<true|false>
 
@@ -2641,16 +2805,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
@@ -3284,11 +3438,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
@@ -3364,21 +3513,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>
@@ -3393,13 +3527,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
@@ -3810,6 +3937,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)>,
@@ -4416,6 +4589,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>
@@ -4459,6 +4639,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.
@@ -4619,6 +4861,13 @@ information.
          WarningMin 100000000
        </Type>
      </Plugin>
+
+     <Type "load">
+       DataSource "midterm"
+       FailureMax 4
+       Hits 3
+       Hysteresis 3
+     </Type>
    </Host>
  </Threshold>
 
@@ -4691,6 +4940,27 @@ 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 arised before to
+dispatch any notification or, in other words, the number of B<Interval>s
+than 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 everthing 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 FILTER CONFIGURATION
index e7fc4e3554f4c0c0ea90403994af186e11d4cf56..8dd0f4263b55a1921ab5e105c354f37948226b20 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
@@ -294,8 +279,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..e1091cc
--- /dev/null
@@ -0,0 +1,591 @@
+/**
+ * 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
+
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <math.h>
+
+#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 (argv[i], (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 2598036ddff77d0c7aac985771658ce67c1bc788..1c80e8f1b8cd6d2f85dfebd482e30caf88cdf6d0 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>
@@ -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,36 @@ 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 (host));
+       sstrncpy (vl->plugin, plugin, sizeof (plugin));
+       sstrncpy (vl->plugin_instance, plugin_instance, sizeof (plugin_instance));
+       sstrncpy (vl->type, type, sizeof (type));
+       sstrncpy (vl->type_instance, type_instance, sizeof (type_instance));
+
+       return (0);
+} /* }}} int parse_identifier_vl */
+
 int parse_value (const char *value, value_t *ret_value, int ds_type)
 {
   char *endptr = NULL;
@@ -909,9 +1009,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 229f7098d6c8948ed69656f5dc30d3e69f47d705..425d6e2d6c5b74b729439be7be89b095b9e7c2d0 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);
 
index 0b7786f929605a311b4c8705a48e73a80ace68b4..e162dd995edf2efe69d37cf80616c1489f9d9717 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/configfile.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
@@ -96,7 +96,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"},
@@ -1014,11 +1014,37 @@ 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 */
 
+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. 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. */
@@ -1033,3 +1059,28 @@ int cf_util_get_port_number (const oconfig_item_t *ci) /* {{{ */
 
        return (service_name_to_port_number (ci->values[0].value.string));
 } /* }}} 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 432e09f5ba73f0663669dfe0f6bae7f65e154f48..65b1efcdd5a07d9a0d7fe7d50228470475bdb524 100644 (file)
@@ -2,7 +2,7 @@
 #define CONFIGFILE_H
 /**
  * collectd - src/configfile.h
- * Copyright (C) 2005,2006  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
@@ -23,6 +23,7 @@
  **/
 
 #include "collectd.h"
+#include "utils_time.h"
 #include "liboconfig/oconfig.h"
 
 /*
@@ -103,9 +104,16 @@ 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 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. 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 06055ca59372299616a6f8b1bf105d30e34760f4..c207318f9d62425fbfb18e7e86727bce62b65bcb 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 7aa6361bad3b7959f3dcba1a98ecd079fc48fc04..3dbe80eeb1b7f4727b491803e93e841cac09200a 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -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)
index 46e2301a1874f566098c15d54774fb1925b786de..4b8aa72143167864ff575147c5ef19949997ab50 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 96c1e3e7aba250179d6c950abbdb12f5fc7d7def..87a7b4e3a9d0a8cf82927d49913b947b699efe60 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 a533e147b1b6e2af1dcf00ff7634667b20bf4784..8b95c80febb279a1c6f2e0579787274bb113967f 100644 (file)
@@ -577,7 +577,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));
@@ -596,7 +595,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 0527dc8d772ef0cce5952aac2a60f11cbb62f209..433764e285014902dd7bbe7f53371ed2cf364a7b 100644 (file)
@@ -98,18 +98,12 @@ static size_t cj_curl_callback (void *buf, /* {{{ */
     return (0);
 
   status = yajl_parse(db->yajl, (unsigned char *)buf, len);
-  if (status == yajl_status_ok)
-  {
-    status = yajl_parse_complete(db->yajl);
-    return (len);
-  }
-  else if (status == yajl_status_insufficient_data)
-    return (len);
-
-  if (status != yajl_status_ok)
+  if ((status != yajl_status_ok)
+      && (status != yajl_status_insufficient_data))
   {
     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 */
@@ -769,9 +763,14 @@ static int cj_curl_perform (cj_t *db, CURL *curl) /* {{{ */
   }
 
   status = curl_easy_perform (curl);
-
-  yajl_free (db->yajl);
-  db->yajl = yprev;
+  if (status != 0)
+  {
+    ERROR ("curl_json plugin: curl_easy_perform failed with status %i: %s (%s)",
+           status, db->curl_errbuf, url);
+    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);
@@ -779,18 +778,30 @@ static int cj_curl_perform (cj_t *db, CURL *curl) /* {{{ */
   /* 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)
+  status = yajl_parse_complete (db->yajl);
+  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 77f393f5fc6a606c8151860617f4da4b9f62a0d3..caa41ef64023d247bd14721f936b0323df0ccfae 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 fc80ac3f08c27c659d4261427be91345c62238be..4b3cba019cea9219289cc8adef7633a05e30a9ba 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -60,9 +60,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)
 {
@@ -117,25 +116,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);
        }
@@ -144,28 +134,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,
@@ -213,6 +181,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)
@@ -271,39 +242,22 @@ 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 */
-                       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);
-               }
+               /* Sanity-check for the values in the struct */
+               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 f3280c0bed9f65ef37d3e8e554be640ca36ab83d..47da4e94c122e60dbd3084212e09e71cb3e5fbc1 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -80,14 +80,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);
 }
 
@@ -96,9 +92,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);
@@ -122,7 +115,6 @@ static counter_list_t *counter_list_create (counter_list_t **list,
                last->next = entry;
        }
 
-       DEBUG ("return (%p)", (void *) entry);
        return (entry);
 }
 
@@ -131,9 +123,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)
@@ -144,7 +133,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)
@@ -238,7 +226,7 @@ static void *dns_child_loop (void __attribute__((unused)) *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)
        {
@@ -261,7 +249,7 @@ static void *dns_child_loop (void __attribute__((unused)) *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);
@@ -274,7 +262,7 @@ static void *dns_child_loop (void __attribute__((unused)) *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;
@@ -375,7 +363,7 @@ static int dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DEBUG ("qtype = %u; counter = %u;", keys[i], values[i]);
+               DEBUG ("dns plugin: qtype = %u; counter = %u;", keys[i], values[i]);
                submit_counter ("dns_qtype", qtype_str (keys[i]), values[i]);
        }
 
@@ -391,7 +379,7 @@ static int dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DEBUG ("opcode = %u; counter = %u;", keys[i], values[i]);
+               DEBUG ("dns plugin: opcode = %u; counter = %u;", keys[i], values[i]);
                submit_counter ("dns_opcode", opcode_str (keys[i]), values[i]);
        }
 
@@ -407,7 +395,7 @@ static int dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DEBUG ("rcode = %u; counter = %u;", keys[i], values[i]);
+               DEBUG ("dns plugin: rcode = %u; counter = %u;", keys[i], values[i]);
                submit_counter ("dns_rcode", rcode_str (keys[i]), values[i]);
        }
 
index c64f949fc57b4ac5cff424a6b27e7cd283e13184..8d5ae9c3894932c6b21abbc1dc8bb952b84da870 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);
@@ -541,12 +542,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 }}} */
 
index 2ffc42a57d93aadf0b3d3bf080d6566c093592f4..8c774e536ff9c23e112c3e440d18aa15284478c4 100644 (file)
@@ -719,7 +719,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 4e083753202718c588f72b0b1a2c58dc3ef1f37c..4428b75ddc086db0be4e8cff39f95f6437e09e89 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 1ba6c8c32b73199823134d1662d89975065dc1d9..177afbaa0847b8f1db0dac2dd89bf6d6bf8bb19e 100644 (file)
@@ -171,8 +171,8 @@ static void if_submit (const char *dev, const char *type,
        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 */
index 95b3dbf5625fcd4c09aef04d2a880c5ca85d2ae8..f341320ddec54ed9135f6cec34759f30eb74ecd7 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 87eee108a79410853b6f02e107697b7a358f465a..f3a583b9d510edfbdae487d4aed2ab7ac2a91538 100644 (file)
@@ -235,8 +235,6 @@ static void cipvs_submit_connections (char *pi, char *ti, counter_t 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));
@@ -260,8 +258,6 @@ static void cipvs_submit_if (char *pi, char *t, char *ti,
        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 528ec9c475656140b4572bf30361c1c082fbd46b..3089a5337fdc4b21b5c592d06185789da8e72107 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:
@@ -2551,11 +2552,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;
@@ -2578,21 +2580,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 0c748ba7fa47e3b30f1d2a8d5c30dffdfd70d3e3..75ac7b6da0b96c1d901007ab8dd1f2d4c0470e06 100644 (file)
@@ -788,7 +788,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);
     }
index 11e7b13cc31575ee83d598a1f75984ae19b09e63..990035381c75d4198cf8fd6e1c202cb9891bf9ea 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 bcbf0e6ad51a5527df6b9a74a6a7322bd916881c..5d9d84b6fa1a124d79fda845b3d0fba8fbbba39e 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,113 @@ 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];
+    char  *host_ptr;
+    size_t host_len;
+
+    vl->interval = interval_g;
+
+    sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
+
+    vl->host[0] = '\0';
+    host_ptr = vl->host;
+    host_len = sizeof (vl->host);
+
+    /* 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].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,
+             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].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,
+             virDomainPtr dom, const char *devname)
+{
+    value_t values[2];
+    value_list_t vl = VALUE_LIST_INIT;
+
+    init_value_list (&vl, 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_init (void)
 {
@@ -215,7 +321,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 +334,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 +347,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;
 }
@@ -300,7 +418,7 @@ lv_read (void)
         if (virDomainGetInfo (domains[i], &info) != 0)
             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) {
@@ -310,15 +428,15 @@ lv_read (void)
 
         if (virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
                     NULL, 0) != 0) {
-            free (vinfo);
+            sfree (vinfo);
             continue;
         }
 
         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. */
@@ -332,17 +450,21 @@ lv_read (void)
         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);
+                    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);
+                    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,
@@ -352,22 +474,22 @@ lv_read (void)
        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);
+                   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);
+                   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);
+                   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);
+                   interface_devices[i].dom, display_name);
     } /* for (nr_interface_devices) */
 
     return 0;
@@ -398,7 +520,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;
         }
 
@@ -482,38 +604,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;
@@ -527,7 +665,7 @@ free_domains ()
     if (domains) {
         for (i = 0; i < nr_domains; ++i)
             virDomainFree (domains[i]);
-        free (domains);
+        sfree (domains);
     }
     domains = NULL;
     nr_domains = 0;
@@ -559,8 +697,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;
@@ -583,7 +721,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;
@@ -598,36 +736,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++;
 }
 
@@ -645,121 +790,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];
-    char  *host_ptr;
-    size_t host_len;
-
-    vl->time = t;
-    vl->interval = interval_g;
-
-    sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
-
-    vl->host[0] = '\0';
-    host_ptr = vl->host;
-    host_len = sizeof (vl->host);
-
-    /* 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 6d0f6e07826f2eb5391a64bc93db72e642948362..60fb5d9202ecfc5e5d9ddc2252820732e5586433 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 4ac944afe3dfb58f45b9df2ecea2e1300d5cadec..2e2741550c46e63882fd162d31caf8264cbfce21 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 d066501cdcba73afb56363dae167b9dd78353e10..8f51e22f01dd3c2d728d0cbc0a8e2cc61fba99e1 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 348591fd160b79c0f64308732698e79ec9ab4789..8b4a8fc1b9a2495fb966442ff96ffad386787f5a 100644 (file)
@@ -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
                        {
@@ -302,7 +304,6 @@ static void submit_counter2 (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));
@@ -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));
index adab0d0fe8e0756641a509b0c39b6373c44735b4..3824097c5a43b57e34c170eb4782ff756d8524a7 100644 (file)
@@ -94,7 +94,7 @@ 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;
@@ -771,7 +771,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);
@@ -797,21 +797,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 c7b796b18d79d5c92dcc34cacba287c4a0db26ea..1ca3b484ce6d2ebadc490196ed64260140c7d18c 100644 (file)
@@ -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)
        {
@@ -352,6 +208,28 @@ static int mysql_config (oconfig_item_t *ci) /* {{{ */
                return (-1);
        }
 
+       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 */
 
@@ -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)
@@ -473,33 +338,14 @@ 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)
 {
@@ -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))
@@ -709,16 +557,16 @@ static int mysql_read (user_data_t *ud)
        char      *query;
        int        field_num;
 
-       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;
@@ -778,15 +626,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)
@@ -800,13 +648,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)
@@ -818,16 +666,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 a4e03c6e67c3c7988f7e2a3295edf53b9cb0c0cb..5d100a69ca5f0eb23d5149a4f426becb6dfbd6b1 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;
 
@@ -595,7 +595,7 @@ static int submit_values (const char *host, /* {{{ */
 
 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)
+               cdtime_t timestamp, cdtime_t interval)
 {
        value_t values[2];
 
@@ -607,7 +607,8 @@ static int submit_two_counters (const char *host, const char *plugin_inst, /* {{
 } /* }}} int submit_two_counters */
 
 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)
+               const char *type, const char *type_inst, counter_t counter,
+               cdtime_t timestamp, cdtime_t interval)
 {
        value_t v;
 
@@ -619,7 +620,7 @@ static int submit_counter (const char *host, const char *plugin_inst, /* {{{ */
 
 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;
 
@@ -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);
 
@@ -1733,9 +1745,9 @@ static int cna_handle_system_data (const char *hostname, /* {{{ */
        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)
@@ -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")) {
@@ -2559,8 +2556,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 412b457bcf522028b8e8a9a82ed37697e86fbe58..7a1fcf7fd2bc9c3a6734a1e5ada0f2a68b5cef90 100644 (file)
@@ -259,7 +259,7 @@ 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;
+static size_t network_config_packet_size = 1452;
 static int network_config_forward = 0;
 static int network_config_stats = 0;
 
@@ -320,30 +320,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
@@ -384,7 +384,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.");
@@ -1381,8 +1381,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)
@@ -1391,7 +1402,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)
                {
@@ -2587,7 +2606,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;
@@ -2595,7 +2614,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;
@@ -3057,8 +3076,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.",
@@ -3079,8 +3096,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,13 +3278,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
        gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
@@ -3354,9 +3370,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 777616c4725cc75ddb13f9844e5c833aa81e7e35..1b354561ec7e8a2ab6e7a29cb1f6106445cca28f 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 697684277a153911fdc43474cdc74bdab5b62d1e..36d3d8d2bed85f9de5867f9f381f0102e85f51c0 100644 (file)
@@ -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);
 }
index 0aed27f12bb2ac8b41b5fa4e80d586e0c71f8bca..da6894a3db4dc8d0de24fbde2408ff03f194f47a 100644 (file)
@@ -230,6 +230,7 @@ static int notify_email_notification (const notification_t *n,
 {
   smtp_recipient_t recipient;
 
+  time_t tt;
   struct tm timestamp_tm;
   char timestamp_str[64];
 
@@ -249,7 +250,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 462458c73d626d097915501ce1c08221daa5245c..09a6bf0926154369c3fe75e408a3c79c9b194cfe 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 3fe21254ab33f08391ec7c45c6c26216ec074816..03567494f227cd281e41d528fbbee7fc67823620 100644 (file)
@@ -331,7 +331,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
@@ -586,7 +586,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 a2f5da299bf92ae9679d3fd69b478f691540e3e4..f8a482275d89bde294344222b060294cdaa8b3e6 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));
 
@@ -1993,7 +1999,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;
@@ -2095,19 +2101,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
@@ -2115,8 +2129,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
@@ -2158,12 +2172,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 af894d54724c804a0bed9ae512b74fd533f9a18d..e32c8f9c900faa3f7bd36b91296b3091287e05c2 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/plugin.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>
  *   Sebastian Harl <sh at tokkee.org>
  **/
 
@@ -74,6 +74,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;
@@ -336,7 +337,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;
@@ -347,10 +348,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,
@@ -361,15 +361,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,
@@ -459,7 +457,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.",
@@ -476,15 +474,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.",
@@ -842,6 +837,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 (char *name,
                int (*callback) (void))
 {
@@ -1028,6 +1030,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));
@@ -1251,7 +1258,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;
 
@@ -1296,7 +1303,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;
@@ -1326,6 +1334,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);
@@ -1333,6 +1342,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);
+    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;
@@ -1384,16 +1431,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);
@@ -1518,9 +1566,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)
@@ -1654,7 +1702,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:
@@ -1708,7 +1756,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 8b9449ee1dd64ec76436446bbbbaa9edd38a898b..bc873b08c939bc892982b944c62f9085f80f199a 100644 (file)
@@ -2,7 +2,7 @@
 #define PLUGIN_H
 /**
  * collectd - src/plugin.h
- * Copyright (C) 2005-2008  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
  * 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 *);
 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',
@@ -272,6 +277,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 (char *name,
                plugin_shutdown_cb callback);
 int plugin_register_data_set (const data_set_t *ds);
@@ -287,6 +294,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);
@@ -308,6 +316,7 @@ int plugin_unregister_notification (const char *name);
  *              function.
  */
 int plugin_dispatch_values (value_list_t *vl);
+int plugin_dispatch_missing (const value_list_t *vl);
 
 int plugin_dispatch_notification (const notification_t *notif);
 
@@ -340,7 +349,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 dd53cb4fd2b018fd11dd18a8d1c5788b7cc95a04..a8812e2158327bf86153689894e8eada7e620022 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 29f6bca502c7b48be0ecbadd2bc4befabf337885..a1b23555bec080592a261f91e1d6e02ae769bd6a 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 c056b5bf076ebee47b4490ff033a204dbf8f922e..eed0591d395aed66ba373d3b02b208e65912adf3 100644 (file)
@@ -435,8 +435,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);
@@ -465,7 +465,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 cc7e296c020e0a7df6706f432a374371caeb7219..36a717e9bfec401b54d8e2b629f110a01a303d7a 100644 (file)
@@ -91,7 +91,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);
        }
@@ -351,14 +351,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;
        const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
        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;
@@ -485,8 +484,7 @@ 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;
        const char *host = self->data.host;
        const char *plugin = self->data.plugin;
        const char *plugin_instance = self->data.plugin_instance;
@@ -495,7 +493,7 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
        
        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;
@@ -559,8 +557,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);
        sstrncpy(value_list.host, host, sizeof(value_list.host));
        sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
        sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
@@ -588,8 +586,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;
        const char *host = self->data.host;
        const char *plugin = self->data.plugin;
        const char *plugin_instance = self->data.plugin_instance;
@@ -599,7 +596,7 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
        
        static char *kwlist[] = {"destination", "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;
@@ -658,8 +655,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);
        sstrncpy(value_list.host, host, sizeof(value_list.host));
        sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
        sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
@@ -701,7 +698,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);
        }
@@ -864,7 +861,7 @@ static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObj
                return NULL;
        }
 
-       notification.time = t;
+       notification.time = DOUBLE_TO_CDTIME_T(t);
        notification.severity = severity;
        sstrncpy(notification.message, message, sizeof(notification.message));
        sstrncpy(notification.host, host, sizeof(notification.host));
@@ -873,8 +870,8 @@ static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObj
        sstrncpy(notification.type, type, sizeof(notification.type));
        sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
        notification.meta = 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..30bd8da
--- /dev/null
@@ -0,0 +1,311 @@
+/**
+ * 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>
+
+#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_c (char *plugin_instance,
+    const char *type, const char *type_instance,
+    counter_t value) /* {{{ */
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  values[0].counter = 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_c (rn->name, "total_connections", NULL, info.total_connections_received);
+    redis_submit_c (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 34e860ba6dc72ccff994e7dc999ca79682292c63..fb7eb79e8ec50eca5ab5d9273ff349d9fb5dd4cf 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 4655b96ee77c79a74dca16f9f412bd2df55d3cd7..b366a9c64166eeeae135f700b069e81578cac28a 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)
        {
@@ -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);
@@ -1134,12 +1167,12 @@ static int rrd_init (void)
                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 +1187,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)
index 1c2828c1fb2469494e84aafebb6a77d01fadcde9..54bcf67242170ea93c6cdc070a5a81a8196ed067 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;
 };
@@ -159,7 +159,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)
 {
@@ -543,22 +542,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;
@@ -607,7 +590,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);
@@ -651,9 +634,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,
@@ -1529,8 +1510,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;
@@ -1540,9 +1521,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);
@@ -1564,14 +1543,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 46ba6652953726ce0b7d90aecea2345f681ec64b..2025533eae298ee59048913eb4f69e2b466ad5ab 100644 (file)
@@ -76,8 +76,8 @@ static derive_t pagesize;
 static kstat_t *ksp;
 /* #endif HAVE_LIBKSTAT */
 
-#elif HAVE_SWAPCTL
-/* No global variables */
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
+static derive_t pagesize;
 /* #endif HAVE_SWAPCTL */
 
 #elif defined(VM_SWAPUSAGE)
@@ -115,8 +115,9 @@ static int swap_init (void)
                ksp = NULL;
 /* #endif HAVE_LIBKSTAT */
 
-#elif HAVE_SWAPCTL
-       /* No init stuff */
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
+       /* getpagesize(3C) tells me this does not fail.. */
+       pagesize = (derive_t) getpagesize ();
 /* #endif HAVE_SWAPCTL */
 
 #elif defined(VM_SWAPUSAGE)
@@ -338,6 +339,74 @@ static int swap_read (void)
 /* #endif HAVE_LIBKSTAT */
 
 #elif HAVE_SWAPCTL
+ #if HAVE_SWAPCTL_TWO_ARGS
+        swaptbl_t *s;
+        char strtab[255];
+        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);
+
+        s = (swaptbl_t *) smalloc (swap_num * sizeof (swapent_t) + sizeof (struct swaptable));
+        if (s == NULL)
+        {
+                ERROR ("swap plugin: smalloc failed.");
+                return (-1);
+        }
+        /* Initialize string pointers. We have them share the same buffer as we don't care
+        * about the device's name, only its size. This saves memory and alloc/free ops */
+        for (i = 0; i < (swap_num + 1); i++) {
+                s->swt_ent[i].ste_path = strtab;
+        }
+        s->swt_n = swap_num + 1;
+        status = swapctl (SC_LIST, s);
+        if (status != swap_num)
+        {
+                ERROR ("swap plugin: swapctl (SC_LIST) failed with status %i.",
+                                status);
+                sfree (s);
+                return (-1);
+        }
+
+        for (i = 0; i < swap_num; i++)
+        {
+                if ((s->swt_ent[i].ste_flags & ST_INDEL) != 0)
+                        continue;
+
+                avail += ((derive_t) s->swt_ent[i].ste_free)
+                         * pagesize;
+                total += ((derive_t) s->swt_ent[i].ste_pages)
+                         * pagesize;
+        }
+
+        if (total < avail)
+        {
+                ERROR ("swap plugin: Total swap space (%"PRIi64") "
+                                "is less than free swap space (%"PRIi64").",
+                                total, avail);
+                sfree (s);
+                return (-1);
+        }
+
+        swap_submit ("used", total - avail, DS_TYPE_GAUGE);
+        swap_submit ("free", avail, DS_TYPE_GAUGE);
+
+        sfree (s);
+ /* #endif HAVE_SWAPCTL_TWO_ARGS */
+ #elif HAVE_SWAPCTL_THREE_ARGS
+
        struct swapent *swap_entries;
        int swap_num;
        int status;
@@ -346,18 +415,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,6 +470,7 @@ static int swap_read (void)
        swap_submit ("free", total - used, DS_TYPE_GAUGE);
 
        sfree (swap_entries);
+ #endif /* HAVE_SWAPCTL_THREE_ARGS */
 /* #endif HAVE_SWAPCTL */
 
 #elif defined(VM_SWAPUSAGE)
index 96598afd76fd53500948e34dda8bf516726e4371..cb68048b6a8f7c042cdd37bbf7dc3c77a24bd754 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 29fecdfd7b5818479437659982226c993934a63d..af224f109d6bb8de19066b8c472a6557d6058d3e 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 8dc00e5a161ad928883b086d100a451e48d1db6f..bf519bbee53ec38c34ddae669c707523e2fbf617 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 b9d07bf5ce22fcacd55f5dcac729e4ad665b12d5..0ad0d90a04377126132e35cad77e4d592a844a1d 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;
 }
 
index ad542402952f33c23c1419866114520ae1971e21..0484983294ba523ff5b167c2c6f78e87c59dab7d 100644 (file)
@@ -13,8 +13,9 @@ ath_nodes             value:GAUGE:0:65535
 ath_stat               value:COUNTER:0:4294967295
 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
@@ -26,6 +27,8 @@ counter                       value:COUNTER:U:U
 cpufreq                        value:GAUGE:0:U
 cpu                    value:COUNTER:0:4294967295
 current                        value:GAUGE:U:U
+current_connections    value:GAUGE:0:U
+current_sessions       value:GAUGE:0:U
 delay                  seconds:GAUGE:-1000000:1000000
 derive                 value:DERIVE:0:U
 df                     used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
@@ -98,8 +101,6 @@ 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
 nginx_connections      value:GAUGE:0:U
 nginx_requests         value:COUNTER:0:134217728
@@ -134,8 +135,9 @@ ps_stacksize                value:GAUGE:0:9223372036854775807
 ps_state               value:GAUGE:0:65535
 ps_vm                  value:GAUGE:0:9223372036854775807
 queue_length           value:GAUGE:0:U
-response_time          value:GAUGE:0:U
 records                        count:GAUGE:0:U
+requests               value:GAUGE:0:U
+response_time          value:GAUGE:0:U
 route_etx              value:GAUGE:0:U
 route_metric           value:GAUGE:0:U
 routes                 value:GAUGE:0:U
@@ -155,17 +157,23 @@ time_dispersion           seconds:GAUGE:-1000000:1000000
 timeleft               timeleft:GAUGE:0:3600
 time_offset            seconds: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
+vcpu                   value:GAUGE:0:U
 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
 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
index 0b897482c9d956547d74be3f905f9d9941b157be..6de1395662161a66aaacafa389efa1e680583bf9 100644 (file)
@@ -54,7 +54,8 @@ static const char *config_keys[] =
 {
        "SocketFile",
        "SocketGroup",
-       "SocketPerms"
+       "SocketPerms",
+       "DeleteSocket"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
@@ -65,6 +66,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 +91,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)
        {
@@ -392,6 +411,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 aeb662d55bc09e63c18ae856ac182aa04fc6b369..7e1dcf758af50785e0cb5551989a91e2c38373ec 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"
@@ -38,13 +38,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,6 +120,7 @@ static void cache_free (cache_entry_t *ce)
   sfree (ce);
 } /* void cache_free */
 
+__attribute__((unused))
 static int uc_send_notification (const char *name)
 {
   cache_entry_t *ce = NULL;
@@ -164,7 +165,7 @@ static int uc_send_notification (const char *name)
    * acquiring the lock takes and we will use this time later to decide
    * whether or not the state is OKAY.
    */
-  n.time = time (NULL);
+  n.time = cdtime ();
 
   status = c_avl_get (cache_tree, name, (void *) &ce);
   if (status != 0)
@@ -184,8 +185,8 @@ static int uc_send_notification (const char *name)
   }
 
   ssnprintf (n.message, sizeof (n.message),
-      "%s has not been updated for %i seconds.", name,
-      (int) (n.time - ce->last_update));
+      "%s has not been updated for %.3f seconds.", name,
+      CDTIME_T_TO_DOUBLE (n.time - ce->last_update));
 
   pthread_mutex_unlock (&cache_lock);
 
@@ -258,7 +259,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 +275,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 +301,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) */
+    char **tmp;
+    cdtime_t *tmp_time;
 
-  ce = NULL;
-
-  for (i = 0; i < keys_len; i++)
-  {
-    int status;
-
-    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 */
+    keys[keys_len] = strdup (key);
+    if (keys[keys_len] == NULL)
     {
-      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
-    {
-      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++)
+  {
+    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++)
   {
-    if (keys[i] == NULL)
+    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 */
@@ -448,7 +437,7 @@ 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;
+  cdtime_t update_delay = 0;
   notification_t n;
   int status;
   int i;
@@ -475,9 +464,11 @@ 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);
   }
 
@@ -487,7 +478,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
   {
     send_okay_notification = 1;
     ce->state = STATE_OKAY;
-    update_delay = time (NULL) - ce->last_update;
+    update_delay = cdtime () - ce->last_update;
   }
 
   for (i = 0; i < ds->ds_num; i++)
@@ -514,7 +505,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 +522,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,7 +562,7 @@ 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);
@@ -682,14 +673,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 +701,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 f8059ecaf077dda6924122e3dc6452b4babfb282..87f93c0ed378ca0bcefed6f89cdcbd72053291f9 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 0e7b350f581f02f07ccaf234c1ec0c225011b33d..3584f3b71a3c82bd73ec85cd55201422f8a8e1f8 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 4ca9646de8155a71b1a2b076cabf9b74ef5de002..ef66af56c408d8ae1ab300386875c7d57fe93189 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 ec2b5f876795b53f2faec5c5ddc6104d7c0679a3..dd43337ee01390eb3c703a5d8c473bc93eb7ea90 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 8460b13388488be5c1401a3ff23a57a3d6e4f4bb..9c92fd31c0caf6a0524ef595c60d3158051b73aa 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 7d594d812a4e0bf2f0f1b9c3e936ec762f917e5a..dcac80764c665ca1dd98a456feea0cb2386692c4 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;
 }; /* }}} */
@@ -190,173 +179,6 @@ static int udb_config_set_uint (unsigned int *ret_value, /* {{{ */
   return (0);
 } /* }}} int udb_config_set_uint */
 
-/*
- * Legacy result private functions
- */
-static void udb_legacy_result_finish_result (const 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,
-    const 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.type_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 (const 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
  */
@@ -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 (const 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 (const 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 (const 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 (const udb_query_t const *q, /* {{{ */
 int udb_query_prepare_result (const 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 fa2b2885679c435245b836f4cbc4ccb01556c5db..727be03647714e8bc76f6b4d5403508eeca74616 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 (const 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 (const udb_query_t const *q,
     udb_query_preparation_area_t *prep_area, char **column_values);
 void udb_query_finish_result (const udb_query_t const *q,
index 2348be24db05d55c5b1d6b6ad000ce8108594701..22c9b95994377f9ed1752d4192eb25c29a97b8e8 100644 (file)
@@ -291,13 +291,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 +310,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 +334,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 +358,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 +392,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')))
@@ -647,10 +664,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;
 
@@ -684,7 +697,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 efc790319cebea5e3253cad748de71d4e8923aaa..56213afa18bc800035fafa88b149120edf266b4f 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 ac88c0fa27c4f7ae4b50cd734d78f886a79482b3..65c886b6fc28239183be31d8a10a896ec5f7800c 100644 (file)
@@ -265,7 +265,7 @@ static int value_list_to_json (char *buffer, size_t buffer_size, /* {{{ */
   BUFFER_ADD (",\"dsnames\":%s", temp);
 
   BUFFER_ADD (",\"time\":%lu", (unsigned long) vl->time);
-  BUFFER_ADD (",\"interval\":%i", vl->interval);
+  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 66bb27e75dacf6ad6bce7f7f659cfd9e59bd211e..ce6443b7e5a47300e72fae2b2bb81d729ac3db41 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;
+  int stepsize;
 
   if (check_create_dir (filename))
     return (-1);
@@ -398,9 +405,19 @@ int cu_rrd_create_file (const char *filename, /* {{{ */
   memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
   argv[ds_num + rra_num] = NULL;
 
+  last_up = CDTIME_T_TO_TIME_T (vl->time);
+  if (last_up <= 10)
+    last_up = time (NULL);
+  last_up -= 10;
+
+  if (cfg->stepsize > 0)
+    stepsize = cfg->stepsize;
+  else
+    stepsize = (int) CDTIME_T_TO_TIME_T (vl->interval);
+
   status = srrd_create (filename,
       (cfg->stepsize > 0) ? cfg->stepsize : vl->interval,
-      (vl->time > 10) ? (vl->time - 10) : vl->time,
+      last_up,
       argc, (const char **) argv);
 
   free (argv);
index 090cc75206f9c47acdde32dc5c6821bca67201aa..99309b93b58b46ec84512cad69b087deba146a19 100644 (file)
@@ -40,6 +40,7 @@
 #define UT_FLAG_INVERT  0x01
 #define UT_FLAG_PERSIST 0x02
 #define UT_FLAG_PERCENTAGE 0x04
+#define UT_FLAG_INTERESTING 0x08
 /* }}} */
 
 /*
@@ -217,60 +218,6 @@ static int ut_config_type_min (threshold_t *th, oconfig_item_t *ci)
   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)
@@ -330,6 +277,7 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
   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++)
   {
@@ -346,12 +294,14 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
     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 = ut_config_type_invert (&th, option);
+      status = cf_util_get_flag (option, &th.flags, UT_FLAG_INVERT);
     else if (strcasecmp ("Persist", option->key) == 0)
-      status = ut_config_type_persist (&th, option);
+      status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERSIST);
     else if (strcasecmp ("Percentage", option->key) == 0)
-      status = ut_config_type_percentage (&th, option);
+      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)
@@ -517,6 +467,7 @@ int ut_config (const oconfig_item_t *ci)
 
   th.hits = 0;
   th.hysteresis = 0;
+  th.flags = UT_FLAG_INTERESTING; /* interesting by default */
     
   for (i = 0; i < ci->children_num; i++)
   {
@@ -1028,6 +979,10 @@ int ut_check_interesting (const char *name)
   th = threshold_search (&vl);
   if (th == NULL)
     return (0);
+
+  if ((th->flags & UT_FLAG_INTERESTING) == 0)
+    return (0);
+
   if ((th->flags & UT_FLAG_PERSIST) == 0)
     return (1);
   return (2);
index 8aaf34c61af0175c18d3fa9f4ae3897d8b998e15..5955ca6ed79db1a124c33a46ea56e0f1e53e4860 100644 (file)
@@ -39,7 +39,7 @@ typedef struct threshold_s
   gauge_t failure_min;
   gauge_t failure_max;
   gauge_t hysteresis;
-  int flags;
+  unsigned int flags;
   int hits;
   struct threshold_s *next;
 } threshold_t;
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..6bf2db7
--- /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_gauge (conf->instance,  "sm", "bytes", "allocated",      VSL_stats->sm_balloc);
+               /* bytes free */
+               varnish_submit_gauge (conf->instance,  "sm", "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_gauge (conf->instance,  "sma", "bytes", "allocated",      VSL_stats->sma_balloc);
+               /* SMA bytes free */
+               varnish_submit_gauge (conf->instance,  "sma", "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_gauge (conf->instance,  "sms", "bytes", "allocated",          VSL_stats->sms_balloc);
+               /* SMS bytes freed */
+               varnish_submit_gauge (conf->instance,  "sms", "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_gauge (conf->instance, "workers", "total_threads", "created",     VSL_stats->n_wrk_create);
+               /* worker threads not created */
+               varnish_submit_gauge (conf->instance, "workers", "total_threads", "failed",      VSL_stats->n_wrk_failed);
+               /* worker threads limited */
+               varnish_submit_gauge (conf->instance, "workers", "total_threads", "limited",     VSL_stats->n_wrk_max);
+               /* queued work requests */
+               varnish_submit_gauge (conf->instance, "workers", "total_requests", "queued",     VSL_stats->n_wrk_queue);
+               /* overflowed work requests */
+               varnish_submit_gauge (conf->instance, "workers", "total_requests", "overflowed", VSL_stats->n_wrk_overflow);
+               /* dropped work requests */
+               varnish_submit_gauge (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 ab8757ed67f151875bc806279425f3c86d971c87..1a0e4ef06d2fa13dc91cdb7faf315e6874e1d609 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)
         {
@@ -157,19 +157,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);
         }
@@ -178,7 +180,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);
                 }
 
@@ -189,7 +191,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);
                 }
 
@@ -218,7 +220,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)
 {
@@ -258,7 +260,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);
@@ -270,76 +272,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)
 {
@@ -366,7 +298,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");
@@ -374,8 +306,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);
@@ -397,7 +331,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);
@@ -449,7 +383,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 5f14e90981adda089fb2b94cd85b5094a4e451b2..bc2b0d2b4e6eab185d5d2687ceee80819d6b5aff 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, arc_ratio, l2_hits, l2_misses, l2_ratio;
+       value_t  l2_io[2];
 
        get_kstat (&ksp, "zfs", 0, "arcstats");
        if (ksp == NULL)
@@ -102,11 +96,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");
@@ -117,31 +114,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) /* {{{ */
 {