Merge branch 'collectd-5.4'
authorFlorian Forster <octo@collectd.org>
Mon, 18 Aug 2014 07:50:34 +0000 (09:50 +0200)
committerFlorian Forster <octo@collectd.org>
Mon, 18 Aug 2014 07:50:34 +0000 (09:50 +0200)
Conflicts:
configure.ac
src/curl_json.c
src/lvm.c
src/write_riemann.c

27 files changed:
ChangeLog
configure.ac
contrib/collection3/etc/collection.conf
contrib/redhat/collectd.spec
src/Makefile.am
src/aggregation.c
src/amqp.c
src/apache.c
src/collectd-unixsock.pod
src/collectd.conf.in
src/collectd.conf.pod
src/common.c
src/configfile.c
src/curl.c
src/curl_json.c
src/curl_xml.c
src/exec.c
src/lvm.c
src/network.c
src/processes.c
src/pyvalues.c
src/snmp.c
src/tcpconns.c
src/utils_vl_lookup.c
src/write_http.c
src/write_riemann.c
version-gen.sh

index 8cd1579..8112afa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2014-01-26, Version 5.4.1
+       * amqp plugin: Add support for RabbitMQ 0.4.x to avoid compiler
+         warnings. Thanks to Sebastian Harl for implementing this.
+       * apache / network plugins: Improved initialization order hopefully
+         resolved gcrypt initialization problems.
+       * aquaero plugin: The type used to submit fan utilization was fixed.
+         Thanks to Alex Deymo for the patch.
+       * cgroups plugin: A small memory leak was fixed. Checking the existence
+         of a mount option without a value was fixed. More permissive parsing
+         of the cpuacct.stats file fixes support for some versions of Linux.
+         Thanks to Marc Fournier for bug reports and patches.
+       * curl plugin: Fix <Match> blocks without an instance. Thanks to
+         Alexander Golovko for reporting and Sebastian Harl for fixing this.
+       * curl_json plugin: Potentially invalid memory access has been
+         sanitized. Thanks to Jim Radford for his patch.
+       * interface plugin: Fix behavior under FreeBSD 10: Reporting of
+         per-address statistics caused duplicate updates to the same metric.
+         Thanks to demon / @trtrmitya for the patch.
+       * write_graphite plugin: Use TCP to connect to Graphite by default. The
+         default changed from TCP to UDP between 5.3.1 and 5.4.0, which is a
+         regression. Thanks to Marc Fournier for fixing this. Reconnect
+         behavior was improved. Thanks to Michael Hart for his patch.
+       * zfs_arc plugin: Collect "allocated" and "stolen" on FreeBSD only.
+
 2013-08-18, Version 5.4.0
        * collectd: The "LoadPlugin" config option no longer attempts to load
          plugins twice. If more than one "LoadPlugin" statement or block is
index 92fd877..0df5678 100644 (file)
@@ -404,6 +404,18 @@ AC_CHECK_HEADERS(linux/if.h, [], [],
 #  include <sys/socket.h>
 #endif
 ])
+AC_CHECK_HEADERS(linux/inet_diag.h, [], [],
+[
+#if HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+#if HAVE_LINUX_INET_DIAG_H
+# include <linux/inet_diag.h>
+#endif
+])
 AC_CHECK_HEADERS(linux/netdevice.h, [], [],
 [
 #if HAVE_SYS_TYPES_H
@@ -1218,10 +1230,9 @@ if test "x$have_getmntent" = "xgen"; then
 fi
 
 # Check for htonll
-AC_MSG_CHECKING([if have htonll defined])
-
-    have_htonll="no"
-    AC_LINK_IFELSE([AC_LANG_PROGRAM(
+AC_CACHE_CHECK([if have htonll defined],
+                  [c_cv_have_htonll],
+                  AC_LINK_IFELSE([AC_LANG_PROGRAM(
 [[[
 #include <sys/types.h>
 #include <netinet/in.h>
@@ -1233,12 +1244,14 @@ AC_MSG_CHECKING([if have htonll defined])
           return htonll(0);
 ]]]
     )],
-    [
-      have_htonll="yes"
-      AC_DEFINE(HAVE_HTONLL, 1, [Define if the function htonll exists.])
-    ])
-
-AC_MSG_RESULT([$have_htonll])
+    [c_cv_have_htonll="yes"],
+    [c_cv_have_htonll="no"]
+  )
+)
+if test "x$c_cv_have_htonll" = "xyes"
+then
+    AC_DEFINE(HAVE_HTONLL, 1, [Define if the function htonll exists.])
+fi
 
 # Check for structures
 AC_CHECK_MEMBERS([struct if_data.ifi_ibytes, struct if_data.ifi_opackets, struct if_data.ifi_ierrors],
@@ -1258,6 +1271,13 @@ AC_CHECK_MEMBERS([struct net_device_stats.rx_bytes, struct net_device_stats.tx_p
        #include <linux/if.h>
        #include <linux/netdevice.h>
        ])
+AC_CHECK_MEMBERS([struct inet_diag_req.id, struct inet_diag_req.idiag_states],
+       [AC_DEFINE(HAVE_STRUCT_LINUX_INET_DIAG_REQ, 1, [Define if struct inet_diag_req exists and is usable.])],
+       [],
+       [
+       #include <linux/inet_diag.h>
+       ])
+
 
 AC_CHECK_MEMBERS([struct ip_mreqn.imr_ifindex], [],
        [],
@@ -1368,8 +1388,8 @@ AC_CHECK_LIB(hal,libhal_device_property_exists,
             [with_libhal="no"])
 if test "x$with_libhal" = "xyes"; then
        if test "x$PKG_CONFIG" != "x"; then
-               BUILD_WITH_LIBHAL_CFLAGS="`pkg-config --cflags hal`"
-               BUILD_WITH_LIBHAL_LIBS="`pkg-config --libs hal`"
+               BUILD_WITH_LIBHAL_CFLAGS="`$PKG_CONFIG --cflags hal`"
+               BUILD_WITH_LIBHAL_LIBS="`$PKG_CONFIG --libs hal`"
                AC_SUBST(BUILD_WITH_LIBHAL_CFLAGS)
                AC_SUBST(BUILD_WITH_LIBHAL_LIBS)
        fi
@@ -3576,6 +3596,41 @@ fi
 CPPFLAGS="$SAVE_CPPFLAGS"
 LDFLAGS="$SAVE_LDFLAGS"
 AM_CONDITIONAL(BUILD_WITH_LIBRABBITMQ, test "x$with_librabbitmq" = "xyes")
+
+with_amqp_tcp_socket="no"
+if test "x$with_librabbitmq" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       SAVE_LDFLAGS="$LDFLAGS"
+       SAVE_LIBS="$LIBS"
+       CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
+       LDFLAGS="$LDFLAGS $with_librabbitmq_ldflags"
+       LIBS="-lrabbitmq"
+
+       AC_CHECK_HEADERS(amqp_tcp_socket.h amqp_socket.h)
+       AC_CHECK_FUNC(amqp_tcp_socket_new, [with_amqp_tcp_socket="yes"], [with_amqp_tcp_socket="no"])
+       if test "x$with_amqp_tcp_socket" = "xyes"
+       then
+               AC_DEFINE(HAVE_AMQP_TCP_SOCKET, 1,
+                               [Define if librabbitmq provides the new TCP socket interface.])
+       fi
+
+       AC_CHECK_DECLS(amqp_socket_close,
+                               [amqp_socket_close_decl="yes"], [amqp_socket_close_decl="no"],
+                               [[
+#include <amqp.h>
+#ifdef HAVE_AMQP_TCP_SOCKET_H
+# include <amqp_tcp_socket.h>
+#endif
+#ifdef HAVE_AMQP_SOCKET_H
+# include <amqp_socket.h>
+#endif
+                               ]])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+       LDFLAGS="$SAVE_LDFLAGS"
+       LIBS="$SAVE_LIBS"
+fi
 # }}}
 
 # --with-librdkafka {{{
@@ -3844,18 +3899,20 @@ AC_ARG_WITH(libsigrok, [AS_HELP_STRING([--with-libsigrok@<:@=PREFIX@:>@], [Path
                        with_libsigrok_ldflags="-L$withval/lib"
                fi
        fi
-],[])
+],[with_libsigrok="yes"])
 
 # libsigrok has a glib dependency
 if test "x$with_libsigrok" = "xyes"
 then
-       if test -z "m4_ifdef([AM_PATH_GLIB_2_0], [yes], [])"
-       then
-               with_libsigrok="no (glib not available)"
-       else
-               AM_PATH_GLIB_2_0([2.28.0],
-                       [with_libsigrok_cflags="$with_libsigrok_cflags $GLIB_CFLAGS"; with_libsigrok_ldflags="$with_libsigrok_ldflags $GLIB_LIBS"])
-       fi
+m4_ifdef([AM_PATH_GLIB_2_0],
+       [
+        AM_PATH_GLIB_2_0([2.28.0],
+               [with_libsigrok_cflags="$with_libsigrok_cflags $GLIB_CFLAGS"; with_libsigrok_ldflags="$with_libsigrok_ldflags $GLIB_LIBS"])
+       ],
+       [
+        with_libsigrok="no (glib not available)"
+       ]
+)
 fi
 
 # libsigrok headers
@@ -4039,8 +4096,8 @@ then
   if $PKG_CONFIG --exists tokyotyrant
   then
     with_libtokyotyrant_cppflags="$with_libtokyotyrant_cppflags `$PKG_CONFIG --cflags tokyotyrant`"
-    with_libtokyotyrant_ldflags="$with_libtokyotyrant_ldflags `pkg-config --libs-only-L tokyotyrant`"
-    with_libtokyotyrant_libs="$with_libtokyotyrant_libs `pkg-config --libs-only-l tokyotyrant`"
+    with_libtokyotyrant_ldflags="$with_libtokyotyrant_ldflags `$PKG_CONFIG --libs-only-L tokyotyrant`"
+    with_libtokyotyrant_libs="$with_libtokyotyrant_libs `$PKG_CONFIG --libs-only-l tokyotyrant`"
   fi
 fi
 
@@ -4557,7 +4614,7 @@ with_libvirt_cflags=""
 with_libvirt_ldflags=""
 if test "x$PKG_CONFIG" != "x"
 then
-       pkg-config --exists 'libxml-2.0' 2>/dev/null
+       $PKG_CONFIG --exists 'libxml-2.0' 2>/dev/null
        if test "$?" = "0"
        then
                with_libxml2="yes"
@@ -4565,7 +4622,7 @@ then
                with_libxml2="no (pkg-config doesn't know libxml-2.0)"
        fi
 
-       pkg-config --exists libvirt 2>/dev/null
+       $PKG_CONFIG --exists libvirt 2>/dev/null
        if test "$?" = "0"
        then
                with_libvirt="yes"
@@ -4575,12 +4632,12 @@ then
 fi
 if test "x$with_libxml2" = "xyes"
 then
-       with_libxml2_cflags="`pkg-config --cflags libxml-2.0`"
+       with_libxml2_cflags="`$PKG_CONFIG --cflags libxml-2.0`"
        if test $? -ne 0
        then
                with_libxml2="no"
        fi
-       with_libxml2_ldflags="`pkg-config --libs libxml-2.0`"
+       with_libxml2_ldflags="`$PKG_CONFIG --libs libxml-2.0`"
        if test $? -ne 0
        then
                with_libxml2="no"
@@ -4620,12 +4677,12 @@ if test "x$with_libxml2" = "xyes"; then
 fi
 if test "x$with_libvirt" = "xyes"
 then
-       with_libvirt_cflags="`pkg-config --cflags libvirt`"
+       with_libvirt_cflags="`$PKG_CONFIG --cflags libvirt`"
        if test $? -ne 0
        then
                with_libvirt="no"
        fi
-       with_libvirt_ldflags="`pkg-config --libs libvirt`"
+       with_libvirt_ldflags="`$PKG_CONFIG --libs libvirt`"
        if test $? -ne 0
        then
                with_libvirt="no"
index 5fe4313..3e19bfc 100644 (file)
@@ -7,7 +7,7 @@ GraphWidth 400
   RRDTitle "Apache Traffic"
   RRDVerticalLabel "Bytes/s"
   RRDFormat "%5.1lf%s"
-  Color count 0000ff
+  Color value 0000ff
 </Type>
 <Type apache_requests>
   DataSources value
@@ -15,7 +15,7 @@ GraphWidth 400
   RRDTitle "Apache Traffic"
   RRDVerticalLabel "Requests/s"
   RRDFormat "%5.2lf"
-  Color count 00d000
+  Color value 00d000
 </Type>
 <Type apache_scoreboard>
   Module GenericStacked
@@ -272,7 +272,7 @@ GraphWidth 400
   RRDTitle "Frequency ({type_instance})"
   RRDVerticalLabel "Hertz"
   RRDFormat "%4.1lfHz"
-  Color frequency a000a0
+  Color value a000a0
 </Type>
 <Type humidity>
   DataSources value
@@ -547,7 +547,7 @@ GraphWidth 400
   RRDTitle "Percent ({type_instance})"
   RRDVerticalLabel "Percent"
   RRDFormat "%4.1lf%%"
-  Color percent 0000ff
+  Color value 0000ff
 </Type>
 <Type ping>
   DataSources value
@@ -705,7 +705,7 @@ GraphWidth 400
   RRDTitle "Users ({type_instance}) on {hostname}"
   RRDVerticalLabel "Users"
   RRDFormat "%.1lf"
-  Color users 0000f0
+  Color value 0000f0
 </Type>
 <Type voltage>
   DataSources value
index 6af91e8..9facca8 100644 (file)
@@ -45,6 +45,7 @@
 %{?el6:%global _has_ip_vs_h 1}
 %{?el6:%global _has_lvm2app_h 1}
 %{?el6:%global _has_perl_extutils_embed 1}
+%{?el6:%global _has_libmodbus 1}
 
 # plugins enabled by default
 %define with_aggregation 0%{!?_without_aggregation:1}
@@ -92,6 +93,7 @@
 %define with_memcached 0%{!?_without_memcached:1}
 %define with_memory 0%{!?_without_memory:1}
 %define with_multimeter 0%{!?_without_multimeter:1}
+%define with_modbus 0%{!?_without_modbus:0%{?_has_libmodbus}}
 %define with_mysql 0%{!?_without_mysql:1}
 %define with_netlink 0%{!?_without_netlink:1}
 %define with_network 0%{!?_without_network:1}
@@ -422,6 +424,16 @@ The mic plugin collects CPU usage, memory usage, temperatures and power
 consumption from Intel Many Integrated Core (MIC) CPUs.
 %endif
 
+%if %{with_modbus}
+%package modbus
+Summary:       modbus plugin for collectd
+Group:         System Environment/Daemons
+Requires:      %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: libmodbus-devel
+%description modbus
+The modbus plugin collects values from Modbus/TCP enabled devices
+%endif
+
 %if %{with_mysql}
 %package mysql
 Summary:       MySQL plugin for collectd
@@ -997,6 +1009,12 @@ Development files for libcollectdclient
 %define _with_multimeter --disable-multimeter
 %endif
 
+%if %{with_modbus}
+%define _with_modbus --enable-modbus
+%else
+%define _with_modbus --disable-modbus
+%endif
+
 %if %{with_mysql}
 %define _with_mysql --enable-mysql
 %else
@@ -2013,6 +2031,9 @@ fi
 - Enable cgroups, lvm and statsd plugins
 - Enable (but don't build by default) mic, aquaero and sigrok plugins
 
+* Wed Aug 06 2014 Marc Fournier <marc.fournier@camptocamp.com> 5.3.1-2
+- Enabled modbus plugin
+
 * Tue Aug 06 2013 Marc Fournier <marc.fournier@camptocamp.com> 5.3.1-1
 - New upstream version
 - Added RHEL5 support:
index d25370a..d727566 100644 (file)
@@ -520,8 +520,8 @@ if BUILD_PLUGIN_IPTABLES
 pkglib_LTLIBRARIES += iptables.la
 iptables_la_SOURCES = iptables.c
 iptables_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBIPTC_CPPFLAGS)
-iptables_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBIPTC_LDFLAGS)
-iptables_la_LIBADD = -liptc
+iptables_la_LDFLAGS = -module -avoid-version
+iptables_la_LIBADD = $(BUILD_WITH_LIBIPTC_LDFLAGS)
 collectd_LDADD += "-dlopen" iptables.la
 collectd_DEPENDENCIES += iptables.la
 endif
index 0c0f19d..8175c66 100644 (file)
@@ -440,8 +440,7 @@ static int agg_instance_read (agg_instance_t *inst, cdtime_t t) /* {{{ */
 
 /* lookup_class_callback_t for utils_vl_lookup */
 static void *agg_lookup_class_callback ( /* {{{ */
-    __attribute__((unused)) data_set_t const *ds,
-    value_list_t const *vl, void *user_class)
+    data_set_t const *ds, value_list_t const *vl, void *user_class)
 {
   return (agg_instance_create (ds, vl, (aggregation_t *) user_class));
 } /* }}} void *agg_class_callback */
index 56718f0..1764129 100644 (file)
 #include <amqp.h>
 #include <amqp_framing.h>
 
+#ifdef HAVE_AMQP_TCP_SOCKET_H
+# include <amqp_tcp_socket.h>
+#endif
+#ifdef HAVE_AMQP_SOCKET_H
+# include <amqp_socket.h>
+#endif
+#ifdef HAVE_AMQP_TCP_SOCKET
+#if defined HAVE_DECL_AMQP_SOCKET_CLOSE && !HAVE_DECL_AMQP_SOCKET_CLOSE
+/* rabbitmq-c does not currently ship amqp_socket.h
+ * and, thus, does not define this function. */
+int amqp_socket_close(amqp_socket_t *);
+#endif
+#endif
+
 /* Defines for the delivery mode. I have no idea why they're not defined by the
  * library.. */
 #define CAMQP_DM_VOLATILE   1
@@ -392,8 +406,12 @@ static int camqp_setup_queue (camqp_config_t *conf) /* {{{ */
 static int camqp_connect (camqp_config_t *conf) /* {{{ */
 {
     amqp_rpc_reply_t reply;
-    int sockfd;
     int status;
+#ifdef HAVE_AMQP_TCP_SOCKET
+    amqp_socket_t *socket;
+#else
+    int sockfd;
+#endif
 
     if (conf->connection != NULL)
         return (0);
@@ -405,6 +423,33 @@ static int camqp_connect (camqp_config_t *conf) /* {{{ */
         return (ENOMEM);
     }
 
+#ifdef HAVE_AMQP_TCP_SOCKET
+# define CLOSE_SOCKET() /* amqp_destroy_connection() closes the socket for us */
+    /* TODO: add support for SSL using amqp_ssl_socket_new
+     *       and related functions */
+    socket = amqp_tcp_socket_new (conf->connection);
+    if (! socket)
+    {
+        ERROR ("amqp plugin: amqp_tcp_socket_new failed.");
+        amqp_destroy_connection (conf->connection);
+        conf->connection = NULL;
+        return (ENOMEM);
+    }
+
+    status = amqp_socket_open (socket, CONF(conf, host), conf->port);
+    if (status < 0)
+    {
+        char errbuf[1024];
+        status *= -1;
+        ERROR ("amqp plugin: amqp_socket_open failed: %s",
+                sstrerror (status, errbuf, sizeof (errbuf)));
+        amqp_destroy_connection (conf->connection);
+        conf->connection = NULL;
+        return (status);
+    }
+#else /* HAVE_AMQP_TCP_SOCKET */
+# define CLOSE_SOCKET() close(sockfd)
+    /* this interface is deprecated as of rabbitmq-c 0.4 */
     sockfd = amqp_open_socket (CONF(conf, host), conf->port);
     if (sockfd < 0)
     {
@@ -417,6 +462,7 @@ static int camqp_connect (camqp_config_t *conf) /* {{{ */
         return (status);
     }
     amqp_set_sockfd (conf->connection, sockfd);
+#endif
 
     reply = amqp_login (conf->connection, CONF(conf, vhost),
             /* channel max = */      0,
@@ -429,7 +475,7 @@ static int camqp_connect (camqp_config_t *conf) /* {{{ */
         ERROR ("amqp plugin: amqp_login (vhost = %s, user = %s) failed.",
                 CONF(conf, vhost), CONF(conf, user));
         amqp_destroy_connection (conf->connection);
-        close (sockfd);
+        CLOSE_SOCKET ();
         conf->connection = NULL;
         return (1);
     }
@@ -442,7 +488,7 @@ static int camqp_connect (camqp_config_t *conf) /* {{{ */
         ERROR ("amqp plugin: amqp_channel_open failed.");
         amqp_connection_close (conf->connection, AMQP_REPLY_SUCCESS);
         amqp_destroy_connection (conf->connection);
-        close(sockfd);
+        CLOSE_SOCKET ();
         conf->connection = NULL;
         return (1);
     }
index 7e4c79b..ad5975c 100644 (file)
@@ -671,9 +671,18 @@ static int apache_read_host (user_data_t *user_data) /* {{{ */
        return (0);
 } /* }}} int apache_read_host */
 
+static int apache_init (void) /* {{{ */
+{
+       /* Call this while collectd is still single-threaded to avoid
+        * initialization issues in libgcrypt. */
+       curl_global_init (CURL_GLOBAL_SSL);
+       return (0);
+} /* }}} int apache_init */
+
 void module_register (void)
 {
        plugin_register_complex_config ("apache", config);
+       plugin_register_init ("apache", apache_init);
 } /* void module_register */
 
 /* vim: set sw=8 noet fdm=marker : */
index eb1d14f..b241a9f 100644 (file)
@@ -13,6 +13,7 @@ collectd-unixsock - Documentation of collectd's C<unixsock plugin>
     SocketFile "/path/to/socket"
     SocketGroup "collectd"
     SocketPerms "0770"
+    DeleteSocket false
   </Plugin>
 
 =head1 DESCRIPTION
index 18a74c6..4d5abe0 100644 (file)
 #  </View>
 #</Plugin>
 
-#<Plugin cgroup>
+#<Plugin cgroups>
 #  CGroup "libvirt"
 #  IgnoreSelected false
 #</Plugin>
index acd0cbb..3a8af84 100644 (file)
@@ -494,6 +494,8 @@ possibly filtering or messages.
  #   StoreRates false
  #   GraphitePrefix "collectd."
  #   GraphiteEscapeChar "_"
+ #   GraphiteSeparateInstances false
+ #   GraphiteAlwaysAppendDS false
    </Publish>
 
    # Receive values from an AMQP broker
@@ -647,6 +649,19 @@ In I<Graphite> metric name, dots are used as separators between different
 metric parts (host, plugin, type).
 Default is "_" (I<Underscore>).
 
+=item B<GraphiteSeparateInstances> B<true>|B<false>
+
+If set to B<true>, the plugin instance and type instance will be in their own
+path component, for example C<host.cpu.0.cpu.idle>. If set to B<false> (the
+default), the plugin and plugin instance (and likewise the type and type
+instance) are put into one component, for example C<host.cpu-0.cpu-idle>.
+
+=item B<GraphiteAlwaysAppendDS> B<true>|B<false>
+
+If set to B<true>, append the name of the I<Data Source> (DS) to the "metric"
+identifier. If set to B<false> (the default), this is only done when there is
+more than one DS.
+
 =back
 
 =head2 Plugin C<apache>
@@ -6512,7 +6527,7 @@ instance) are put into one component, for example C<host.cpu-0.cpu-idle>.
 
 =item B<AlwaysAppendDS> B<false>|B<true>
 
-If set the B<true>, append the name of the I<Data Source> (DS) to the "metric"
+If set to B<true>, append the name of the I<Data Source> (DS) to the "metric"
 identifier. If set to B<false> (the default), this is only done when there is
 more than one DS.
 
@@ -7387,19 +7402,36 @@ Available options:
 =item B<Plugin> I<Name>
 
 Name of the write plugin to which the data should be sent. This option may be
-given multiple times to send the data to more than one write plugin.
+given multiple times to send the data to more than one write plugin. If the
+plugin supports multiple instances, the plugin's instance(s) must also be
+specified.
 
 =back
 
 If no plugin is explicitly specified, the values will be sent to all available
 write plugins.
 
-Example:
+Single-instance plugin example:
 
  <Target "write">
    Plugin "rrdtool"
  </Target>
 
+Multi-instance plugin example:
+
+ <Plugin "write_graphite">
+   <Node "foo">
+   ...
+   </Node>
+   <Node "bar">
+   ...
+   </Node>
+ </Plugin>
+  ...
+ <Target "write">
+   Plugin "write_graphite/foo"
+ </Target>
+
 =item B<jump>
 
 Starts processing the rules of another chain, see L<"Flow control"> above. If
index 93c1ca1..8691d3e 100644 (file)
@@ -1073,9 +1073,9 @@ int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
   }
 
   if (value == endptr) {
-    sfree (value);
     ERROR ("parse_value: Failed to parse string as %s: %s.",
         DS_TYPE_TO_STRING (ds_type), value);
+    sfree (value);
     return -1;
   }
   else if ((NULL != endptr) && ('\0' != *endptr))
index 855681b..d2a307d 100644 (file)
@@ -481,6 +481,12 @@ static int cf_ci_replace_child (oconfig_item_t *dst, oconfig_item_t *src,
 
        /* Resize the memory containing the children to be big enough to hold
         * all children. */
+       if (dst->children_num + src->children_num - 1 == 0)
+       {
+               dst->children_num = 0;
+               return (0);
+       }
+
        temp = (oconfig_item_t *) realloc (dst->children,
                        sizeof (oconfig_item_t)
                        * (dst->children_num + src->children_num - 1));
@@ -595,7 +601,8 @@ static int cf_include_all (oconfig_item_t *root, int depth)
                        return (-1);
 
                /* Now replace the i'th child in `root' with `new'. */
-               cf_ci_replace_child (root, new, i);
+               if (cf_ci_replace_child (root, new, i) < 0)
+                       return (-1);
 
                /* ... and go back to the new i'th child. */
                --i;
index 3e7c5a5..f605c07 100644 (file)
@@ -579,6 +579,7 @@ static int cc_init (void) /* {{{ */
     INFO ("curl plugin: No pages have been defined.");
     return (-1);
   }
+  curl_global_init (CURL_GLOBAL_SSL);
   return (0);
 } /* }}} int cc_init */
 
index 6a01590..a84cba0 100644 (file)
@@ -726,7 +726,7 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
   if (status == 0)
   {
     user_data_t ud;
-    char cb_name[DATA_MAX_NAME_LEN];
+    char *cb_name;
     struct timespec interval = { 0, 0 };
 
     CDTIME_T_TO_TIMESPEC (db->interval, &interval);
@@ -741,12 +741,13 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
     ud.data = (void *) db;
     ud.free_func = cj_free;
 
-    ssnprintf (cb_name, sizeof (cb_name), "curl_json-%s-%s",
+    cb_name = ssnprintf_alloc ("curl_json-%s-%s",
                db->instance, db->url ? db->url : db->sock);
 
     plugin_register_complex_read (/* group = */ NULL, cb_name, cj_read,
                                   /* interval = */ (db->interval > 0) ? &interval : NULL,
                                   &ud);
+    sfree (cb_name);
   }
   else
   {
@@ -975,9 +976,18 @@ static int cj_read (user_data_t *ud) /* {{{ */
   return cj_perform (db);
 } /* }}} int cj_read */
 
+static int cj_init (void) /* {{{ */
+{
+  /* Call this while collectd is still single-threaded to avoid
+   * initialization issues in libgcrypt. */
+  curl_global_init (CURL_GLOBAL_SSL);
+  return (0);
+} /* }}} int cj_init */
+
 void module_register (void)
 {
   plugin_register_complex_config ("curl_json", cj_config);
+  plugin_register_init ("curl_json", cj_init);
 } /* void module_register */
 
 /* vim: set sw=2 sts=2 et fdm=marker : */
index 6d36d29..a743753 100644 (file)
@@ -386,7 +386,7 @@ static int cx_handle_instance_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */
   /* If the base xpath returns more than one block, the result is assumed to be
    * a table. The `Instance' option is not optional in this case. Check for the
    * condition and inform the user. */
-  if (is_table && (vl->type_instance == NULL))
+  if (is_table)
   {
     WARNING ("curl_xml plugin: "
         "Base-XPath %s is a table (more than one result was returned), "
@@ -1042,9 +1042,18 @@ static int cx_config (oconfig_item_t *ci) /* {{{ */
   return (0);
 } /* }}} int cx_config */
 
+static int cx_init (void) /* {{{ */
+{
+  /* Call this while collectd is still single-threaded to avoid
+   * initialization issues in libgcrypt. */
+  curl_global_init (CURL_GLOBAL_SSL);
+  return (0);
+} /* }}} int cx_init */
+
 void module_register (void)
 {
   plugin_register_complex_config ("curl_xml", cx_config);
+  plugin_register_init ("curl_xml", cx_init);
 } /* void module_register */
 
 /* vim: set sw=2 sts=2 et fdm=marker : */
index d56c07f..cb6844b 100644 (file)
@@ -744,8 +744,8 @@ static void *exec_notification_one (void *arg) /* {{{ */
 
   fprintf (fh,
       "Severity: %s\n"
-      "Time: %.3f\n",
-      severity, CDTIME_T_TO_DOUBLE (n->time));
+      "Time: %u\n",
+      severity, (unsigned int)CDTIME_T_TO_TIME_T(n->time));
 
   /* Print the optional fields */
   if (strlen (n->host) > 0)
index 9e24542..82d7f6f 100644 (file)
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -125,6 +125,10 @@ static void vg_read(vg_t vg, char const *vg_name)
     }
 
     dm_list_iterate_items(lvl, lvs) {
+         lvm_submit(vg_name, lvm_lv_get_name(lvl->lv), lvm_lv_get_size(lvl->lv));
+    }
+
+    dm_list_iterate_items(lvl, lvs) {
         name = lvm_lv_get_name(lvl->lv);
         attrs = get_lv_property_string(lvl->lv, "lv_attr");
         size = lvm_lv_get_size(lvl->lv);
index 5769da7..b191983 100644 (file)
@@ -501,8 +501,15 @@ static void network_init_gcrypt (void) /* {{{ */
   if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P))
     return;
 
-  gcry_check_version (NULL); /* before calling any other functions */
+ /* http://www.gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
+  * To ensure thread-safety, it's important to set GCRYCTL_SET_THREAD_CBS
+  * *before* initalizing Libgcrypt with gcry_check_version(), which itself must
+  * be called before any other gcry_* function. GCRYCTL_ANY_INITIALIZATION_P
+  * above doesn't count, as it doesn't implicitly initalize Libgcrypt.
+  *
+  * tl;dr: keep all these gry_* statements in this exact order please. */
   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+  gcry_check_version (NULL);
   gcry_control (GCRYCTL_INIT_SECMEM, 32768);
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED);
 } /* }}} void network_init_gcrypt */
index 210e6f1..5601d29 100644 (file)
@@ -223,7 +223,7 @@ static int pagesize;
 int     getprocs64 (void *procsinfo, int sizproc, void *fdsinfo, int sizfd, pid_t *index, int count);
 int     getthrds64( pid_t, void *, int, tid64_t *, int );
 #endif
-int getargs (struct procentry64 *processBuffer, int bufferLen, char *argsBuffer, int argsLen);
+int getargs (void *processBuffer, int bufferLen, char *argsBuffer, int argsLen);
 #endif /* HAVE_PROCINFO_H */
 
 /* put name of process from config to list_head_g tree
index 307af17..4a658d0 100644 (file)
@@ -767,7 +767,7 @@ static void Values_dealloc(PyObject *self) {
 }
 
 static PyMemberDef Values_members[] = {
-       {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
+       {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc},
        {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
        {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
        {NULL}
index 3be2ae2..7d6e0a1 100644 (file)
@@ -1618,6 +1618,10 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
     snmp_free_pdu (res);
   res = NULL;
 
+  if (req != NULL)
+    snmp_free_pdu (req);
+  req = NULL;
+
   if (status == 0)
     csnmp_dispatch_table (host, data, instance_list_head, value_list_head);
 
index 80435db..5a04231 100644 (file)
@@ -74,7 +74,9 @@
 /* sys/socket.h is necessary to compile when using netlink on older systems. */
 # include <sys/socket.h>
 # include <linux/netlink.h>
+#if HAVE_LINUX_INET_DIAG_H
 # include <linux/inet_diag.h>
+#endif
 # include <sys/socket.h>
 # include <arpa/inet.h>
 /* #endif KERNEL_LINUX */
 #endif /* KERNEL_AIX */
 
 #if KERNEL_LINUX
+#if HAVE_STRUCT_LINUX_INET_DIAG_REQ
 struct nlreq {
   struct nlmsghdr nlh;
   struct inet_diag_req r;
 };
+#endif
 
 static const char *tcp_state[] =
 {
@@ -276,7 +280,12 @@ static int port_collect_listening = 0;
 static port_entry_t *port_list_head = NULL;
 
 #if KERNEL_LINUX
+#if HAVE_STRUCT_LINUX_INET_DIAG_REQ
+/* This depends on linux inet_diag_req because if this structure is missing,
+ * sequence_number is useless and we get a compilation warning.
+ */
 static uint32_t sequence_number = 0;
+#endif
 
 enum
 {
@@ -446,6 +455,7 @@ static int conn_handle_ports (uint16_t port_local, uint16_t port_remote, uint8_t
  * zero on other errors. */
 static int conn_read_netlink (void)
 {
+#if HAVE_STRUCT_LINUX_INET_DIAG_REQ
   int fd;
   struct sockaddr_nl nladdr;
   struct nlreq req;
@@ -574,6 +584,9 @@ static int conn_read_netlink (void)
 
   /* Not reached because the while() loop above handles the exit condition. */
   return (0);
+#else
+  return (1);
+#endif /* HAVE_STRUCT_LINUX_INET_DIAG_REQ */
 } /* int conn_read_netlink */
 
 static int conn_handle_line (char *buffer)
index 01d33ff..75c0206 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "collectd.h"
 
+#include <pthread.h>
 #include <regex.h>
 
 #include "common.h"
@@ -86,6 +87,7 @@ struct user_obj_s
 
 struct user_class_s
 {
+  pthread_mutex_t lock;
   void *user_class;
   identifier_match_t match;
   user_obj_t *user_obj_list; /* list of user_obj */
@@ -191,6 +193,7 @@ static int lu_copy_ident_to_match (identifier_match_t *match, /* {{{ */
   return (0);
 } /* }}} int lu_copy_ident_to_match */
 
+/* user_class->lock must be held when calling this function */
 static void *lu_create_user_obj (lookup_t *obj, /* {{{ */
     data_set_t const *ds, value_list_t const *vl,
     user_class_t *user_class)
@@ -245,6 +248,7 @@ static void *lu_create_user_obj (lookup_t *obj, /* {{{ */
   return (user_obj);
 } /* }}} void *lu_create_user_obj */
 
+/* user_class->lock must be held when calling this function */
 static user_obj_t *lu_find_user_obj (user_class_t *user_class, /* {{{ */
     value_list_t const *vl)
 {
@@ -294,14 +298,17 @@ static int lu_handle_user_class (lookup_t *obj, /* {{{ */
       || !lu_part_matches (&user_class->match.host, vl->host))
     return (1);
 
+  pthread_mutex_lock (&user_class->lock);
   user_obj = lu_find_user_obj (user_class, vl);
   if (user_obj == NULL)
   {
     /* call lookup_class_callback_t() and insert into the list of user objects. */
     user_obj = lu_create_user_obj (obj, ds, vl, user_class);
+    pthread_mutex_unlock (&user_class->lock);
     if (user_obj == NULL)
       return (-1);
   }
+  pthread_mutex_unlock (&user_class->lock);
 
   status = obj->cb_user_obj (ds, vl,
       user_class->user_class, user_obj->user_obj);
@@ -402,7 +409,7 @@ static int lu_add_by_plugin (by_type_entry_t *by_type, /* {{{ */
   identifier_match_t const *match = &user_class_list->entry.match;
 
   /* Lookup user_class_list from the per-plugin structure. If this is the first
-   * user_class to be added, the blocks return immediately. Otherwise they will
+   * user_class to be added, the block returns immediately. Otherwise they will
    * set "ptr" to non-NULL. */
   if (match->plugin.is_regex)
   {
@@ -487,6 +494,7 @@ static void lu_destroy_user_class_list (lookup_t *obj, /* {{{ */
 
     lu_destroy_user_obj (obj, user_class_list->entry.user_obj_list);
     user_class_list->entry.user_obj_list = NULL;
+    pthread_mutex_destroy (&user_class_list->entry.lock);
 
     sfree (user_class_list);
     user_class_list = next;
@@ -599,6 +607,7 @@ int lookup_add (lookup_t *obj, /* {{{ */
     return (ENOMEM);
   }
   memset (user_class_obj, 0, sizeof (*user_class_obj));
+  pthread_mutex_init (&user_class_obj->entry.lock, /* attr = */ NULL);
   user_class_obj->entry.user_class = user_class;
   lu_copy_ident_to_match (&user_class_obj->entry.match, ident, group_by);
   user_class_obj->entry.user_obj_list = NULL;
index aabca3e..eee5a1c 100644 (file)
@@ -601,9 +601,18 @@ static int wh_config (oconfig_item_t *ci) /* {{{ */
         return (0);
 } /* }}} int wh_config */
 
+static int wh_init (void) /* {{{ */
+{
+        /* Call this while collectd is still single-threaded to avoid
+         * initialization issues in libgcrypt. */
+        curl_global_init (CURL_GLOBAL_SSL);
+        return (0);
+} /* }}} int wh_init */
+
 void module_register (void) /* {{{ */
 {
         plugin_register_complex_config ("write_http", wh_config);
+        plugin_register_init ("write_http", wh_init);
 } /* }}} void module_register */
 
 /* vim: set fdm=marker sw=8 ts=8 tw=78 et : */
index 78f01c0..b59c3e3 100644 (file)
@@ -51,8 +51,8 @@ struct riemann_host {
 #define F_CONNECT               0x01
        uint8_t                  flags;
        pthread_mutex_t          lock;
-    _Bool            notifications;
-    _Bool            check_thresholds;
+       _Bool                    notifications;
+       _Bool                    check_thresholds;
        _Bool                    store_rates;
        _Bool                    always_append_ds;
        char                    *node;
@@ -97,7 +97,7 @@ static void riemann_event_protobuf_free (Event *event) /* {{{ */
        sfree (event);
 } /* }}} void riemann_event_protobuf_free */
 
-static void riemann_msg_protobuf_free (Msg *msg) /* {{{ */
+static void riemann_msg_protobuf_free(Msg *msg) /* {{{ */
 {
        size_t i;
 
@@ -319,7 +319,7 @@ static int riemann_event_add_tag (Event *event, char const *tag) /* {{{ */
        return (strarray_add (&event->tags, &event->n_tags, tag));
 } /* }}} int riemann_event_add_tag */
 
-static int riemann_event_add_attribute (Event *event, /* {{{ */
+static int riemann_event_add_attribute(Event *event, /* {{{ */
                char const *key, char const *value)
 {
        Attribute **new_attributes;
@@ -352,7 +352,7 @@ static int riemann_event_add_attribute (Event *event, /* {{{ */
        return (0);
 } /* }}} int riemann_event_add_attribute */
 
-static Msg *riemann_notification_to_protobuf (struct riemann_host *host, /* {{{ */
+static Msg *riemann_notification_to_protobuf(struct riemann_host *host, /* {{{ */
                notification_t const *n)
 {
        Msg *msg;
@@ -459,7 +459,7 @@ static Msg *riemann_notification_to_protobuf (struct riemann_host *host, /* {{{
        return (msg);
 } /* }}} Msg *riemann_notification_to_protobuf */
 
-static Event *riemann_value_to_protobuf (struct riemann_host const *host, /* {{{ */
+static Event *riemann_value_to_protobuf(struct riemann_host const *host, /* {{{ */
                data_set_t const *ds,
                value_list_t const *vl, size_t index,
                                         gauge_t const *rates,
@@ -484,22 +484,22 @@ static Event *riemann_value_to_protobuf (struct riemann_host const *host, /* {{{
        event->time = CDTIME_T_TO_TIME_T (vl->time);
        event->has_time = 1;
 
-    if (host->check_thresholds) {
-        switch (status) {
-        case STATE_OKAY:
-            event->state = strdup("ok");
-            break;
-        case STATE_ERROR:
-            event->state = strdup("critical");
-            break;
-        case STATE_WARNING:
-            event->state = strdup("warning");
-            break;
-        case STATE_MISSING:
-            event->state = strdup("unknown");
-            break;
-        }
-    }
+       if (host->check_thresholds) {
+               switch (status) {
+                       case STATE_OKAY:
+                               event->state = strdup("ok");
+                               break;
+                       case STATE_ERROR:
+                               event->state = strdup("critical");
+                               break;
+                       case STATE_WARNING:
+                               event->state = strdup("warning");
+                               break;
+                       case STATE_MISSING:
+                               event->state = strdup("unknown");
+                               break;
+               }
+       }
 
        ttl = CDTIME_T_TO_DOUBLE (vl->interval) * host->ttl_factor;
        event->ttl = (float) ttl;
@@ -645,8 +645,8 @@ static int riemann_notification(const notification_t *n, user_data_t *ud) /* {{{
        struct riemann_host     *host = ud->data;
        Msg                     *msg;
 
-    if (!host->notifications)
-        return 0;
+       if (!host->notifications)
+               return 0;
 
        msg = riemann_notification_to_protobuf (host, n);
        if (msg == NULL)
@@ -670,8 +670,8 @@ static int riemann_write(const data_set_t *ds, /* {{{ */
        struct riemann_host     *host = ud->data;
        Msg                     *msg;
 
-    if (host->check_thresholds)
-        write_riemann_threshold_check(ds, vl, statuses);
+       if (host->check_thresholds)
+               write_riemann_threshold_check(ds, vl, statuses);
        msg = riemann_value_list_to_protobuf (host, ds, vl, statuses);
        if (msg == NULL)
                return (-1);
@@ -725,8 +725,8 @@ static int riemann_config_node(oconfig_item_t *ci) /* {{{ */
        host->reference_count = 1;
        host->node = NULL;
        host->service = NULL;
-    host->notifications = 1;
-    host->check_thresholds = 0;
+       host->notifications = 1;
+       host->check_thresholds = 0;
        host->store_rates = 1;
        host->always_append_ds = 0;
        host->use_tcp = 0;
@@ -751,14 +751,14 @@ static int riemann_config_node(oconfig_item_t *ci) /* {{{ */
                        status = cf_util_get_string (child, &host->node);
                        if (status != 0)
                                break;
-        } else if (strcasecmp ("Notifications", child->key) == 0) {
-            status = cf_util_get_boolean(child, &host->notifications);
-            if (status != 0)
-                break;
-        } else if (strcasecmp ("CheckThresholds", child->key) == 0) {
-            status = cf_util_get_boolean(child, &host->check_thresholds);
-            if (status != 0)
-                break;
+               } else if (strcasecmp ("Notifications", child->key) == 0) {
+                       status = cf_util_get_boolean(child, &host->notifications);
+                       if (status != 0)
+                               break;
+               } else if (strcasecmp ("CheckThresholds", child->key) == 0) {
+                       status = cf_util_get_boolean(child, &host->check_thresholds);
+                       if (status != 0)
+                               break;
                } else if (strcasecmp ("Port", child->key) == 0) {
                        status = cf_util_get_service (child, &host->service);
                        if (status != 0) {
@@ -928,7 +928,7 @@ static int riemann_config(oconfig_item_t *ci) /* {{{ */
                                 child->key);
                }
        }
-    return 0;
+       return (0);
 } /* }}} int riemann_config */
 
 void module_register(void)
index 7fbc867..6b5e40e 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-DEFAULT_VERSION="5.4.0.git"
+DEFAULT_VERSION="5.4.1.git"
 
 VERSION="`git describe 2> /dev/null | grep collectd | sed -e 's/^collectd-//'`"