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

24 files changed:
1  2 
ChangeLog
configure.ac
contrib/redhat/collectd.spec
src/Makefile.am
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/snmp.c
src/tcpconns.c
src/utils_vl_lookup.c
src/write_http.c
src/write_riemann.c
version-gen.sh

diff --combined ChangeLog
+++ b/ChangeLog
@@@ -1,3 -1,27 +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
  
  2008-07-15, Version 4.4.2
        * build system: Use pkg-config to detect the upsclient library.
 -      * collectd: Try even harder to determine the endianess of the
 +      * collectd: Try even harder to determine the endianness of the
          architecture collectd is being built on.
        * disk plugin: Fix for Linux 2.4: A wrong field was used as the name
          of disks.
  2008-08-30, Version 4.3.4
        * Build system: Improved detection of and linking with the statgrab
          library.
 -      * collectd: Portability fixes, especially to determine endianess more
 +      * collectd: Portability fixes, especially to determine endianness more
          reliable.
        * Various plugins: Fix format strings.
        * disk plugin: A fix for giving disks under Linux 2.4 the right names
diff --combined configure.ac
@@@ -404,6 -404,18 +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
@@@ -981,7 -993,7 +993,7 @@@ if test "x$fp_layout_type" = "xunknown"
        uint8_t c[8];
        double d;
  
 -      d = 8.642135e130; 
 +      d = 8.642135e130;
        memcpy ((void *) &i0, (void *) &d, 8);
  
        i1 = i0;
@@@ -1036,7 -1048,7 +1048,7 @@@ if test "x$fp_layout_type" = "xunknown"
        uint8_t c[8];
        double d;
  
 -      d = 8.642135e130; 
 +      d = 8.642135e130;
        memcpy ((void *) &i0, (void *) &d, 8);
  
        i1 = endianflip (i0);
@@@ -1085,7 -1097,7 +1097,7 @@@ if test "x$fp_layout_type" = "xunknown"
        uint8_t c[8];
        double d;
  
 -      d = 8.642135e130; 
 +      d = 8.642135e130;
        memcpy ((void *) &i0, (void *) &d, 8);
  
        i1 = intswap (i0);
    AC_MSG_ERROR([Didn't find out how doubles are stored in memory. Sorry.])
  fi; fi; fi
  
 +# --with-useragent {{{
 +AC_ARG_WITH(useragent, [AS_HELP_STRING([--with-useragent@<:@=AGENT@:>@], [User agent to use on http requests])],
 +[
 +    if test "x$withval" != "xno" && test "x$withval" != "xyes"
 +    then
 +        AC_DEFINE_UNQUOTED(COLLECTD_USERAGENT, ["$withval"], [User agent for http requests])
 +    fi
 +])
 +
 +# }}}
 +
  have_getfsstat="no"
  AC_CHECK_FUNCS(getfsstat, [have_getfsstat="yes"])
  have_getvfsstat="no"
@@@ -1218,10 -1219,9 +1230,9 @@@ if test "x$have_getmntent" = "xgen"; th
  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>
            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 -1260,13 +1271,13 @@@ AC_CHECK_MEMBERS([struct net_device_sta
        #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 -1377,8 +1388,8 @@@ AC_CHECK_LIB(hal,libhal_device_property
             [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
@@@ -1380,7 -1389,7 +1400,7 @@@ collectd additional packages:]
  
  AM_CONDITIONAL([BUILD_FREEBSD],[test "x$x$ac_system" = "xFreeBSD"])
  
 -AM_CONDITIONAL([BUILD_AIX],[test "x$x$ac_system" = "xAIX"]) 
 +AM_CONDITIONAL([BUILD_AIX],[test "x$x$ac_system" = "xAIX"])
  
  if test "x$ac_system" = "xAIX"
  then
@@@ -1710,7 -1719,6 +1730,7 @@@ the
        LDFLAGS="$LDFLAGS $with_libdbi_ldflags"
  
        AC_CHECK_LIB(dbi, dbi_initialize, [with_libdbi="yes"], [with_libdbi="no (Symbol 'dbi_initialize' not found)"])
 +      AC_CHECK_LIB(dbi, dbi_driver_open_r, [with_libdbi_r="yes"], [with_libdbi_r="no"])
  
        CPPFLAGS="$SAVE_CPPFLAGS"
        LDFLAGS="$SAVE_LDFLAGS"
        AC_SUBST(BUILD_WITH_LIBDBI_CPPFLAGS)
        AC_SUBST(BUILD_WITH_LIBDBI_LDFLAGS)
        AC_SUBST(BUILD_WITH_LIBDBI_LIBS)
 +
 +  if test "x$with_libdbi_r" = "xyes"
 +  then
 +              AC_DEFINE(HAVE_LIBDBI_R, 1, [Define if reentrant dbi facility is present and usable.])
 +  fi
  fi
  AM_CONDITIONAL(BUILD_WITH_LIBDBI, test "x$with_libdbi" = "xyes")
  # }}}
@@@ -1946,7 -1949,10 +1966,7 @@@ AM_CONDITIONAL(BUILD_WITH_LIBGCRYPT, te
  # --with-libiptc {{{
  AC_ARG_WITH(libiptc, [AS_HELP_STRING([--with-libiptc@<:@=PREFIX@:>@], [Path to libiptc.])],
  [
 -      if test "x$withval" = "xshipped"
 -      then
 -              with_libiptc="own"
 -      else if test "x$withval" = "xyes"
 +      if test "x$withval" = "xyes"
        then
                with_libiptc="pkgconfig"
        else if test "x$withval" = "xno"
                with_libiptc="yes"
                with_libiptc_cflags="-I$withval/include"
                with_libiptc_libs="-L$withval/lib"
 -      fi; fi; fi
 +      fi; fi
  ],
  [
        if test "x$ac_system" = "xLinux"
  
  CPPFLAGS="$SAVE_CPPFLAGS"
  
 -if test "x$with_libiptc" = "xown"
 -then
 -      with_libiptc_cflags=""
 -      with_libiptc_libs=""
 -fi
 -if test "x$with_libiptc" = "xown"
 -then
 -      AC_CHECK_HEADERS(linux/netfilter_ipv4/ip_tables.h linux/netfilter_ipv6/ip6_tables.h linux/netfilter/x_tables.h, [],
 -      [
 -              with_libiptc="no (Linux iptables headers not found)"
 -      ],
 -      [
 -#include "$srcdir/src/owniptc/ipt_kernel_headers.h"
 -      ])
 -fi
 -AM_CONDITIONAL(BUILD_WITH_OWN_LIBIPTC, test "x$with_libiptc" = "xown")
 -if test "x$with_libiptc" = "xown"
 -then
 -      AC_DEFINE(OWN_LIBIPTC, 1, [Define to 1 if we use the shipped iptc library.])
 -      with_libiptc="yes"
 -fi
 -
  AM_CONDITIONAL(BUILD_WITH_LIBIPTC, test "x$with_libiptc" = "xyes")
  if test "x$with_libiptc" = "xyes"
  then
@@@ -2241,7 -2269,7 +2261,7 @@@ the
          CPPFLAGS="$CPPFLAGS $with_liblvm2app_cppflags"
          LDFLAGS="$LDFLAGS $with_liblvm2app_ldflags"
  
 -        AC_CHECK_LIB(lvm2app, lvm_init, [with_liblvm2app="yes"], [with_liblvm2app="no (Symbol 'lvm_init' not found)"])
 +        AC_CHECK_LIB(lvm2app, lvm_lv_get_property, [with_liblvm2app="yes"], [with_liblvm2app="no (Symbol 'lvm_lv_get_property' not found)"])
  
          CPPFLAGS="$SAVE_CPPFLAGS"
          LDFLAGS="$SAVE_LDFLAGS"
@@@ -2643,15 -2671,6 +2663,15 @@@ return (retval)
  fi
  if test "x$with_libmnl" = "xyes"
  then
 +      AC_CHECK_MEMBERS([struct rtnl_link_stats64.tx_window_errors],
 +      [AC_DEFINE(HAVE_RTNL_LINK_STATS64, 1, [Define if struct rtnl_link_stats64 exists and is usable.])],
 +      [],
 +      [
 +      #include <linux/if_link.h>
 +      ])
 +fi
 +if test "x$with_libmnl" = "xyes"
 +then
        AC_CHECK_LIB(mnl, mnl_nlmsg_get_payload,
                     [with_libmnl="yes"],
                     [with_libmnl="no (symbol 'mnl_nlmsg_get_payload' not found)"],
@@@ -2775,7 -2794,7 +2795,7 @@@ the
        else
                SAVE_CPPFLAGS="$CPPFLAGS"
                CPPFLAGS="$CPPFLAGS $with_snmp_cflags"
 -              
 +
                AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
  
                CPPFLAGS="$SAVE_CPPFLAGS"
@@@ -3002,7 -3021,7 +3022,7 @@@ if test "x$with_libowcapi" = "xyes
  then
        SAVE_CPPFLAGS="$CPPFLAGS"
        CPPFLAGS="$with_libowcapi_cppflags"
 -      
 +
        AC_CHECK_HEADERS(owcapi.h, [with_libowcapi="yes"], [with_libowcapi="no (owcapi.h not found)"])
  
        CPPFLAGS="$SAVE_CPPFLAGS"
@@@ -3013,7 -3032,7 +3033,7 @@@ the
        SAVE_CPPFLAGS="$CPPFLAGS"
        LDFLAGS="$with_libowcapi_libs"
        CPPFLAGS="$with_libowcapi_cppflags"
 -      
 +
        AC_CHECK_LIB(owcapi, OW_get, [with_libowcapi="yes"], [with_libowcapi="no (libowcapi not found)"])
  
        LDFLAGS="$SAVE_LDFLAGS"
  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 {{{
 +AC_ARG_WITH(librdkafka, [AS_HELP_STRING([--with-librdkafka@<:@=PREFIX@:>@], [Path to librdkafka.])],
 +[
 +  if test "x$withval" = "xno" && test "x$withval" != "xyes"
 +  then
 +    with_librdkafka_cppflags="-I$withval/include"
 +    with_librdkafka_ldflags="-L$withval/lib"
 +    with_librdkafka="yes"
 +  else
 +    with_librdkafka="$withval"
 +  fi
 +],
 +[
 +  with_librdkafka="yes"
 +])
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +
 +if test "x$with_librdkafka" = "xyes"
 +then
 +      AC_CHECK_HEADERS(librdkafka/rdkafka.h, [with_librdkafka="yes"], [with_librdkafka="no (librdkafka/rdkafka.h not found)"])
 +fi
 +
 +if test "x$with_librdkafka" = "xyes"
 +then
 +      AC_CHECK_LIB(rdkafka, rd_kafka_new, [with_librdkafka="yes"], [with_librdkafka="no (Symbol 'rd_kafka_new' not found)"])
 +  AC_CHECK_LIB(rdkafka, rd_kafka_conf_set_log_cb, [with_librdkafka_log_cb="yes"], [with_librdkafka_log_cb="no"])
 +  AC_CHECK_LIB(rdkafka, rd_kafka_conf_set_logger, [with_librdkafka_logger="yes"], [with_librdkafka_logger="no"])
 +fi
 +if test "x$with_librdkafka" = "xyes"
 +then
 +      BUILD_WITH_LIBRDKAFKA_CPPFLAGS="$with_librdkafka_cppflags"
 +      BUILD_WITH_LIBRDKAFKA_LDFLAGS="$with_librdkafka_ldflags"
 +      BUILD_WITH_LIBRDKAFKA_LIBS="-lrdkafka"
 +      AC_SUBST(BUILD_WITH_LIBRDKAFKA_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBRDKAFKA_LDFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBRDKAFKA_LIBS)
 +      AC_DEFINE(HAVE_LIBRDKAFKA, 1, [Define if librdkafka is present and usable.])
 +  if test "x$with_librdkafka_log_cb" = "xyes"
 +  then
 +        AC_DEFINE(HAVE_LIBRDKAFKA_LOG_CB, 1, [Define if librdkafka log facility is present and usable.])
 +  fi
 +  if test "x$with_librdkafka_logger" = "xyes"
 +  then
 +        AC_DEFINE(HAVE_LIBRDKAFKA_LOGGER, 1, [Define if librdkafka log facility is present and usable.])
 +  fi
 +fi
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +AM_CONDITIONAL(BUILD_WITH_LIBRDKAFKA, test "x$with_librdkafka" = "xyes")
 +
 +# }}}
 +
  # --with-librouteros {{{
  AC_ARG_WITH(librouteros, [AS_HELP_STRING([--with-librouteros@<:@=PREFIX@:>@], [Path to librouteros.])],
  [
@@@ -3844,18 -3845,20 +3899,20 @@@ AC_ARG_WITH(libsigrok, [AS_HELP_STRING(
                        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 -4042,8 +4096,8 @@@ the
    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
  
@@@ -4073,7 -4076,7 +4130,7 @@@ CPPFLAGS="$SAVE_CPPFLAGS
  LDFLAGS="$SAVE_LDFLAGS"
  
  if test "x$with_libtokyotyrant" = "xyes"
 -then 
 +then
    BUILD_WITH_LIBTOKYOTYRANT_CPPFLAGS="$with_libtokyotyrant_cppflags"
    BUILD_WITH_LIBTOKYOTYRANT_LDFLAGS="$with_libtokyotyrant_ldflags"
    BUILD_WITH_LIBTOKYOTYRANT_LIBS="$with_libtokyotyrant_libs"
  AM_CONDITIONAL(BUILD_WITH_LIBTOKYOTYRANT, test "x$with_libtokyotyrant" = "xyes")
  # }}}
  
 +# --with-libudev {{{
 +with_libudev_cflags=""
 +with_libudev_ldflags=""
 +AC_ARG_WITH(libudev, [AS_HELP_STRING([--with-libudev@<:@=PREFIX@:>@], [Path to libudev.])],
 +[
 +      if test "x$withval" = "xno"
 +      then
 +              with_libudev="no"
 +      else
 +              with_libudev="yes"
 +              if test "x$withval" != "xyes"
 +              then
 +                      with_libudev_cflags="-I$withval/include"
 +                      with_libudev_ldflags="-L$withval/lib"
 +                      with_libudev="yes"
 +              fi
 +      fi
 +],
 +[
 +      if test "x$ac_system" = "xLinux"
 +      then
 +              with_libudev="yes"
 +      else
 +              with_libudev="no (Linux only library)"
 +      fi
 +])
 +if test "x$with_libudev" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libudev_cflags"
 +
 +      AC_CHECK_HEADERS(libudev.h, [], [with_libudev="no (libudev.h not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +if test "x$with_libudev" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      SAVE_LDFLAGS="$LDFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libudev_cflags"
 +      LDFLAGS="$LDFLAGS $with_libudev_ldflags"
 +
 +      AC_CHECK_LIB(udev, udev_new,
 +      [
 +              AC_DEFINE(HAVE_LIBUDEV, 1, [Define to 1 if you have the udev library (-ludev).])
 +      ],
 +      [with_libudev="no (libudev not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +      LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +if test "x$with_libudev" = "xyes"
 +then
 +      BUILD_WITH_LIBUDEV_CFLAGS="$with_libudev_cflags"
 +      BUILD_WITH_LIBUDEV_LDFLAGS="$with_libudev_ldflags"
 +      AC_SUBST(BUILD_WITH_LIBUDEV_CFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBUDEV_LDFLAGS)
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBUDEV, test "x$with_libudev" = "xyes")
 +# }}}
 +
  # --with-libupsclient {{{
  with_libupsclient_config=""
  with_libupsclient_cflags=""
@@@ -4557,7 -4499,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"
                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"
  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 -4562,12 +4677,12 @@@ if test "x$with_libxml2" = "xyes"; the
  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"
@@@ -4881,7 -4823,6 +4938,7 @@@ dependency_warning="no
  dependency_error="no"
  
  plugin_ascent="no"
 +plugin_barometer="no"
  plugin_battery="no"
  plugin_bind="no"
  plugin_cgroups="no"
@@@ -4893,7 -4834,6 +4950,7 @@@ plugin_curl_json="no
  plugin_curl_xml="no"
  plugin_df="no"
  plugin_disk="no"
 +plugin_drbd="no"
  plugin_entropy="no"
  plugin_ethstat="no"
  plugin_fscache="no"
@@@ -4903,7 -4843,6 +4960,7 @@@ plugin_ipvs="no
  plugin_irq="no"
  plugin_libvirt="no"
  plugin_load="no"
 +plugin_log_logstash="no"
  plugin_memory="no"
  plugin_multimeter="no"
  plugin_nfs="no"
@@@ -4934,7 -4873,6 +4991,7 @@@ the
        plugin_cpu="yes"
        plugin_cpufreq="yes"
        plugin_disk="yes"
 +      plugin_drbd="yes"
        plugin_entropy="yes"
        plugin_fscache="yes"
        plugin_interface="yes"
        plugin_tape="yes"
  fi
  
 +# libi2c-dev
 +with_libi2c="no"
 +if test "x$ac_system" = "xLinux"
 +then
 +AC_CHECK_DECL(i2c_smbus_read_i2c_block_data,
 +      [with_libi2c="yes"],
 +      [with_libi2c="no (symbol i2c_smbus_read_i2c_block_data not found - have you installed libi2c-dev ?)"],
 +      [[#include <stdlib.h>
 +      #include <linux/i2c-dev.h>]])
 +fi
 +
 +if test "x$with_libi2c" = "xyes"
 +then
 +      plugin_barometer="yes"
 +fi
 +
 +
  # libstatgrab
  if test "x$with_libstatgrab" = "xyes"
  then
        plugin_load="yes"
  fi
  
 +if test "x$with_libyajl" = "xyes"
 +then
 +      plugin_log_logstash="yes"
 +fi
 +
  if test "x$c_cv_have_libperl$c_cv_have_perl_ithreads" = "xyesyes"
  then
        plugin_perl="yes"
  
  if test "x$have_termios_h" = "xyes"
  then
 -      plugin_multimeter="yes"
 +      if test "x$ac_system" != "xAIX"
 +      then
 +              plugin_multimeter="yes"
 +      fi
        plugin_ted="yes"
  fi
  
@@@ -5238,7 -5151,6 +5295,7 @@@ AC_PLUGIN([apcups],      [yes]
  AC_PLUGIN([apple_sensors], [$with_libiokit],   [Apple's hardware sensors])
  AC_PLUGIN([aquaero],     [$with_libaquaero5],  [Aquaero's hardware sensors])
  AC_PLUGIN([ascent],      [$plugin_ascent],     [AscentEmu player statistics])
 +AC_PLUGIN([barometer],   [$plugin_barometer],  [Barometer sensor on I2C])
  AC_PLUGIN([battery],     [$plugin_battery],    [Battery statistics])
  AC_PLUGIN([bind],        [$plugin_bind],       [ISC Bind nameserver statistics])
  AC_PLUGIN([conntrack],   [$plugin_conntrack],  [nf_conntrack statistics])
@@@ -5253,7 -5165,6 +5310,7 @@@ AC_PLUGIN([cgroups],     [$plugin_cgrou
  AC_PLUGIN([dbi],         [$with_libdbi],       [General database statistics])
  AC_PLUGIN([df],          [$plugin_df],         [Filesystem usage statistics])
  AC_PLUGIN([disk],        [$plugin_disk],       [Disk usage statistics])
 +AC_PLUGIN([drbd],        [$plugin_drbd],       [DRBD statistics])
  AC_PLUGIN([dns],         [$with_libpcap],      [DNS traffic analysis])
  AC_PLUGIN([email],       [yes],                [EMail statistics])
  AC_PLUGIN([entropy],     [$plugin_entropy],    [Entropy statistics])
@@@ -5272,7 -5183,6 +5329,7 @@@ AC_PLUGIN([java],        [$with_java]
  AC_PLUGIN([libvirt],     [$plugin_libvirt],    [Virtual machine statistics])
  AC_PLUGIN([load],        [$plugin_load],       [System load])
  AC_PLUGIN([logfile],     [yes],                [File logging plugin])
 +AC_PLUGIN([log_logstash], [$plugin_log_logstash], [Logstash json_event compatible logging])
  AC_PLUGIN([lpar],        [$with_perfstat],     [AIX logical partitions statistics])
  AC_PLUGIN([lvm],         [$with_liblvm2app],   [LVM statistics])
  AC_PLUGIN([madwifi],     [$have_linux_wireless_h], [Madwifi wireless statistics])
@@@ -5350,11 -5260,9 +5407,11 @@@ AC_PLUGIN([vserver],     [$plugin_vserv
  AC_PLUGIN([wireless],    [$plugin_wireless],   [Wireless statistics])
  AC_PLUGIN([write_graphite], [yes],             [Graphite / Carbon output plugin])
  AC_PLUGIN([write_http],  [$with_libcurl],      [HTTP output plugin])
 +AC_PLUGIN([write_kafka],  [$with_librdkafka],  [Kafka output plugin])
  AC_PLUGIN([write_mongodb], [$with_libmongoc],  [MongoDB output plugin])
  AC_PLUGIN([write_redis], [$with_libcredis],    [Redis output plugin])
  AC_PLUGIN([write_riemann], [$have_protoc_c],   [Riemann output plugin])
 +AC_PLUGIN([write_tsdb],  [yes],                [TSDB output plugin])
  AC_PLUGIN([xmms],        [$with_libxmms],      [XMMS statistics])
  AC_PLUGIN([zfs_arc],     [$plugin_zfs_arc],    [ZFS ARC statistics])
  
@@@ -5362,7 -5270,6 +5419,7 @@@ dnl Default configuration fil
  # Load either syslog or logfile
  LOAD_PLUGIN_SYSLOG=""
  LOAD_PLUGIN_LOGFILE=""
 +LOAD_PLUGIN_LOG_LOGSTASH=""
  
  AC_MSG_CHECKING([which default log plugin to load])
  default_log_plugin="none"
  else
        LOAD_PLUGIN_LOGFILE="##"
  fi
 +
 +if test "x$enable_log_logstash" = "xyes"
 +then
 +  LOAD_PLUGIN_LOG_LOGSTASH="#"
 +else
 +  LOAD_PLUGIN_LOG_LOGSTASH="##"
 +fi
 +
 +
  AC_MSG_RESULT([$default_log_plugin])
  
  AC_SUBST(LOAD_PLUGIN_SYSLOG)
  AC_SUBST(LOAD_PLUGIN_LOGFILE)
 +AC_SUBST(LOAD_PLUGIN_LOG_LOGSTASH)
  
  DEFAULT_LOG_LEVEL="info"
  if test "x$enable_debug" = "xyes"
@@@ -5546,13 -5443,11 +5603,13 @@@ Configuration
      libesmtp  . . . . . . $with_libesmtp
      libganglia  . . . . . $with_libganglia
      libgcrypt . . . . . . $with_libgcrypt
 +    libi2c-dev  . . . . . $with_libi2c
      libiokit  . . . . . . $with_libiokit
      libiptc . . . . . . . $with_libiptc
      libjvm  . . . . . . . $with_java
      libkstat  . . . . . . $with_kstat
      libkvm  . . . . . . . $with_libkvm
 +    liblvm2app  . . . . . $with_liblvm2app
      libmemcached  . . . . $with_libmemcached
      libmnl  . . . . . . . $with_libmnl
      libmodbus . . . . . . $with_libmodbus
      libpq . . . . . . . . $with_libpq
      libpthread  . . . . . $with_libpthread
      librabbitmq . . . . . $with_librabbitmq
 +    librdkafka  . . . . . $with_librdkafka
      librouteros . . . . . $with_librouteros
      librrd  . . . . . . . $with_librrd
      libsensors  . . . . . $with_libsensors
      libsigrok   . . . . . $with_libsigrok
      libstatgrab . . . . . $with_libstatgrab
      libtokyotyrant  . . . $with_libtokyotyrant
 +    libudev . . . . . . . $with_libudev
      libupsclient  . . . . $with_libupsclient
      libvarnish  . . . . . $with_libvarnish
      libvirt . . . . . . . $with_libvirt
      aquaero . . . . . . . $enable_aquaero
      apple_sensors . . . . $enable_apple_sensors
      ascent  . . . . . . . $enable_ascent
 +    barometer . . . . . . $enable_barometer
      battery . . . . . . . $enable_battery
      bind  . . . . . . . . $enable_bind
      conntrack . . . . . . $enable_conntrack
      df  . . . . . . . . . $enable_df
      disk  . . . . . . . . $enable_disk
      dns . . . . . . . . . $enable_dns
 +    drbd  . . . . . . . . $enable_drbd
      email . . . . . . . . $enable_email
      entropy . . . . . . . $enable_entropy
      ethstat . . . . . . . $enable_ethstat
      load  . . . . . . . . $enable_load
      logfile . . . . . . . $enable_logfile
      lpar  . . . . . . . . $enable_lpar
 +    log_logstash  . . . . $enable_log_logstash
      lvm . . . . . . . . . $enable_lvm
      madwifi . . . . . . . $enable_madwifi
      match_empty_counter . $enable_match_empty_counter
      wireless  . . . . . . $enable_wireless
      write_graphite  . . . $enable_write_graphite
      write_http  . . . . . $enable_write_http
 +    write_kafka . . . . . $enable_write_kafka
      write_mongodb . . . . $enable_write_mongodb
      write_redis . . . . . $enable_write_redis
      write_riemann . . . . $enable_write_riemann
 +    write_tsdb  . . . . . $enable_write_tsdb
      xmms  . . . . . . . . $enable_xmms
      zfs_arc . . . . . . . $enable_zfs_arc
  
@@@ -45,6 -45,7 +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 +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 +424,16 @@@ The mic plugin collects CPU usage, memo
  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 +1009,12 @@@ Development files for libcollectdclien
  %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
  - 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:
  * Sat Nov 17 2012 Ruben Kerkhof <ruben@tilaa.nl> 5.1.0-2
  - Move perl stuff to perl_vendorlib
  - Replace hardcoded paths with macros
 -- Remove unneccesary Requires
 +- Remove unnecessary Requires
  - Removed .a and .la files
  - Some other small cleanups
  
  - New upstream version
  - Changes to support 5.1.0
  - Enabled all buildable plugins based on libraries available on EL6 + EPEL
 -- All plugins requiring external libraries are now shipped in seperate
 +- All plugins requiring external libraries are now shipped in separate
    packages.
  - No longer treat Java plugin as an exception, correctly set $JAVA_HOME during
    the build process + ensure build deps are installed.
diff --combined src/Makefile.am
@@@ -17,8 -17,6 +17,8 @@@ endi
  AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
  AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
  
 +AUTOMAKE_OPTIONS = subdir-objects
 +
  sbin_PROGRAMS = collectd collectdmon
  bin_PROGRAMS = collectd-nagios collectdctl collectd-tg
  
@@@ -41,9 -39,7 +41,9 @@@ collectd_SOURCES = collectd.c collectd.
                   utils_subst.c utils_subst.h \
                   utils_tail.c utils_tail.h \
                   utils_time.c utils_time.h \
 -                 types_list.c types_list.h
 +                 types_list.c types_list.h \
 +                 utils_threshold.c utils_threshold.h
 +
  
  collectd_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL)
  collectd_CFLAGS = $(AM_CFLAGS)
@@@ -137,9 -133,9 +137,9 @@@ collectd_tg_LDADD += libcollectdclient/
  collectd_tg_DEPENDENCIES = libcollectdclient/libcollectdclient.la
  
  
 -pkglib_LTLIBRARIES = 
 +pkglib_LTLIBRARIES =
  
 -BUILT_SOURCES = 
 +BUILT_SOURCES =
  CLEANFILES =
  
  if BUILD_PLUGIN_AGGREGATION
@@@ -221,15 -217,6 +221,15 @@@ collectd_LDADD += "-dlopen" ascent.l
  collectd_DEPENDENCIES += ascent.la
  endif
  
 +if BUILD_PLUGIN_BAROMETER
 +pkglib_LTLIBRARIES += barometer.la
 +barometer_la_SOURCES = barometer.c
 +barometer_la_LDFLAGS = -module -avoid-version
 +barometer_la_LIBADD = -lm
 +collectd_LDADD += "-dlopen" barometer.la
 +collectd_DEPENDENCIES += barometer.la
 +endif
 +
  if BUILD_PLUGIN_BATTERY
  pkglib_LTLIBRARIES += battery.la
  battery_la_SOURCES = battery.c
@@@ -286,7 -273,7 +286,7 @@@ pkglib_LTLIBRARIES += cpu.l
  cpu_la_SOURCES = cpu.c
  cpu_la_CFLAGS = $(AM_CFLAGS)
  cpu_la_LDFLAGS = -module -avoid-version
 -cpu_la_LIBADD = 
 +cpu_la_LIBADD =
  if BUILD_WITH_LIBKSTAT
  cpu_la_LIBADD += -lkstat
  endif
@@@ -384,7 -371,7 +384,7 @@@ pkglib_LTLIBRARIES += disk.l
  disk_la_SOURCES = disk.c
  disk_la_CFLAGS = $(AM_CFLAGS)
  disk_la_LDFLAGS = -module -avoid-version
 -disk_la_LIBADD = 
 +disk_la_LIBADD =
  if BUILD_WITH_LIBKSTAT
  disk_la_LIBADD += -lkstat
  endif
@@@ -395,12 -382,9 +395,12 @@@ if BUILD_WITH_LIBIOKI
  disk_la_LDFLAGS += -framework IOKit
  endif
  if BUILD_WITH_LIBSTATGRAB
 -disk_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)  
 +disk_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
  disk_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
  endif
 +if BUILD_WITH_LIBUDEV
 +disk_la_LIBADD += -ludev
 +endif
  if BUILD_WITH_PERFSTAT
  disk_la_LIBADD += -lperfstat
  endif
@@@ -417,15 -401,6 +417,15 @@@ collectd_LDADD += "-dlopen" dns.l
  collectd_DEPENDENCIES += dns.la
  endif
  
 +if BUILD_PLUGIN_DRBD
 +pkglib_LTLIBRARIES += drbd.la
 +drbd_la_SOURCES = drbd.c
 +drbd_la_LDFLAGS = -module -avoid-version
 +drbd_la_LIBADD = -lpthread
 +collectd_LDADD += "-dlopen" drbd.la
 +collectd_DEPENDENCIES += drbd.la
 +endif
 +
  if BUILD_PLUGIN_EMAIL
  pkglib_LTLIBRARIES += email.la
  email_la_SOURCES = email.c
@@@ -520,8 -495,8 +520,8 @@@ if BUILD_PLUGIN_IPTABLE
  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
@@@ -602,17 -577,6 +602,17 @@@ collectd_LDADD += "-dlopen" logfile.l
  collectd_DEPENDENCIES += logfile.la
  endif
  
 +if BUILD_PLUGIN_LOG_LOGSTASH
 +pkglib_LTLIBRARIES += log_logstash.la
 +log_logstash_la_SOURCES = log_logstash.c
 +log_logstash_la_CFLAGS = $(AM_CFLAGS)
 +log_logstash_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBYAJL_LDFLAGS)
 +log_logstash_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
 +log_logstash_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
 +collectd_LDADD += "-dlopen" log_logstash.la
 +collectd_DEPENDENCIES += log_logstash.la
 +endif
 +
  if BUILD_PLUGIN_LPAR
  pkglib_LTLIBRARIES += lpar.la
  lpar_la_SOURCES = lpar.c
@@@ -898,7 -862,7 +898,7 @@@ if BUILD_PLUGIN_OLSR
  pkglib_LTLIBRARIES += olsrd.la
  olsrd_la_SOURCES = olsrd.c
  olsrd_la_LDFLAGS = -module -avoid-version
 -olsrd_la_LIBADD = 
 +olsrd_la_LIBADD =
  if BUILD_WITH_LIBSOCKET
  olsrd_la_LIBADD += -lsocket
  endif
@@@ -1305,7 -1269,6 +1305,7 @@@ pkglib_LTLIBRARIES += unixsock.l
  unixsock_la_SOURCES = unixsock.c \
                      utils_cmd_flush.h utils_cmd_flush.c \
                      utils_cmd_getval.h utils_cmd_getval.c \
 +                    utils_cmd_getthreshold.h utils_cmd_getthreshold.c \
                      utils_cmd_listval.h utils_cmd_listval.c \
                      utils_cmd_putval.h utils_cmd_putval.c \
                      utils_cmd_putnotif.h utils_cmd_putnotif.c
@@@ -1424,19 -1387,6 +1424,19 @@@ endi
  collectd_DEPENDENCIES += write_http.la
  endif
  
 +if BUILD_PLUGIN_WRITE_KAFKA
 +pkglib_LTLIBRARIES += write_kafka.la
 +write_kafka_la_SOURCES = write_kafka.c \
 +                        utils_format_graphite.c utils_format_graphite.h \
 +                        utils_format_json.c utils_format_json.h \
 +                        utils_cmd_putval.c utils_cmd_putval.h \
 +                        utils_crc32.c utils_crc32.h
 +write_kafka_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRDKAFKA_LDFLAGS)
 +write_kafka_la_LIBADD = $(BUILD_WITH_LIBRDKAFKA_LIBS)
 +collectd_LDADD += "-dlopen" write_kafka.la
 +collectd_DEPENDENCIES += write_kafka.la
 +endif
 +
  if BUILD_PLUGIN_WRITE_MONGODB
  pkglib_LTLIBRARIES += write_mongodb.la
  write_mongodb_la_SOURCES = write_mongodb.c
@@@ -1459,7 -1409,7 +1459,7 @@@ endi
  
  if BUILD_PLUGIN_WRITE_RIEMANN
  pkglib_LTLIBRARIES += write_riemann.la
 -write_riemann_la_SOURCES = write_riemann.c
 +write_riemann_la_SOURCES = write_riemann.c write_riemann_threshold.c
  nodist_write_riemann_la_SOURCES = riemann.pb-c.c riemann.pb-c.h
  write_riemann_la_LDFLAGS = -module -avoid-version
  write_riemann_la_LIBADD = -lprotobuf-c
@@@ -1467,14 -1417,6 +1467,14 @@@ collectd_LDADD += "-dlopen" write_riema
  collectd_DEPENDENCIES += write_riemann.la
  endif
  
 +if BUILD_PLUGIN_WRITE_TSDB
 +pkglib_LTLIBRARIES += write_tsdb.la
 +write_tsdb_la_SOURCES = write_tsdb.c
 +write_tsdb_la_LDFLAGS = -module -avoid-version
 +collectd_LDADD += "-dlopen" write_tsdb.la
 +collectd_DEPENDENCIES += write_tsdb.la
 +endif
 +
  if BUILD_PLUGIN_XMMS
  pkglib_LTLIBRARIES += xmms.la
  xmms_la_SOURCES = xmms.c
@@@ -1593,48 -1535,15 +1593,48 @@@ uninstall-hook
        rm -f $(DESTDIR)$(sysconfdir)/collectd.conf
        rm -f $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
  
 -if BUILD_FEATURE_DEBUG
 -bin_PROGRAMS += utils_vl_lookup_test
 -utils_vl_lookup_test_SOURCES = utils_vl_lookup_test.c \
 +check_PROGRAMS = test_common test_utils_avltree test_utils_heap test_utils_mount test_utils_vl_lookup
 +
 +test_common_SOURCES = tests/test_common.c \
 +                      common.h common.c \
 +                      tests/mock/plugin.c \
 +                      tests/mock/utils_cache.c \
 +                      tests/mock/utils_time.c
 +test_common_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
 +test_common_LDFLAGS = -export-dynamic
 +test_common_LDADD =
 +
 +test_utils_avltree_SOURCES = tests/test_utils_avltree.c \
 +                             utils_avltree.c utils_avltree.h
 +test_utils_avltree_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
 +test_utils_avltree_LDFLAGS = -export-dynamic
 +test_utils_avltree_LDADD =
 +
 +test_utils_heap_SOURCES = tests/test_utils_heap.c \
 +                          utils_heap.c utils_heap.h
 +test_utils_heap_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
 +test_utils_heap_LDFLAGS = -export-dynamic
 +test_utils_heap_LDADD =
 +
 +test_utils_mount_SOURCES = tests/test_utils_mount.c \
 +                           utils_mount.c utils_mount.h \
 +                           common.c common.h \
 +                           tests/mock/plugin.c \
 +                           tests/mock/utils_cache.c \
 +                           tests/mock/utils_time.c
 +test_utils_mount_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
 +test_utils_mount_LDFLAGS = -export-dynamic
 +test_utils_mount_LDADD =
 +
 +test_utils_vl_lookup_SOURCES = tests/test_utils_vl_lookup.c \
                                 utils_vl_lookup.h utils_vl_lookup.c \
                                 utils_avltree.c utils_avltree.h \
 -                               common.h
 -
 -utils_vl_lookup_test_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL) -DBUILD_TEST=1
 -utils_vl_lookup_test_CFLAGS = $(AM_CFLAGS)
 -utils_vl_lookup_test_LDFLAGS = -export-dynamic
 -utils_vl_lookup_test_LDADD =
 -endif
 +                               common.c common.h \
 +                               tests/mock/plugin.c \
 +                               tests/mock/utils_cache.c \
 +                               tests/mock/utils_time.c
 +test_utils_vl_lookup_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
 +test_utils_vl_lookup_LDFLAGS = -export-dynamic
 +test_utils_vl_lookup_LDADD =
 +
 +TESTS = test_common test_utils_avltree test_utils_heap test_utils_mount test_utils_vl_lookup
diff --combined src/amqp.c
@@@ -23,7 -23,7 +23,7 @@@
   *
   * Authors:
   *   Sebastien Pahl <sebastien.pahl at dotcloud.com>
 - *   Florian Forster <octo at verplant.org>
 + *   Florian Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
  #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
@@@ -79,8 -93,6 +93,8 @@@ struct camqp_config_
      /* subscribe only */
      char   *exchange_type;
      char   *queue;
 +    _Bool   queue_durable;
 +    _Bool   queue_auto_delete;
  
      amqp_connection_state_t connection;
      pthread_mutex_t lock;
@@@ -316,9 -328,9 +330,9 @@@ static int camqp_setup_queue (camqp_con
              ? amqp_cstring_bytes (conf->queue)
              : AMQP_EMPTY_BYTES,
              /* passive     = */ 0,
 -            /* durable     = */ 0,
 +            /* durable     = */ conf->queue_durable,
              /* exclusive   = */ 0,
 -            /* auto_delete = */ 1,
 +            /* auto_delete = */ conf->queue_auto_delete,
              /* arguments   = */ AMQP_EMPTY_TABLE);
      if (qd_ret == NULL)
      {
  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);
          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)
      {
          return (status);
      }
      amqp_set_sockfd (conf->connection, sockfd);
+ #endif
  
      reply = amqp_login (conf->connection, CONF(conf, vhost),
              /* channel max = */      0,
          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);
      }
          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);
      }
@@@ -743,7 -787,7 +789,7 @@@ static int camqp_write (const data_set_
  {
      camqp_config_t *conf = user_data->data;
      char routing_key[6 * DATA_MAX_NAME_LEN];
 -    char buffer[4096];
 +    char buffer[8192];
      int status;
  
      if ((ds == NULL) || (vl == NULL) || (conf == NULL))
@@@ -887,8 -931,6 +933,8 @@@ static int camqp_config_connection (oco
      /* subscribe only */
      conf->exchange_type = NULL;
      conf->queue = NULL;
 +    conf->queue_durable = 0;
 +    conf->queue_auto_delete = 1;
      /* general */
      conf->connection = NULL;
      pthread_mutex_init (&conf->lock, /* attr = */ NULL);
              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 ("QueueDurable", child->key) == 0) && !publish)
 +            status = cf_util_get_boolean (child, &conf->queue_durable);
 +        else if ((strcasecmp ("QueueAutoDelete", child->key) == 0) && !publish)
 +            status = cf_util_get_boolean (child, &conf->queue_auto_delete);
          else if (strcasecmp ("RoutingKey", child->key) == 0)
              status = cf_util_get_string (child, &conf->routing_key);
          else if ((strcasecmp ("Persistent", child->key) == 0) && publish)
diff --combined src/apache.c
@@@ -18,7 -18,7 +18,7 @@@
   * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   *
   * Authors:
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Florent EppO Monbillard <eppo at darox.net>
   *   - connections/lighttpd extension
   *   Amit Gupta <amit.gupta221 at gmail.com>
@@@ -402,7 -402,7 +402,7 @@@ static int init_host (apache_t *st) /* 
                curl_easy_setopt (st->curl, CURLOPT_WRITEHEADER, st);
        }
  
 -      curl_easy_setopt (st->curl, CURLOPT_USERAGENT, PACKAGE_NAME"/"PACKAGE_VERSION);
 +      curl_easy_setopt (st->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT);
        curl_easy_setopt (st->curl, CURLOPT_ERRORBUFFER, st->apache_curl_error);
  
        if (st->user != NULL)
@@@ -671,9 -671,18 +671,18 @@@ static int apache_read_host (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 : */
@@@ -13,6 -13,7 +13,7 @@@ collectd-unixsock - Documentation of co
      SocketFile "/path/to/socket"
      SocketGroup "collectd"
      SocketPerms "0770"
+     DeleteSocket false
    </Plugin>
  
  =head1 DESCRIPTION
@@@ -176,24 -177,11 +177,24 @@@ table. All the options are optional, bu
  or B<type_instance> without B<type> doesn't make much sense and should be
  avoided.
  
 -Please note that this is the same format as used in the B<exec plugin>, see
 -L<collectd-exec(5)>.
 +=item B<type:key=>I<value>
 +
 +Sets user defined meta information. The B<type> key is a single character
 +defining the type of the meta information.
 +
 +The current supported types are:
 +
 +=over 8
 +
 +=item B<s> A string passed as-is.
  
  =back
  
 +=back
 +
 +Please note that this is the same format as used in the B<exec plugin>, see
 +L<collectd-exec(5)>.
 +
  Example:
    -> | PUTNOTIF type=temperature severity=warning time=1201094702 message=The roof is on fire!
    <- | 0 Success
@@@ -255,6 -243,6 +256,6 @@@ L<unix(7)
  
  =head1 AUTHOR
  
 -Florian Forster E<lt>octo@verplant.orgE<gt>
 +Florian Forster E<lt>octo@collectd.orgE<gt>
  
  =cut
diff --combined src/collectd.conf.in
@@@ -52,7 -52,6 +52,7 @@@
  
  @LOAD_PLUGIN_SYSLOG@LoadPlugin syslog
  @LOAD_PLUGIN_LOGFILE@LoadPlugin logfile
 +@LOAD_PLUGIN_LOG_LOGSTASH@LoadPlugin log_logstash
  
  #<Plugin logfile>
  #     LogLevel @DEFAULT_LOG_LEVEL@
  #     PrintSeverity false
  #</Plugin>
  
 +#<Plugin log_logstash>
 +#     LogLevel @DEFAULT_LOG_LEVEL@
 +#     File "@localstatedir@/log/@PACKAGE_NAME@.json.log"
 +#</Plugin>
 +
  #<Plugin syslog>
  #     LogLevel @DEFAULT_LOG_LEVEL@
  #</Plugin>
@@@ -87,7 -81,6 +87,7 @@@
  #@BUILD_PLUGIN_APPLE_SENSORS_TRUE@LoadPlugin apple_sensors
  #@BUILD_PLUGIN_AQUAERO_TRUE@LoadPlugin aquaero
  #@BUILD_PLUGIN_ASCENT_TRUE@LoadPlugin ascent
 +#@BUILD_PLUGIN_BAROMETER_TRUE@LoadPlugin barometer
  #@BUILD_PLUGIN_BATTERY_TRUE@LoadPlugin battery
  #@BUILD_PLUGIN_BIND_TRUE@LoadPlugin bind
  #@BUILD_PLUGIN_CONNTRACK_TRUE@LoadPlugin conntrack
  #@BUILD_PLUGIN_DF_TRUE@LoadPlugin df
  #@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk
  #@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns
 +#@BUILD_PLUGIN_DRBD_TRUE@LoadPlugin drbd
  #@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
  #@BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
  #@BUILD_PLUGIN_ETHSTAT_TRUE@LoadPlugin ethstat
  #@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
  #@BUILD_PLUGIN_WRITE_GRAPHITE_TRUE@LoadPlugin write_graphite
  #@BUILD_PLUGIN_WRITE_HTTP_TRUE@LoadPlugin write_http
 +#@BUILD_PLUGIN_WRITE_KAFKA_TRUE@LoadPlugin write_kafka
  #@BUILD_PLUGIN_WRITE_MONGODB_TRUE@LoadPlugin write_mongodb
  #@BUILD_PLUGIN_WRITE_REDIS_TRUE@LoadPlugin write_redis
  #@BUILD_PLUGIN_WRITE_RIEMANN_TRUE@LoadPlugin write_riemann
 +#@BUILD_PLUGIN_WRITE_TSDB_TRUE@LoadPlugin write_tsdb
  #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
  #@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc
  
  # ription of those options is available in the collectd.conf(5) manual page. #
  ##############################################################################
  
 -#<Plugin "aggregation">
 +#<Plugin aggregation>
  #  <Aggregation>
  #    #Host "unspecified"
  #    Plugin "cpu"
  #  </Aggregation>
  #</Plugin>
  
 -#<Plugin "amqp">
 +#<Plugin amqp>
  #  <Publish "name">
  #    Host "localhost"
  #    Port "5672"
  #     CACert "/etc/ssl/ca.crt"
  #</Plugin>
  
 +#<Plugin "barometer">
 +#   Device            "/dev/i2c-0";
 +#   Oversampling      512
 +#   PressureOffset    0.0
 +#   TemperatureOffset 0.0
 +#   Normalization     2
 +#   Altitude          238.0
 +#   TemperatureSensor "myserver/onewire-F10FCA000800/temperature"
 +#</Plugin>
 +
  #<Plugin "bind">
  #  URL "http://localhost:8053/"
  #  ParseTime       false
  #  </View>
  #</Plugin>
  
- #<Plugin cgroup>
+ #<Plugin cgroups>
  #  CGroup "libvirt"
  #  IgnoreSelected false
  #</Plugin>
  
 +#<Plugin cpu>
 +#  ReportActive false
 +#  ReportByCpu true
 +#  ValuesPercentage false
 +#</Plugin>
 +#
  #<Plugin csv>
  #     DataDir "@localstatedir@/lib/@PACKAGE_NAME@/csv"
  #     StoreRates false
  #  </URL>
  #</Plugin>
  
 -#<Plugin "curl_xml">
 +#<Plugin curl_xml>
  #  <URL "http://localhost/stats.xml">
  #    Host "my_host"
  #    Instance "some_instance"
  #<Plugin disk>
  #     Disk "/^[hs]d[a-f][0-9]?$/"
  #     IgnoreSelected false
 +#     UseBSDName false
 +#     UdevNameAttr "DEVNAME"
  #</Plugin>
  
  #<Plugin dns>
  #     </Directory>
  #</Plugin>
  
 -#<Plugin "gmond">
 +#<Plugin gmond>
  #  MCReceiveFrom "239.2.11.71" "8649"
  #  <Metric "swap_total">
  #    Type "swap"
  #     IgnoreSelected true
  #</Plugin>
  
 -#<Plugin "java">
 +#<Plugin java>
  #     JVMArg "-verbose:jni"
  #     JVMArg "-Djava.class.path=@prefix@/share/collectd/java/collectd-api.jar"
  #
  #     IgnoreSelected false
  #     HostnameFormat name
  #     InterfaceFormat name
 +#     PluginInstanceFormat name
 +#</Plugin>
 +
 +#<Plugin load>
 +#        ReportRelative true
  #</Plugin>
  
  #<Plugin lpar>
  #     </Instance>
  #</Plugin>
  
 +#<Plugin memory>
 +#     ValuesAbsolute true
 +#     ValuesPercentage false
 +#</Plugin>
 +
  #<Plugin modbus>
  #     <Data "data_name">
  #             RegisterBase 1234
  #             Password "secret"
  #             Database "db_name"
  #             MasterStats true
 +#             ConnectTimeout 10
 +#             InnodbStats true
  #     </Database>
  #
  #     <Database db_name2>
 +#             Alias "squeeze"
  #             Host "localhost"
  #             Socket "/var/run/mysql/mysqld.sock"
  #             SlaveStats true
  #  TimerPercentile 90.0
  #</Plugin>
  
 -#<Plugin "swap">
 +#<Plugin swap>
  #     ReportByDevice false
  #     ReportBytes true
 +#     ValuesAbsolute true
 +#     ValuesPercentage false
  #</Plugin>
  
 -#<Plugin "table">
 +#<Plugin table>
  #     <Table "/proc/slabinfo">
  #             Instance "slabinfo"
  #             Separator " "
  #     </Table>
  #</Plugin>
  
 -#<Plugin "tail">
 +#<Plugin tail>
  #  <File "/var/log/exim4/mainlog">
  #    Instance "exim"
 +#    Interval 60
  #    <Match>
  #      Regex "S=([1-9][0-9]*)"
  #      DSType "CounterAdd"
  #  </File>
  #</Plugin>
  
 -#<Plugin "tail_csv">
 +#<Plugin tail_csv>
  #   <Metric "dropped">
  #       Type "percent"
  #       Instance "dropped"
  #             VerifyPeer true
  #             VerifyHost true
  #             CACert "/etc/ssl/ca.crt"
 +#             CAPath "/etc/ssl/certs/"
 +#             ClientKey "/etc/ssl/client.pem"
 +#             ClientCert "/etc/ssl/client.crt"
 +#             ClientKeyPass "secret"
 +#             SSLVersion "TLSv1"
  #             Format "Command"
  #             StoreRates false
  #     </URL>
  #</Plugin>
  
 +#<Plugin write_kafka>
 +#  Property "metadata.broker.list" "localhost:9092"
 +#  <Topic "collectd">
 +#    Format JSON
 +#  </Topic>
 +#</Plugin>
 +
  #<Plugin write_mongodb>
  #     <Node "example">
  #             Host "localhost"
  #             TTLFactor 2.0
  #     </Node>
  #     Tag "foobar"
 +#       Attribute "foo" "bar"
 +#</Plugin>
 +
 +#<Plugin write_tsdb>
 +#     <Node>
 +#             Host "localhost"
 +#             Port "4242"
 +#             HostTags "status=production"
 +#             StoreRates false
 +#             AlwaysAppendDS false
 +#     </Node>
  #</Plugin>
  
  ##############################################################################
  ##############################################################################
  
  #@BUILD_PLUGIN_THRESHOLD_TRUE@LoadPlugin "threshold"
 -#<Plugin "threshold">
 +#<Plugin threshold>
  #  <Type "foo">
  #    WarningMin    0.00
  #    WarningMax 1000.00
diff --combined src/collectd.conf.pod
@@@ -9,14 -9,14 +9,14 @@@ collectd.conf - Configuration for the s
    BaseDir "/path/to/data/"
    PIDFile "/path/to/pidfile/collectd.pid"
    Server  "123.123.123.123" 12345
 -  
 +
    LoadPlugin cpu
    LoadPlugin load
 -  
 +
    <LoadPlugin df>
      Interval 3600
    </LoadPlugin>
 -  
 +
    LoadPlugin ping
    <Plugin ping>
      Host "example.org"
@@@ -341,10 -341,10 +341,10 @@@ The full example configuration looks li
     <Aggregation>
       Plugin "cpu"
       Type "cpu"
 -     
 +
       GroupBy "Host"
       GroupBy "TypeInstance"
 -     
 +
       CalculateSum true
       CalculateAverage true
     </Aggregation>
@@@ -420,13 -420,13 +420,13 @@@ The following example calculates the av
       Plugin "cpu"
       PluginInstance "/[0,2,4,6,8]$/"
       Type "cpu"
 -     
 +
       SetPlugin "cpu"
       SetPluginInstance "even-%{aggregation}"
 -     
 +
       GroupBy "Host"
       GroupBy "TypeInstance"
 -     
 +
       CalculateAverage true
     </Aggregation>
   </Plugin>
@@@ -494,8 -494,10 +494,10 @@@ possibly filtering or messages
   #   StoreRates false
   #   GraphitePrefix "collectd."
   #   GraphiteEscapeChar "_"
+  #   GraphiteSeparateInstances false
+  #   GraphiteAlwaysAppendDS false
     </Publish>
 -   
 +
     # Receive values from an AMQP broker
     <Subscribe "some_name">
       Host "localhost"
       Exchange "amq.fanout"
   #   ExchangeType "fanout"
   #   Queue "queue_name"
 + #   QueueDurable false
 + #   QueueAutoDelete true
   #   RoutingKey "collectd.#"
     </Subscribe>
   </Plugin>
@@@ -560,23 -560,9 +562,23 @@@ 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
 +Configures the I<queue> name to subscribe to. If no queue name was configured
  explicitly, a unique queue name will be created by the broker.
  
 +=item B<QueueDurable> B<true>|B<false> (Subscribe only)
 +
 +Defines if the I<queue> subscribed to is durable (saved to persistent storage)
 +or transient (will disappear if the AMQP broker is restarted). Defaults to
 +"false".
 +
 +This option should be used in conjunction with the I<Persistent> option on the
 +publish side.
 +
 +=item B<QueueAutoDelete> B<true>|B<false> (Subscribe only)
 +
 +Defines if the I<queue> subscribed to will be deleted once the last consumer
 +unsubscribes. Defaults to "true".
 +
  =item B<RoutingKey> I<Key>
  
  In I<Publish> blocks, this configures the routing key to set on all outgoing
@@@ -647,6 -633,19 +649,19 @@@ In I<Graphite> metric name, dots are us
  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>
@@@ -812,131 -811,6 +827,131 @@@ and are checked by default depends on t
  
  =back
  
 +=head2 Plugin C<barometer>
 +
 +This plugin reads absolute air pressure using digital barometer sensor MPL115A2
 +or MPL3115 from Freescale (sensor attached to any I2C bus available in
 +the computer, for HW details see 
 +I<http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPL115A> or
 +I<http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPL3115A2>).
 +The sensor type - one fo these two - is detected automatically by the plugin
 +and indicated in the plugin_instance (typically you will see subdirectory
 +"barometer-mpl115" or "barometer-mpl3115").
 +
 +The plugin provides absolute barometric pressure, air pressure reduced to sea
 +level (several possible approximations) and as an auxiliary value also internal
 +sensor temperature. It uses (expects/provides) typical metric units - pressure
 +in [hPa], temperature in [C], altitude in [m].
 +
 +It was developed and tested under Linux only. The only platform dependency is
 +the standard Linux i2c-dev interface (the particular bus driver has to
 +support the SM Bus command subset).
 +
 +The reduction or normalization to mean sea level pressure requires (depedning on
 +selected method/approximation) also altitude and reference to temperature sensor(s).
 +When multiple temperature sensors are configured the minumum of their values is
 +always used (expecting that the warmer ones are affected by e.g. direct sun light
 +at that moment).
 +
 +Synopsis:
 +
 +  <Plugin "barometer">
 +     Device            "/dev/i2c-0";
 +     Oversampling      512
 +     PressureOffset    0.0
 +     TemperatureOffset 0.0
 +     Normalization     2
 +     Altitude          238.0
 +     TemperatureSensor "myserver/onewire-F10FCA000800/temperature"
 +  </Plugin>
 +
 +=over 4
 +
 +=item B<Device> I<device>
 +
 +Device name of the I2C bus to which the sensor is connected. Note that typically
 +you need to have loaded the i2c-dev module.
 +Using i2c-tools you can check/list i2c buses available on your system by:
 +
 +  i2cdetect -l
 +
 +Then you can scan for devices on given bus. E.g. to scan the whole bus 0 use:
 +
 +  i2cdetect -y -a 0
 +
 +This way you should be able to verify that the pressure sensor (either type) is
 +connected and detected on address 0x60.
 +
 +=item B<Oversampling> I<value>
 +
 +For MPL115 this is the size of the averaging window. To filter out sensor noise
 +a simple averaging using floating window of configurable size is used. The plugin
 +will use average of the last C<value> measurements (value of 1 means no averaging).
 +Minimal size is 1, maximal 1024.
 +
 +For MPL3115 this is the oversampling value. The actual oversampling is performed
 +by the sensor and the higher value the higher accuracy and longer conversion time
 +(although nothing to worry about in the collectd context). Supported values are:
 +1, 2, 4, 8, 16, 32, 64 and 128. Any other value is adjusted by the plugin to
 +the closest supported one. Default is 128.
 +
 +=item B<PressureOffset> I<offset>
 +
 +You can further calibrate the sensor by supplying pressure and/or temperature offsets.
 +This is added to the measured/caclulated value (i.e. if the measured value is too high
 +then use negative offset).
 +In hPa, default is 0.0.
 +
 +=item B<TemperatureOffset> I<offset>
 +
 +You can further calibrate the sensor by supplying pressure and/or temperature offsets.
 +This is added to the measured/caclulated value (i.e. if the measured value is too high
 +then use negative offset).
 +In C, default is 0.0.
 +
 +=item B<Normalization> I<method>
 +
 +Normalization method - what approximation/model is used to compute mean sea
 +level pressure from the air absolute pressure.
 +
 +Supported values of the C<method> (integer between from 0 to 2) are:
 +
 +=over 5
 +
 +=item B<0> - no conversion, absolute pressrure is simply copied over. For this method you
 +       do not need to configure C<Altitude> or C<TemperatureSensor>.
 +
 +=item B<1> - international formula for conversion ,
 +See I<http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation>.
 +For this method you have to configure C<Altitude> but do not need C<TemperatureSensor>
 +(uses fixed global temperature average instead).
 +
 +=item B<2> - formula as recommended by the Deutsche Wetterdienst (German
 +Meteorological Service).
 +See I<http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie>
 +For this method you have to configure both  C<Altitude> and C<TemperatureSensor>.
 +
 +=back
 +
 +
 +=item B<Altitude> I<altitude>
 +
 +The altitude (in meters) of the location where you meassure the pressure.
 +
 +=item B<TemperatureSensor> I<reference>
 +
 +Temperature sensor which should be used as a reference when normalizing the pressure.
 +When specified more sensors a minumum is found and uses each time.
 +The temperature reading directly from this pressure sensor/plugin
 +is typically not suitable as the pressure sensor
 +will be probably inside while we want outside temperature. 
 +The collectd reference name is something like
 +<hostname>/<plugin_name>-<plugin_instance>/<type>-<type_instance>
 +(<type_instance> is usually omitted when there is just single value type).
 +Or you can figure it out from the path of the output data files.
 +
 +=back
 +
  =head2 Plugin C<bind>
  
  Starting with BIND 9.5.0, the most widely used DNS server software provides
@@@ -963,17 -837,17 +978,17 @@@ Synopsis
     ParseTime       false
     OpCodes         true
     QTypes          true
 - 
 +
     ServerStats     true
     ZoneMaintStats  true
     ResolverStats   false
     MemoryStats     true
 - 
 +
     <View "_default">
       QTypes        true
       ResolverStats true
       CacheRRSets   true
 - 
 +
       Zone "127.in-addr.arpa/IN"
     </View>
   </Plugin>
@@@ -1114,44 -988,6 +1129,44 @@@ at all, B<all> cgroups are selected
  
  =back
  
 +=head2 Plugin C<conntrack>
 +
 +This plugin collects IP conntrack statistics.
 +
 +=over 4
 +
 +=item B<OldFiles>
 +
 +Assume the B<conntrack_count> and B<conntrack_max> files to be found in
 +F</proc/sys/net/ipv4/netfilter> instead of F</proc/sys/net/netfilter/>.
 +
 +=back
 +
 +=head2 Plugin C<cpu>
 +
 +The I<CPU plugin> collects CPU usage metrics.
 +
 +The following configuration options are available:
 +
 +=over 4
 +
 +=item B<ReportActive> B<false>|B<true>
 +
 +Reports non-idle CPU usage as the "active" value. Defaults to false.
 +
 +=item B<ReportByCpu> B<false>|B<true>
 +
 +When true reports usage for all cores. When false, reports cpu usage
 +aggregated over all cores.
 +Defaults to true.
 +
 +=item B<ValuesPercentage> B<false>|B<true>
 +
 +When true report percentage usage instead of tick values. Defaults to false.
 +
 +=back
 +
 +
  =head2 Plugin C<cpufreq>
  
  This plugin doesn't have any options. It reads
@@@ -1225,10 -1061,6 +1240,10 @@@ Username to use if authorization is req
  
  Password to use if authorization is required to read the page.
  
 +=item B<Digest> B<true>|B<false>
 +
 +Enable HTTP digest authentication.
 +
  =item B<VerifyPeer> B<true>|B<false>
  
  Enable or disable peer SSL certificate verification. See
@@@ -1339,25 -1171,12 +1354,25 @@@ The following options are valid within 
  
  Sets the plugin instance to I<Instance>.
  
 +=item B<Interval> I<Interval>
 +
 +Sets the interval (in seconds) in which the values will be collected from this
 +URL. By default the global B<Interval> setting will be used.
 +
  =item B<User> I<Name>
 +
  =item B<Password> I<Password>
 +
 +=item B<Digest> B<true>|B<false>
 +
  =item B<VerifyPeer> B<true>|B<false>
 +
  =item B<VerifyHost> B<true>|B<false>
 +
  =item B<CACert> I<file>
 +
  =item B<Header> I<Header>
 +
  =item B<Post> I<Body>
  
  These options behave exactly equivalent to the appropriate options of the
@@@ -1446,8 -1265,6 +1461,8 @@@ Examples
  
  =item B<Password> I<Password>
  
 +=item B<Digest> B<true>|B<false>
 +
  =item B<VerifyPeer> B<true>|B<false>
  
  =item B<VerifyHost> B<true>|B<false>
@@@ -1687,16 -1504,6 +1702,16 @@@ it should be able to handle integer an 
  
  There must be at least one B<ValuesFrom> option inside each B<Result> block.
  
 +=item B<MetadataFrom> [I<column0> I<column1> ...]
 +
 +Names the columns whose content is used as metadata for the data sets
 +that are dispatched to the daemon. 
 +
 +The actual data type in the columns is not that important. The plugin will
 +automatically cast the values to the right type if it know how to do that. So
 +it should be able to handle integer an floating point types, as well as strings
 +(if they include a number at the beginning).
 +
  =back
  
  =head3 B<Database> blocks
@@@ -1811,17 -1618,17 +1826,17 @@@ transfer agents and web caches
  
  =item B<ValuesAbsolute> B<true>|B<false>
  
 -Enables or disables reporting of free, used and used disk space in 1K-blocks. 
 -Defaults to true.
 +Enables or disables reporting of free and used disk space in 1K-blocks.
 +Defaults to B<true>.
  
 -=item B<ValuesPercentage> B<true>|B<false>
 +=item B<ValuesPercentage> B<false>|B<true>
  
 -Enables or disables reporting of free, used and used disk space in percentage.
 -Defaults to false.
 +Enables or disables reporting of free and used disk space in percentage.
 +Defaults to B<false>.
  
 -This is useful for deploying collectd on the cloud, where machines with
 -different disk size may exist. Then it is more practical to configure thresholds
 -based on relative disk size.
 +This is useful for deploying I<collectd> on the cloud, where machines with
 +different disk size may exist. Then it is more practical to configure
 +thresholds based on relative disk size.
  
  =back
  
@@@ -1857,20 -1664,6 +1872,20 @@@ collected. If at least one B<Disk> opti
  set to B<false>, B<only> matching disks will be collected. If B<IgnoreSelected>
  is set to B<true>, all disks are collected B<except> the ones matched.
  
 +=item B<UseBSDName> B<true>|B<false>
 +
 +Whether to use the device's "BSD Name", on MacE<nbsp>OSE<nbsp>X, instead of the
 +default major/minor numbers. Requires collectd to be built with Apple's
 +IOKitLib support.
 +
 +=item B<UdevNameAttr> I<Attribute>
 +
 +Attempt to override disk instance name with the value of a specified udev
 +attribute when built with B<libudev>.  If the attribute is not defined for the
 +given device, the default name is used. Example:
 +
 +  UdevNameAttr "DM_NAME"
 +
  =back
  
  =head2 Plugin C<dns>
@@@ -2419,35 -2212,8 +2434,35 @@@ 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.
  
 +=item B<PluginInstanceFormat> B<name|uuid>
 +
 +When the libvirt plugin logs data, it sets the plugin_instance of the collected 
 +data according to this setting. The default is to use the guest name as provided 
 +by the hypervisor, which is equal to setting B<name>.
 +
 +B<uuid> means use the guest's UUID.
 +
  =back
  
 +=head2 Plugin C<load>
 +
 +The I<Load plugin> collects the system load. These numbers give a rough overview
 +over the utilization of a machine. The system load is defined as the number of
 +runnable tasks in the run-queue and is provided by many operating systems as a
 +one, five or fifteen minute average.
 +
 +The following configuration options are available:
 +
 +=over 4
 +
 +=item B<ReportRelative> B<false>|B<true>
 +
 +When enabled, system load divided by number of available CPU cores is reported
 +for intervals 1 min, 5 min and 15 min. Defaults to false.
 +
 +=back
 +
 +
  =head2 Plugin C<logfile>
  
  =over 4
@@@ -2482,34 -2248,6 +2497,34 @@@ B<Note>: There is no need to notify th
  log file (e.E<nbsp>g. when rotating the logs). The plugin reopens the file
  for each line it writes.
  
 +=head2 Plugin C<log_logstash>
 +
 +The I<log logstash plugin> behaves like the logfile plugin but formats
 +messages as JSON events for logstash to parse and input.
 +
 +=over 4
 +
 +=item B<LogLevel> B<debug|info|notice|warning|err>
 +
 +Sets the log-level. If, for example, set to B<notice>, then all events with
 +severity B<notice>, B<warning>, or B<err> will be written to the logfile.
 +
 +Please note that B<debug> is only available if collectd has been compiled with
 +debugging support.
 +
 +=item B<File> I<File>
 +
 +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 I<collectd>
 +is running in foreground- or non-daemon-mode.
 +
 +=back
 +
 +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
@@@ -2683,7 -2421,7 +2698,7 @@@ B<Synopsis:
     ShowCPU true
     ShowCPUCores true
     ShowMemory true
 -   
 +
     ShowTemperatures true
     Temperature vddg
     Temperature vddq
     ShowPower true
     Power total0
     Power total1
 -   IgnoreSelectedPower true   
 +   IgnoreSelectedPower true
   </Plugin>
  
  The following options are valid inside the B<PluginE<nbsp>mic> block:
  
  =item B<ShowCPU> B<true>|B<false>
  
 -If enabled (the default) a sum of the CPU usage accross all cores is reported.
 +If enabled (the default) a sum of the CPU usage across all cores is reported.
  
  =item B<ShowCPUCores> B<true>|B<false>
  
@@@ -2749,7 -2487,7 +2764,7 @@@ Fan I
  
  =item fout
  
 -Fan Out 
 +Fan Out
  
  =item vccp
  
@@@ -2790,11 -2528,11 +2805,11 @@@ Known power names are
  
  =item total0
  
 -Total power utilization averaged over Time Window 0 (uWatts). 
 +Total power utilization averaged over Time Window 0 (uWatts).
  
  =item total1
  
 -Total power utilization averaged over Time Window 0 (uWatts). 
 +Total power utilization averaged over Time Window 0 (uWatts).
  
  =item inst
  
@@@ -2802,55 -2540,34 +2817,55 @@@ Instantaneous power (uWatts)
  
  =item imax
  
 -Max instantaneous power (uWatts). 
 +Max instantaneous power (uWatts).
  
  =item pcie
  
 -PCI-E connector power (uWatts). 
 +PCI-E connector power (uWatts).
  
  =item c2x3
  
 -2x3 connector power (uWatts). 
 +2x3 connector power (uWatts).
  
  =item c2x4
  
 -2x4 connector power (uWatts). 
 +2x4 connector power (uWatts).
  
  =item vccp
  
 -Core rail (uVolts). 
 +Core rail (uVolts).
  
  =item vddg
  
 -Uncore rail (uVolts). 
 +Uncore rail (uVolts).
  
  =item vddq
  
 -Memory subsystem rail (uVolts). 
 +Memory subsystem rail (uVolts).
 +
 +=back
  
  =back
  
 +=head2 Plugin C<memory>
 +
 +The I<memory plugin> provides the following configuration options:
 +
 +=over 4
 +
 +=item B<ValuesAbsolute> B<true>|B<false>
 +
 +Enables or disables reporting of physical memory usage in absolute numbers,
 +i.e. bytes. Defaults to B<true>.
 +
 +=item B<ValuesPercentage> B<false>|B<true>
 +
 +Enables or disables reporting of physical memory usage in percentages, e.g.
 +percent of physical memory used. Defaults to B<false>.
 +
 +This is useful for deploying I<collectd> in a heterogeneous environment in
 +which the sizes of physical memory vary.
 +
  =back
  
  =head2 Plugin C<modbus>
@@@ -2868,19 -2585,19 +2883,19 @@@ B<Synopsis:
     Type voltage
     Instance "input-1"
   </Data>
 - 
 +
   <Data "voltage-input-2">
     RegisterBase 2
     RegisterType float
     Type voltage
     Instance "input-2"
   </Data>
 - 
 +
   <Host "modbus.example.com">
     Address "192.168.0.42"
     Port    "502"
     Interval 60
 -   
 +
     <Slave 1>
       Instance "power-supply"
       Collect  "voltage-input-1"
@@@ -3011,11 -2728,9 +3026,11 @@@ Synopsis
        Password "password"
        Port "3306"
        MasterStats true
 +      ConnectTimeout 10
      </Database>
  
      <Database bar>
 +      Alias "squeeze"
        Host "localhost"
        Socket "/var/run/mysql/mysqld.sock"
        SlaveStats true
@@@ -3030,11 -2745,6 +3045,11 @@@ section "mysql_real_connect()" in the B
  
  =over 4
  
 +=item B<Alias> I<Alias>
 +
 +Alias to use as sender instead of hostname when reporting. This may be useful
 +when having cryptic hostnames.
 +
  =item B<Host> I<Hostname>
  
  Hostname of the database server. Defaults to B<localhost>.
@@@ -3073,11 -2783,6 +3088,11 @@@ only has any effect, if B<Host> is set 
  Otherwise, use the B<Port> option above. See the documentation for the
  C<mysql_real_connect> function for details.
  
 +=item B<InnodbStats> I<true|false>
 +
 +If enabled, metrics about the InnoDB storage engine are collected.
 +Disabled by default.
 +
  =item B<MasterStats> I<true|false>
  
  =item B<SlaveStats> I<true|false>
@@@ -3091,10 -2796,6 +3106,10 @@@ privileges. See the B<User> documentati
  If enabled, the plugin sends a notification if the replication slave I/O and /
  or SQL threads are not running.
  
 +=item B<ConnectTimeout> I<Seconds>
 +
 +Sets the connect timeout for the MySQL client.
 +
  =back
  
  =head2 Plugin C<netapp>
@@@ -3129,7 -2830,7 +3144,7 @@@ Required capabilities are documented be
      User          "username"
      Password      "aef4Aebe"
      Interval      30
 -    
 +
      <WAFL>
        Interval 30
        GetNameCache   true
        GetBufferCache true
        GetInodeCache  true
      </WAFL>
 -    
 +
      <Disks>
        Interval 30
        GetBusy true
      </Disks>
 -    
 +
      <VolumePerf>
        Interval 30
        GetIO      "volume0"
        GetLatency "volume0"
        IgnoreSelectedLatency false
      </VolumePerf>
 -    
 +
      <VolumeUsage>
        Interval 30
        GetCapacity "vol0"
        GetSnapshot "vol3"
        IgnoreSelectedSnapshot false
      </VolumeUsage>
 -    
 +
      <Quota>
        Interval 60
      </Quota>
 -    
 +
      <Snapvault>
        Interval 30
      </Snapvault>
 -    
 +
      <System>
        Interval 30
        GetCPULoad     true
@@@ -3731,7 -3432,7 +3746,7 @@@ signature)
     # Export to an internal server
     # (demonstrates usage without additional options)
     Server "collectd.internal.tld"
 -   
 +
     # Export to an external server
     # (demonstrates usage with signature options)
     <Server "collectd.external.tld">
@@@ -4120,36 -3821,13 +4135,36 @@@ B<EXPERIMENTAL!> See notes below
  The C<onewire> plugin uses the B<owcapi> library from the B<owfs> project
  L<http://owfs.org/> to read sensors connected via the onewire bus.
  
 -Currently only temperature sensors (sensors with the family code C<10>,
 -e.E<nbsp>g. DS1820, DS18S20, DS1920) can be read. If you have other sensors you
 -would like to have included, please send a sort request to the mailing list.
 +It can be used in two possible modes - standard or advanced.
 +
 +In the standard mode only temperature sensors (sensors with the family code
 +C<10>, C<22> and C<28> - e.g. DS1820, DS18S20, DS1920) can be read. If you have
 +other sensors you would like to have included, please send a sort request to
 +the mailing list. You can select sensors to be read or to be ignored depending
 +on the option B<IgnoreSelected>). When no list is provided the whole bus is
 +walked and all sensors are read.
  
  Hubs (the DS2409 chips) are working, but read the note, why this plugin is
  experimental, below.
  
 +In the advanced mode you can configure any sensor to be read (only numerical
 +value) using full OWFS path (e.g. "/uncached/10.F10FCA000800/temperature").
 +In this mode you have to list all the sensors. Neither default bus walk nor
 +B<IgnoreSelected> are used here. Address and type (file) is extracted from
 +the path automatically and should produce compatible structure with the "standard"
 +mode (basically the path is expected as for example
 +"/uncached/10.F10FCA000800/temperature" where it would extract address part
 +"F10FCA000800" and the rest after the slash is considered the type - here
 +"temperature").
 +There are two advantages to this mode - you can access virtually any sensor
 +(not just temperature), select whether to use cached or directly read values
 +and it is slighlty faster. The downside is more complex configuration.
 +
 +The two modes are distinguished automatically by the format of the address.
 +It is not possible to mix the two modes. Once a full path is detected in any
 +B<Sensor> then the whole addressing (all sensors) is considered to be this way
 +(and as standard addresses will fail parsing they will be ignored).
 +
  =over 4
  
  =item B<Device> I<Device>
@@@ -4170,23 -3848,14 +4185,23 @@@ This directive is B<required> and does 
  
  =item B<Sensor> I<Sensor>
  
 -Selects sensors to collect or to ignore, depending on B<IgnoreSelected>, see
 -below. Sensors are specified without the family byte at the beginning, to you'd
 -use C<F10FCA000800>, and B<not> include the leading C<10.> family byte and
 -point.
 +In the standard mode selects sensors to collect or to ignore
 +(depending on B<IgnoreSelected>, see below). Sensors are specified without
 +the family byte at the beginning, so you have to use for example C<F10FCA000800>,
 +and B<not> include the leading C<10.> family byte and point.
 +When no B<Sensor> is configured the whole Onewire bus is walked and all supported
 +sensors (see above) are read.
 +
 +In the advanced mode the B<Sensor> specifies full OWFS path - e.g.
 +C</uncached/10.F10FCA000800/temperature> (or when cached values are OK
 +C</10.F10FCA000800/temperature>). B<IgnoreSelected> is not used.
 +
 +As there can be multiple devices on the bus you can list multiple sensor (use
 +multiple B<Sensor> elements).
  
  =item B<IgnoreSelected> I<true>|I<false>
  
 -If no configuration if given, the B<onewire> plugin will collect data from all
 +If no configuration is given, the B<onewire> plugin will collect data from all
  sensors found. This may not be practical, especially if sensors are added and
  removed regularly. Sometimes, however, it's easier/preferred to collect only
  specific sensors or all sensors I<except> a few specified ones. This option
@@@ -4194,8 -3863,6 +4209,8 @@@ enables you to do that: By setting B<Ig
  B<Sensor> is inverted: All selected interfaces are ignored and all other
  interfaces are collected.
  
 +Used only in the standard mode - see above.
 +
  =item B<Interval> I<Seconds>
  
  Sets the interval in which all sensors should be read. If not specified, the
@@@ -4872,6 -4539,13 +4887,6 @@@ Specify the password to be used when co
  Specify whether to use an SSL connection when contacting the server. The
  following modes are supported:
  
 -=item B<Instance> I<name>
 -
 -Specify the plugin instance name that should be used instead of the database
 -name (which is the default, if this option has not been specified). This
 -allows to query multiple databases of the same name on the same host (e.g.
 -when running multiple database server versions in parallel).
 -
  =over 4
  
  =item I<disable>
@@@ -4892,13 -4566,6 +4907,13 @@@ Use SSL only
  
  =back
  
 +=item B<Instance> I<name>
 +
 +Specify the plugin instance name that should be used instead of the database
 +name (which is the default, if this option has not been specified). This
 +allows to query multiple databases of the same name on the same host (e.g.
 +when running multiple database server versions in parallel).
 +
  =item B<KRBSrvName> I<kerberos_service_name>
  
  Specify the Kerberos service name to use when authenticating with Kerberos 5
@@@ -5685,19 -5352,6 +5700,19 @@@ This option is only available if the I<
  When enabled, the I<swap I/O> is reported in bytes. When disabled, the default,
  I<swap I/O> is reported in pages. This option is available under Linux only.
  
 +=item B<ValuesAbsolute> B<true>|B<false>
 +
 +Enables or disables reporting of absolute swap metrics, i.e. number of I<bytes>
 +available and used. Defaults to B<true>.
 +
 +=item B<ValuesPercentage> B<false>|B<true>
 +
 +Enables or disables reporting of relative swap metrics, i.e. I<percent>
 +available and free. Defaults to B<false>.
 +
 +This is useful for deploying I<collectd> in a heterogeneous environment, where
 +swap sizes differ and you want to specify generic thresholds or similar.
 +
  =back
  
  =head2 Plugin C<syslog>
@@@ -5833,7 -5487,6 +5848,7 @@@ user using (extended) regular expressio
    <Plugin "tail">
      <File "/var/log/exim4/mainlog">
        Instance "exim"
 +      Interval 60
        <Match>
          Regex "S=([1-9][0-9]*)"
          DSType "CounterAdd"
@@@ -5860,9 -5513,6 +5875,9 @@@ This plugin instance is for all B<Match
  next B<Instance> option. This way you can extract several plugin instances from
  one logfile, handy when parsing syslog and the like.
  
 +The B<Interval> option allows you to define the length of time between reads. If
 +this is not set, the default Interval will be used.
 +
  Each B<Match> block has the following options to describe how the match should
  be performed:
  
@@@ -6512,65 -6162,12 +6527,65 @@@ instance) are put into one component, f
  
  =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.
  
  =back
  
 +=head2 Plugin C<write_tsdb>
 +
 +The C<write_tsdb> plugin writes data to I<OpenTSDB>, a scalable open-source
 +time series database. The plugin connects to a I<TSD>, a masterless, no shared
 +state daemon that ingests metrics and stores them in HBase. The plugin uses
 +I<TCP> over the "line based" protocol with a default port 4242. The data will
 +be sent in blocks of at most 1428 bytes to minimize the number of network
 +packets.
 +
 +Synopsis:
 +
 + <Plugin write_tsdb>
 +   <Node "example">
 +     Host "tsd-1.my.domain"
 +     Port "4242"
 +     HostTags "status=production"
 +   </Node>
 + </Plugin>
 +
 +The configuration consists of one or more E<lt>B<Node>E<nbsp>I<Name>E<gt>
 +blocks. Inside the B<Node> blocks, the following options are recognized:
 +
 +=over 4
 +
 +=item B<Host> I<Address>
 +
 +Hostname or address to connect to. Defaults to C<localhost>.
 +
 +=item B<Port> I<Service>
 +
 +Service name or port number to connect to. Defaults to C<4242>.
 +
 +
 +=item B<HostTags> I<String>
 +
 +When set, I<HostTags> is added to the end of the metric. It is intended to be
 +used for name=value pairs that the TSD will tag the metric with. Dots and
 +whitespace are I<not> escaped in this string.
 +
 +=item B<StoreRates> B<false>|B<true>
 +
 +If set to B<true>, convert counter values to rates. If set to B<false>
 +(the default) counter values are stored as is, as an increasing
 +integer number.
 +
 +=item B<AlwaysAppendDS> B<false>|B<true>
 +
 +If set the 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<write_mongodb>
  
  The I<write_mongodb plugin> will send values to I<MongoDB>, a schema-less
@@@ -6672,33 -6269,6 +6687,33 @@@ File that holds one or more SSL certifi
  possibly need this option. What CA certificates come bundled with C<libcurl>
  and are checked by default depends on the distribution you use.
  
 +=item B<CAPath> I<Directory>
 +
 +Directory holding one or more CA certificate files. You can use this if for
 +some reason all the needed CA certificates aren't in the same file and can't be
 +pointed to using the B<CACert> option. Requires C<libcurl> to be built against
 +OpenSSL.
 +
 +=item B<ClientKey> I<File>
 +
 +File that holds the private key in PEM format to be used for certificate-based
 +authentication.
 +
 +=item B<ClientCert> I<File>
 +
 +File that holds the SSL certificate to be used for certificate-based
 +authentication.
 +
 +=item B<ClientKeyPass> I<Password>
 +
 +Password required to load the private key in B<ClientKey>.
 +
 +=item B<SSLVersion> B<SSLv2>|B<SSLv3>|B<TLSv1>|B<TLSv1_0>|B<TLSv1_1>|B<TLSv1_2>
 +
 +Define which SSL protocol version must be used. By default C<libcurl> will
 +attempt to figure out the remote SSL protocol version. See
 +L<curl_easy_setopt(3)> for more details.
 +
  =item B<Format> B<Command>|B<JSON>
  
  Format of the output to generate. If set to B<Command>, will create output that
@@@ -6715,114 -6285,9 +6730,114 @@@ number
  
  =back
  
 +=head2 Plugin C<write_kafka>
 +
 +The I<write_kafka plugin> will send values to a I<Kafka> topic, a distributed
 +queue.
 +Synopsis:
 +
 + <Plugin "write_kafka">
 +   Property "metadata.broker.list" "broker1:9092,broker2:9092"
 +   <Topic "collectd">
 +     Format JSON
 +   </Topic>
 + </Plugin>
 +
 +The following options are understood by the I<write_kafka plugin>:
 +
 +=over 4
 +
 +=item E<lt>B<Topic> I<Name>E<gt>
 +
 +The plugin's configuration consists of one or more B<Topic> blocks. Each block
 +is given a unique I<Name> and specifies one kafka producer.
 +Inside the B<Topic> block, the following per-topic options are
 +understood:
 +
 +=over 4
 +
 +=item B<Property> I<String> I<String>
 +
 +Configure the named property for the current topic. Properties are
 +forwarded to the kafka producer library B<librdkafka>.
 +
 +=item B<Key> I<String>
 +
 +Use the specified string as a partioning key for the topic. Kafka breaks
 +topic into partitions and guarantees that for a given topology, the same
 +consumer will be used for a specific key. The special (case insensitive)
 +string B<Random> can be used to specify that an arbitrary partition should
 +be used.
 +
 +=item B<Format> B<Command>|B<JSON>|B<Graphite>
 +
 +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>.
 +
 +If set to B<JSON>, the values are encoded in the I<JavaScript Object Notation>,
 +an easy and straight forward exchange format.
 +
 +If set to B<Graphite>, values are encoded in the I<Graphite> format, which is
 +"<metric> <value> <timestamp>\n".
 +
 +=item B<StoreRates> B<true>|B<false>
 +
 +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>.
 +
 +=item B<GraphitePrefix> (B<Format>=I<Graphite> only)
 +
 +A prefix can be added in the metric name when outputting in the I<Graphite> format.
 +It's added before the I<Host> name.
 +Metric name will be "<prefix><host><postfix><plugin><type><name>"
 +
 +=item B<GraphitePostfix> (B<Format>=I<Graphite> only)
 +
 +A postfix can be added in the metric name when outputting in the I<Graphite> format.
 +It's added after the I<Host> name.
 +Metric name will be "<prefix><host><postfix><plugin><type><name>"
 +
 +=item B<GraphiteEscapeChar> (B<Format>=I<Graphite> only)
 +
 +Specify a character to replace dots (.) in the host part of the metric name.
 +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<false>|B<true>
 +
 +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<StoreRates> B<true>|B<false>
 +
 +If set to B<true> (the default), convert counter values to rates. If set to
 +B<false> counter values are stored as is, i.e. as an increasing integer number.
 +
 +This will be reflected in the C<ds_type> tag: If B<StoreRates> is enabled,
 +converted values will have "rate" appended to the data source type, e.g.
 +C<ds_type:derive:rate>.
 +
 +=back
 +
 +=item B<Property> I<String> I<String>
 +
 +Configure the kafka producer through properties, you almost always will
 +want to set B<metadata.broker.list> to your Kafka broker list.
 +
 +=back
 +
  =head2 Plugin C<write_riemann>
  
 -The I<write_riemann plugin> will send values to I<Riemann>, a powerfull stream
 +The I<write_riemann plugin> will send values to I<Riemann>, a powerful stream
  aggregation and monitoring system. The plugin sends I<Protobuf> encoded data to
  I<Riemann> using UDP packets.
  
@@@ -6838,7 -6303,6 +6853,7 @@@ Synopsis
       TTLFactor 2.0
     </Node>
     Tag "foobar"
 +   Attribute "foo" "bar"
   </Plugin>
  
  The following options are understood by the I<write_riemann plugin>:
@@@ -6892,17 -6356,6 +6907,17 @@@ interval is multiplied to set the TTL. 
  know exactly what you're doing, you should only increase this setting from its
  default value.
  
 +=item B<Notifications> B<false>|B<true>
 +
 +If set to B<true>, create riemann events for notifications. This is B<true>
 +by default. When processing thresholds from write_riemann, it might prove
 +useful to avoid getting notification events.
 +
 +=item B<CheckThresholds> B<false>|B<true>
 +
 +If set to B<true>, attach state to events based on thresholds defined
 +in the B<Threshold> plugin. Defaults to B<false>.
 +
  =back
  
  =item B<Tag> I<String>
  Add the given string as an additional tag to the metric being sent to
  I<Riemann>.
  
 +=item B<Attribute> I<String> I<String>
 +
 +Consider the two given strings to be the key and value of an additional
 +attribute for each metric being sent out to I<Riemann>.
 +
  =back
  
  =head1 THRESHOLD CONFIGURATION
@@@ -7387,19 -6835,36 +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
@@@ -7569,7 -7034,7 +7601,7 @@@ Example
     Max 100
     Satisfy "All"
   </Match>
 - 
 +
   # Match if the value of any data source is outside the range of 0 - 100.
   <Match "value">
     Min   0
@@@ -7751,7 -7216,7 +7783,7 @@@ Example
   <Target "replace">
     # Replace "example.net" with "example.com"
     Host "\\<example.net\\>" "example.com"
 - 
 +
     # Strip "www." from hostnames
     Host "\\<www\\." ""
   </Target>
@@@ -7834,6 -7299,6 +7866,6 @@@ L<sensors(1)
  
  =head1 AUTHOR
  
 -Florian Forster E<lt>octo@verplant.orgE<gt>
 +Florian Forster E<lt>octo@collectd.orgE<gt>
  
  =cut
diff --combined src/common.c
@@@ -1,24 -1,19 +1,24 @@@
  /**
   * collectd - src/common.c
 - * Copyright (C) 2005-2010  Florian octo Forster
 + * Copyright (C) 2005-2014  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.
 + * 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:
   *
 - * 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.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * 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
 + * 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 octo Forster <octo at collectd.org>
@@@ -382,10 -377,8 +382,10 @@@ int strunescape (char *buf, size_t buf_
                if (buf[i] != '\\')
                        continue;
  
 -              if ((i >= buf_len) || (buf[i + 1] == '\0')) {
 +              if (((i + 1) >= buf_len) || (buf[i + 1] == 0)) {
                        ERROR ("string unescape: backslash found at end of string.");
 +                      /* Ensure null-byte at the end of the buffer. */
 +                      buf[i] = 0;
                        return (-1);
                }
  
                                break;
                }
  
 +              /* Move everything after the position one position to the left.
 +               * Add a null-byte as last character in the buffer. */
                memmove (buf + i + 1, buf + i + 2, buf_len - i - 2);
 +              buf[buf_len - 1] = 0;
        }
        return (0);
  } /* int strunescape */
@@@ -428,36 -418,34 +428,36 @@@ size_t strstripnewline (char *buffer
        return (buffer_len);
  } /* size_t strstripnewline */
  
 -int escape_slashes (char *buf, int buf_len)
 +int escape_slashes (char *buffer, size_t buffer_size)
  {
        int i;
 +      size_t buffer_len;
  
 -      if (strcmp (buf, "/") == 0)
 -      {
 -              if (buf_len < 5)
 -                      return (-1);
 +      buffer_len = strlen (buffer);
  
 -              strncpy (buf, "root", buf_len);
 +      if (buffer_len <= 1)
 +      {
 +              if (strcmp ("/", buffer) == 0)
 +              {
 +                      if (buffer_size < 5)
 +                              return (-1);
 +                      sstrncpy (buffer, "root", buffer_size);
 +              }
                return (0);
        }
  
 -      if (buf_len <= 1)
 -              return (0);
 -
        /* Move one to the left */
 -      if (buf[0] == '/')
 -              memmove (buf, buf + 1, buf_len - 1);
 +      if (buffer[0] == '/')
 +      {
 +              memmove (buffer, buffer + 1, buffer_len);
 +              buffer_len--;
 +      }
  
 -      for (i = 0; i < buf_len - 1; i++)
 +      for (i = 0; i < buffer_len - 1; i++)
        {
 -              if (buf[i] == '\0')
 -                      break;
 -              else if (buf[i] == '/')
 -                      buf[i] = '_';
 +              if (buffer[i] == '/')
 +                      buffer[i] = '_';
        }
 -      buf[i] = '\0';
  
        return (0);
  } /* int escape_slashes */
@@@ -660,7 -648,7 +660,7 @@@ int get_kstat (kstat_t **ksp_ptr, char 
        char ident[128];
  
        *ksp_ptr = NULL;
 -      
 +
        if (kc == NULL)
                return (-1);
  
@@@ -1073,9 -1061,9 +1073,9 @@@ int parse_value (const char *value_orig
    }
  
    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))
@@@ -1246,7 -1234,7 +1246,7 @@@ int walk_directory (const char *dir, di
        while ((ent = readdir (dh)) != NULL)
        {
                int status;
 -              
 +
                if (include_hidden)
                {
                        if ((strcmp (".", ent->d_name) == 0)
@@@ -1409,69 -1397,6 +1409,69 @@@ int rate_to_value (value_t *ret_value, 
        return (0);
  } /* }}} value_t rate_to_value */
  
 +int value_to_rate (value_t *ret_rate, derive_t value, /* {{{ */
 +              value_to_rate_state_t *state,
 +              int ds_type, cdtime_t t)
 +{
 +      double interval;
 +
 +      /* Another invalid state: The time is not increasing. */
 +      if (t <= state->last_time)
 +      {
 +              memset (state, 0, sizeof (*state));
 +              return (EINVAL);
 +      }
 +
 +      interval = CDTIME_T_TO_DOUBLE(t - state->last_time);
 +
 +      /* Previous value is invalid. */
 +      if (state->last_time == 0) /* {{{ */
 +      {
 +              if (ds_type == DS_TYPE_DERIVE)
 +              {
 +                      state->last_value.derive = value;
 +              }
 +              else if (ds_type == DS_TYPE_COUNTER)
 +              {
 +                      state->last_value.counter = (counter_t) value;
 +              }
 +              else if (ds_type == DS_TYPE_ABSOLUTE)
 +              {
 +                      state->last_value.absolute = (absolute_t) value;
 +              }
 +              else
 +              {
 +                      assert (23 == 42);
 +              }
 +
 +              state->last_time = t;
 +              return (EAGAIN);
 +      } /* }}} */
 +
 +      if (ds_type == DS_TYPE_DERIVE)
 +      {
 +              ret_rate->gauge = (value - state->last_value.derive) / interval;
 +              state->last_value.derive = value;
 +      }
 +      else if (ds_type == DS_TYPE_COUNTER)
 +      {
 +              ret_rate->gauge = (((counter_t)value) - state->last_value.counter) / interval;
 +              state->last_value.counter = (counter_t) value;
 +      }
 +      else if (ds_type == DS_TYPE_ABSOLUTE)
 +      {
 +              ret_rate->gauge = (((absolute_t)value) - state->last_value.absolute) / interval;
 +              state->last_value.absolute = (absolute_t) value;
 +      }
 +      else
 +      {
 +              assert (23 == 42);
 +      }
 +
 +        state->last_time = t;
 +      return (0);
 +} /* }}} value_t rate_to_value */
 +
  int service_name_to_port_number (const char *service_name)
  {
        struct addrinfo *ai_list;
diff --combined src/configfile.c
@@@ -2,23 -2,19 +2,23 @@@
   * collectd - src/configfile.c
   * Copyright (C) 2005-2011  Florian octo Forster
   *
 - * This program is free software; you can redistribute it and/or modify it
 - * under the terms of the GNU General Public License as published by the
 - * Free Software Foundation; either version 2 of the License, or (at your
 - * option) any later version.
 + * 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:
   *
 - * 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.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * 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
 + * 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 octo Forster <octo at collectd.org>
@@@ -481,6 -477,12 +481,12 @@@ static int cf_ci_replace_child (oconfig
  
        /* 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 -597,8 +601,8 @@@ static int cf_include_all (oconfig_item
                        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;
@@@ -895,13 -898,6 +902,13 @@@ int global_option_set (const char *opti
        if (i >= cf_global_options_num)
                return (-1);
  
 +      if (strcasecmp (option, "PIDFile") == 0 && pidfile_from_cli == 1)
 +      {
 +              DEBUG ("Configfile: Ignoring `PIDFILE' option because "
 +                      "command-line option `-P' take precedence.");
 +              return (0);
 +      }
 +
        sfree (cf_global_options[i].value);
  
        if (value != NULL)
diff --combined src/curl.c
@@@ -17,7 -17,7 +17,7 @@@
   * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   *
   * Authors:
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Aman Gupta <aman at tmm1.net>
   **/
  
@@@ -58,7 -58,6 +58,7 @@@ struct web_page_s /* {{{ *
    char *user;
    char *pass;
    char *credentials;
 +  _Bool digest;
    _Bool verify_peer;
    _Bool verify_host;
    char *cacert;
@@@ -365,7 -364,8 +365,7 @@@ static int cc_page_init_curl (web_page_
    curl_easy_setopt (wp->curl, CURLOPT_NOSIGNAL, 1L);
    curl_easy_setopt (wp->curl, CURLOPT_WRITEFUNCTION, cc_curl_callback);
    curl_easy_setopt (wp->curl, CURLOPT_WRITEDATA, wp);
 -  curl_easy_setopt (wp->curl, CURLOPT_USERAGENT,
 -      PACKAGE_NAME"/"PACKAGE_VERSION);
 +  curl_easy_setopt (wp->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT);
    curl_easy_setopt (wp->curl, CURLOPT_ERRORBUFFER, wp->curl_errbuf);
    curl_easy_setopt (wp->curl, CURLOPT_URL, wp->url);
    curl_easy_setopt (wp->curl, CURLOPT_FOLLOWLOCATION, 1L);
      ssnprintf (wp->credentials, credentials_size, "%s:%s",
          wp->user, (wp->pass == NULL) ? "" : wp->pass);
      curl_easy_setopt (wp->curl, CURLOPT_USERPWD, wp->credentials);
 +    
 +    if (wp->digest)
 +    {
 +      curl_easy_setopt (wp->curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
 +      curl_easy_setopt (wp->curl, CURLOPT_USERNAME, wp->user);
 +      curl_easy_setopt (wp->curl, CURLOPT_PASSWORD, wp->pass);
 +    }
    }
  
    curl_easy_setopt (wp->curl, CURLOPT_SSL_VERIFYPEER, (long) wp->verify_peer);
@@@ -433,7 -426,6 +433,7 @@@ static int cc_config_add_page (oconfig_
    page->url = NULL;
    page->user = NULL;
    page->pass = NULL;
 +  page->digest = 0;
    page->verify_peer = 1;
    page->verify_host = 1;
    page->response_time = 0;
        status = cf_util_get_string (child, &page->user);
      else if (strcasecmp ("Password", child->key) == 0)
        status = cf_util_get_string (child, &page->pass);
 +    else if (strcasecmp ("Digest", child->key) == 0)
 +      status = cf_util_get_boolean (child, &page->digest);
      else if (strcasecmp ("VerifyPeer", child->key) == 0)
        status = cf_util_get_boolean (child, &page->verify_peer);
      else if (strcasecmp ("VerifyHost", child->key) == 0)
@@@ -579,6 -569,7 +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 */
  
diff --combined src/curl_json.c
@@@ -71,13 -71,11 +71,13 @@@ struct cj_s /* {{{ *
    char *user;
    char *pass;
    char *credentials;
 +  _Bool digest;
    _Bool verify_peer;
    _Bool verify_host;
    char *cacert;
    struct curl_slist *headers;
    char *post_body;
 +  cdtime_t interval;
  
    CURL *curl;
    char curl_errbuf[CURL_ERROR_SIZE];
@@@ -589,7 -587,8 +589,7 @@@ static int cj_init_curl (cj_t *db) /* {
    curl_easy_setopt (db->curl, CURLOPT_NOSIGNAL, 1L);
    curl_easy_setopt (db->curl, CURLOPT_WRITEFUNCTION, cj_curl_callback);
    curl_easy_setopt (db->curl, CURLOPT_WRITEDATA, db);
 -  curl_easy_setopt (db->curl, CURLOPT_USERAGENT,
 -                    PACKAGE_NAME"/"PACKAGE_VERSION);
 +  curl_easy_setopt (db->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT);
    curl_easy_setopt (db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf);
    curl_easy_setopt (db->curl, CURLOPT_URL, db->url);
  
      ssnprintf (db->credentials, credentials_size, "%s:%s",
                 db->user, (db->pass == NULL) ? "" : db->pass);
      curl_easy_setopt (db->curl, CURLOPT_USERPWD, db->credentials);
 +    
 +    if (db->digest)
 +    {
 +      curl_easy_setopt (db->curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
 +      curl_easy_setopt (db->curl, CURLOPT_USERNAME, db->user);
 +      curl_easy_setopt (db->curl, CURLOPT_PASSWORD, db->pass);
 +    }
    }
  
    curl_easy_setopt (db->curl, CURLOPT_SSL_VERIFYPEER, (long) db->verify_peer);
@@@ -684,8 -676,6 +684,8 @@@ static int cj_config_add_url (oconfig_i
        status = cf_util_get_string (child, &db->user);
      else if (db->url && strcasecmp ("Password", child->key) == 0)
        status = cf_util_get_string (child, &db->pass);
 +    else if (strcasecmp ("Digest", child->key) == 0)
 +      status = cf_util_get_boolean (child, &db->digest);
      else if (db->url && strcasecmp ("VerifyPeer", child->key) == 0)
        status = cf_util_get_boolean (child, &db->verify_peer);
      else if (db->url && strcasecmp ("VerifyHost", child->key) == 0)
        status = cf_util_get_string (child, &db->post_body);
      else if (strcasecmp ("Key", child->key) == 0)
        status = cj_config_add_key (db, child);
 +    else if (strcasecmp ("Interval", child->key) == 0)
 +      status = cf_util_get_cdtime(child, &db->interval);
      else
      {
        WARNING ("curl_json plugin: Option `%s' not allowed here.", child->key);
    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);
  
      if (db->instance == NULL)
        db->instance = strdup("default");
      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 = */ "curl_json", cb_name, cj_read,
 -                                  /* interval = */ NULL, &ud);
 +    plugin_register_complex_read (/* group = */ NULL, cb_name, cj_read,
 +                                  /* interval = */ (db->interval > 0) ? &interval : NULL,
 +                                  &ud);
+     sfree (cb_name);
    }
    else
    {
@@@ -816,10 -801,11 +817,10 @@@ static void cj_submit (cj_t *db, cj_key
  
    if (key->instance == NULL)
    {
 -    if ((db->depth == 0) || (strcmp ("", db->state[db->depth-1].name) == 0))
 -      sstrncpy (vl.type_instance, db->state[db->depth].name, sizeof (vl.type_instance));
 -    else
 -      ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s",
 -          db->state[db->depth-1].name, db->state[db->depth].name);
 +    int i, len = 0;
 +    for (i = 0; i < db->depth; i++)
 +      len += ssnprintf(vl.type_instance+len, sizeof(vl.type_instance)-len,
 +                       i ? "-%s" : "%s", db->state[i+1].name);
    }
    else
      sstrncpy (vl.type_instance, key->instance, sizeof (vl.type_instance));
    sstrncpy (vl.plugin_instance, db->instance, sizeof (vl.plugin_instance));
    sstrncpy (vl.type, key->type, sizeof (vl.type));
  
 +  if (db->interval > 0)
 +    vl.interval = db->interval;
 +
    plugin_dispatch_values (&vl);
  } /* }}} int cj_submit */
  
@@@ -975,9 -958,18 +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 : */
diff --combined src/curl_xml.c
@@@ -76,7 -76,6 +76,7 @@@ struct cx_s /* {{{ *
    char *user;
    char *pass;
    char *credentials;
 +  _Bool digest;
    _Bool verify_peer;
    _Bool verify_host;
    char *cacert;
@@@ -386,7 -385,7 +386,7 @@@ static int cx_handle_instance_xpath (xm
    /* 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), "
@@@ -839,7 -838,8 +839,7 @@@ static int cx_init_curl (cx_t *db) /* {
    curl_easy_setopt (db->curl, CURLOPT_NOSIGNAL, 1L);
    curl_easy_setopt (db->curl, CURLOPT_WRITEFUNCTION, cx_curl_callback);
    curl_easy_setopt (db->curl, CURLOPT_WRITEDATA, db);
 -  curl_easy_setopt (db->curl, CURLOPT_USERAGENT,
 -                    PACKAGE_NAME"/"PACKAGE_VERSION);
 +  curl_easy_setopt (db->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT);
    curl_easy_setopt (db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf);
    curl_easy_setopt (db->curl, CURLOPT_URL, db->url);
  
      ssnprintf (db->credentials, credentials_size, "%s:%s",
                 db->user, (db->pass == NULL) ? "" : db->pass);
      curl_easy_setopt (db->curl, CURLOPT_USERPWD, db->credentials);
 +    
 +    if (db->digest)
 +    {
 +      curl_easy_setopt (db->curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
 +      curl_easy_setopt (db->curl, CURLOPT_USERNAME, db->user);
 +      curl_easy_setopt (db->curl, CURLOPT_PASSWORD, db->pass);
 +    }
    }
  
    curl_easy_setopt (db->curl, CURLOPT_SSL_VERIFYPEER, db->verify_peer ? 1L : 0L);
@@@ -934,8 -927,6 +934,8 @@@ static int cx_config_add_url (oconfig_i
        status = cf_util_get_string (child, &db->user);
      else if (strcasecmp ("Password", child->key) == 0)
        status = cf_util_get_string (child, &db->pass);
 +    else if (strcasecmp ("Digest", child->key) == 0)
 +      status = cf_util_get_boolean (child, &db->digest);
      else if (strcasecmp ("VerifyPeer", child->key) == 0)
        status = cf_util_get_boolean (child, &db->verify_peer);
      else if (strcasecmp ("VerifyHost", child->key) == 0)
@@@ -1042,9 -1033,18 +1042,18 @@@ static int cx_config (oconfig_item_t *c
    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 : */
diff --combined src/exec.c
@@@ -18,7 -18,7 +18,7 @@@
   * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   *
   * Authors:
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Sebastian Harl <sh at tokkee.org>
   *   Peter Holik <peter at holik.at>
   **/
@@@ -744,8 -744,8 +744,8 @@@ static void *exec_notification_one (voi
  
    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)
diff --combined src/lvm.c
+++ b/src/lvm.c
@@@ -1,7 -1,6 +1,7 @@@
  /**
   * collectd - src/lvm.c
   * Copyright (C) 2013       Chad Malfait
 + * Copyright (C) 2014       Carnegie Mellon University
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
@@@ -18,7 -17,6 +18,7 @@@
   *
   * Authors:
   *   Chad Malfait <malfaitc at yahoo.com>
 + *   Benjamin Gilbert <bgilbert at cs.cmu.edu>
   **/
  
  #include <lvm2app.h>
  #include "common.h"
  #include "plugin.h"
  
 +#define NO_VALUE UINT64_MAX
 +#define PERCENT_SCALE_FACTOR 1e-8
 +
 +static uint64_t get_lv_property_int(lv_t lv, char const *property)
 +{
 +    lvm_property_value_t v;
 +
 +    v = lvm_lv_get_property(lv, property);
 +    if (!v.is_valid || !v.is_integer)
 +        return NO_VALUE;
 +    /* May be NO_VALUE if @property does not apply to this LV */
 +    return v.value.integer;
 +}
 +
 +static char const *get_lv_property_string(lv_t lv, char const *property)
 +{
 +    lvm_property_value_t v;
 +
 +    v = lvm_lv_get_property(lv, property);
 +    if (!v.is_valid || !v.is_string)
 +        return NULL;
 +    return v.value.string;
 +}
 +
  static void lvm_submit (char const *plugin_instance, char const *type_instance,
          uint64_t ivalue)
  {
      plugin_dispatch_values (&vl);
  }
  
 -static int vg_read(vg_t vg, char const *vg_name)
 +static void report_lv_utilization(lv_t lv, char const *vg_name,
 +        char const *lv_name, uint64_t lv_size,
 +        char const *used_percent_property)
 +{
 +    uint64_t used_percent_unscaled;
 +    uint64_t used_bytes;
 +    char plugin_instance[DATA_MAX_NAME_LEN];
 +
 +    used_percent_unscaled = get_lv_property_int(lv, used_percent_property);
 +    if (used_percent_unscaled == NO_VALUE)
 +        return;
 +    used_bytes = lv_size * (used_percent_unscaled * PERCENT_SCALE_FACTOR);
 +
 +    ssnprintf(plugin_instance, sizeof(plugin_instance), "%s-%s",
 +            vg_name, lv_name);
 +    lvm_submit(plugin_instance, "used", used_bytes);
 +    lvm_submit(plugin_instance, "free", lv_size - used_bytes);
 +}
 +
 +static void report_thin_pool_utilization(lv_t lv, char const *vg_name,
 +        uint64_t lv_size)
 +{
 +    char const *data_lv;
 +    char const *metadata_lv;
 +    uint64_t metadata_size;
 +
 +    data_lv = get_lv_property_string(lv, "data_lv");
 +    metadata_lv = get_lv_property_string(lv, "metadata_lv");
 +    metadata_size = get_lv_property_int(lv, "lv_metadata_size");
 +    if (data_lv == NULL || metadata_lv == NULL || metadata_size == NO_VALUE)
 +        return;
 +
 +    report_lv_utilization(lv, vg_name, data_lv, lv_size, "data_percent");
 +    report_lv_utilization(lv, vg_name, metadata_lv, metadata_size,
 +            "metadata_percent");
 +}
 +
 +static void vg_read(vg_t vg, char const *vg_name)
  {
      struct dm_list *lvs;
      struct lvm_lv_list *lvl;
 +    char const *name;
 +    char const *attrs;
 +    uint64_t size;
  
      lvm_submit (vg_name, "free", lvm_vg_get_free_size(vg));
  
      lvs = lvm_vg_list_lvs(vg);
      if (!lvs) {
          /* no VGs are defined, which is not an error per se */
 -        return (0);
 +        return;
      }
  
      dm_list_iterate_items(lvl, lvs) {
 -    return (0);
+          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);
 +        if (name == NULL || attrs == NULL || size == NO_VALUE)
 +            continue;
 +
 +        /* Condition on volume type.  We want the reported sizes in the
 +           volume group to sum to the size of the volume group, so we ignore
 +           virtual volumes.  */
 +        switch (attrs[0]) {
 +            case 's':
 +            case 'S':
 +                /* Snapshot.  Also report used/free space. */
 +                report_lv_utilization(lvl->lv, vg_name, name, size,
 +                        "data_percent");
 +                break;
 +            case 't':
 +                /* Thin pool virtual volume.  We report the underlying data
 +                   and metadata volumes, not this one.  Report used/free
 +                   space, then ignore. */
 +                report_thin_pool_utilization(lvl->lv, vg_name, size);
 +                continue;
 +            case 'v':
 +                /* Virtual volume.  Ignore. */
 +                continue;
 +            case 'V':
 +                /* Thin volume or thin snapshot.  Ignore. */
 +                continue;
 +        }
 +        lvm_submit(vg_name, name, size);
 +    }
  }
  
  static int lvm_read(void)
diff --combined src/network.c
@@@ -501,8 -501,15 +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 */
@@@ -2897,10 -2904,6 +2904,10 @@@ static int network_config_set_ttl (cons
    tmp = (int) ci->values[0].value.number;
    if ((tmp > 0) && (tmp <= 255))
      network_config_ttl = tmp;
 +  else {
 +    WARNING ("network plugin: The `TimeToLive' must be between 1 and 255.");
 +    return (-1);    
 +  }
  
    return (0);
  } /* }}} int network_config_set_ttl */
@@@ -3163,14 -3166,6 +3170,14 @@@ static int network_config (oconfig_item
  {
    int i;
  
 +  /* The options need to be applied first */
 +  for (i = 0; i < ci->children_num; i++)
 +  {
 +    oconfig_item_t *child = ci->children + i;
 +    if (strcasecmp ("TimeToLive", child->key) == 0)
 +      network_config_set_ttl (child);
 +  }
 +
    for (i = 0; i < ci->children_num; i++)
    {
      oconfig_item_t *child = ci->children + i;
        network_config_add_listen (child);
      else if (strcasecmp ("Server", child->key) == 0)
        network_config_add_server (child);
 -    else if (strcasecmp ("TimeToLive", child->key) == 0)
 -      network_config_set_ttl (child);
 +    else if (strcasecmp ("TimeToLive", child->key) == 0) {
 +      /* Handled earlier */
 +    }
      else if (strcasecmp ("MaxPacketSize", child->key) == 0)
        network_config_set_buffer_size (child);
      else if (strcasecmp ("Forward", child->key) == 0)
diff --combined src/processes.c
@@@ -25,7 -25,7 +25,7 @@@
   *
   * Authors:
   *   Lyonel Vincent <lyonel at ezix.org>
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Oleg King <king2 at kaluga.ru>
   *   Sebastian Harl <sh at tokkee.org>
   *   Andrés J. Díaz <ajdiaz at connectical.com>
@@@ -223,7 -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
diff --combined src/snmp.c
@@@ -2,23 -2,18 +2,23 @@@
   * collectd - src/snmp.c
   * Copyright (C) 2007-2012  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.
 + * 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:
   *
 - * 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.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * 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
 + * 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 octo Forster <octo at collectd.org>
@@@ -34,8 -29,6 +34,8 @@@
  #include <net-snmp/net-snmp-config.h>
  #include <net-snmp/net-snmp-includes.h>
  
 +#include <fnmatch.h>
 +
  /*
   * Private data structes
   */
@@@ -57,7 -50,7 +57,7 @@@ struct data_definition_
  {
    char *name; /* used to reference this from the `Collect' option */
    char *type; /* used to find the data_set */
 -  int is_table;
 +  _Bool is_table;
    instance_t instance;
    char *instance_prefix;
    oid_t *values;
@@@ -65,9 -58,6 +65,9 @@@
    double scale;
    double shift;
    struct data_definition_s *next;
 +  char **ignores;
 +  size_t ignores_len;
 +  int invert_match;
  };
  typedef struct data_definition_s data_definition_t;
  
@@@ -75,22 -65,8 +75,22 @@@ struct host_definition_
  {
    char *name;
    char *address;
 -  char *community;
    int version;
 +
 +  /* snmpv1/2 options */
 +  char *community;
 +
 +  /* snmpv3 security options */
 +  char *username;
 +  oid *auth_protocol;
 +  size_t auth_protocol_len;
 +  char *auth_passphrase;
 +  oid *priv_protocol;
 +  size_t priv_protocol_len;
 +  char *priv_passphrase;
 +  int security_level;
 +  char *context;
 +
    void *sess_handle;
    c_complain_t complaint;
    cdtime_t interval;
@@@ -207,10 -183,6 +207,10 @@@ static void csnmp_host_definition_destr
    sfree (hd->name);
    sfree (hd->address);
    sfree (hd->community);
 +  sfree (hd->username);
 +  sfree (hd->auth_passphrase);
 +  sfree (hd->priv_passphrase);
 +  sfree (hd->context);
    sfree (hd->data_list);
  
    sfree (hd);
   *  csnmp_config
   *  +-> call_snmp_init_once
   *  +-> csnmp_config_add_data
 - *  !   +-> csnmp_config_add_data_type
 - *  !   +-> csnmp_config_add_data_table
   *  !   +-> csnmp_config_add_data_instance
   *  !   +-> csnmp_config_add_data_instance_prefix
   *  !   +-> csnmp_config_add_data_values
   *  +-> csnmp_config_add_host
 - *      +-> csnmp_config_add_host_address
 - *      +-> csnmp_config_add_host_community
   *      +-> csnmp_config_add_host_version
   *      +-> csnmp_config_add_host_collect
 + *      +-> csnmp_config_add_host_auth_protocol
 + *      +-> csnmp_config_add_host_priv_protocol
 + *      +-> csnmp_config_add_host_security_level
   */
  static void call_snmp_init_once (void)
  {
    have_init = 1;
  } /* void call_snmp_init_once */
  
 -static int csnmp_config_add_data_type (data_definition_t *dd, oconfig_item_t *ci)
 -{
 -  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
 -  {
 -    WARNING ("snmp plugin: `Type' needs exactly one string argument.");
 -    return (-1);
 -  }
 -
 -  sfree (dd->type);
 -  dd->type = strdup (ci->values[0].value.string);
 -  if (dd->type == NULL)
 -    return (-1);
 -
 -  return (0);
 -} /* int csnmp_config_add_data_type */
 -
 -static int csnmp_config_add_data_table (data_definition_t *dd, oconfig_item_t *ci)
 -{
 -  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
 -  {
 -    WARNING ("snmp plugin: `Table' needs exactly one boolean argument.");
 -    return (-1);
 -  }
 -
 -  dd->is_table = ci->values[0].value.boolean ? 1 : 0;
 -
 -  return (0);
 -} /* int csnmp_config_add_data_table */
 -
  static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t *ci)
  {
 -  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
 -  {
 -    WARNING ("snmp plugin: `Instance' needs exactly one string argument.");
 -    return (-1);
 -  }
 +  char buffer[DATA_MAX_NAME_LEN];
 +  int status;
 +
 +  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
 +  if (status != 0)
 +    return status;
  
    if (dd->is_table)
    {
      /* Instance is an OID */
      dd->instance.oid.oid_len = MAX_OID_LEN;
  
 -    if (!read_objid (ci->values[0].value.string,
 +    if (!read_objid (buffer,
            dd->instance.oid.oid, &dd->instance.oid.oid_len))
      {
 -      ERROR ("snmp plugin: read_objid (%s) failed.",
 -          ci->values[0].value.string);
 +      ERROR ("snmp plugin: read_objid (%s) failed.", buffer);
        return (-1);
      }
    }
    else
    {
      /* Instance is a simple string */
 -    sstrncpy (dd->instance.string, ci->values[0].value.string,
 +    sstrncpy (dd->instance.string, buffer,
          sizeof (dd->instance.string));
    }
  
  static int csnmp_config_add_data_instance_prefix (data_definition_t *dd,
      oconfig_item_t *ci)
  {
 -  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
 -  {
 -    WARNING ("snmp plugin: `InstancePrefix' needs exactly one string argument.");
 -    return (-1);
 -  }
 +  int status;
  
    if (!dd->is_table)
    {
      return (-1);
    }
  
 -  sfree (dd->instance_prefix);
 -  dd->instance_prefix = strdup (ci->values[0].value.string);
 -  if (dd->instance_prefix == NULL)
 -    return (-1);
 -
 -  return (0);
 +  status = cf_util_get_string(ci, &dd->instance_prefix);
 +  return status;
  } /* int csnmp_config_add_data_instance_prefix */
  
  static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *ci)
    return (0);
  } /* int csnmp_config_add_data_instance */
  
 -static int csnmp_config_add_data_shift (data_definition_t *dd, oconfig_item_t *ci)
 +static int csnmp_config_add_data_blacklist(data_definition_t *dd, oconfig_item_t *ci)
  {
 -  if ((ci->values_num != 1)
 -      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
 +  int i;
 +
 +  if (ci->values_num < 1)
 +    return (0);
 +
 +  for (i = 0; i < ci->values_num; i++)
    {
 -    WARNING ("snmp plugin: The `Shift' config option needs exactly one number argument.");
 -    return (-1);
 +    if (ci->values[i].type != OCONFIG_TYPE_STRING)
 +    {
 +      WARNING ("snmp plugin: `Ignore' needs only string argument.");
 +      return (-1);
 +    }
    }
  
 -  dd->shift = ci->values[0].value.number;
 +  dd->ignores_len = 0;
 +  dd->ignores = NULL;
  
 -  return (0);
 -} /* int csnmp_config_add_data_shift */
 +  for (i = 0; i < ci->values_num; ++i)
 +  {
 +    if (strarray_add(&(dd->ignores), &(dd->ignores_len), ci->values[i].value.string) != 0)
 +    {
 +      ERROR("snmp plugin: Can't allocate memory");
 +      strarray_free(dd->ignores, dd->ignores_len);
 +      return (ENOMEM); 
 +    }
 +  }
 +  return 0;
 +} /* int csnmp_config_add_data_blacklist */
  
 -static int csnmp_config_add_data_scale (data_definition_t *dd, oconfig_item_t *ci)
 +static int csnmp_config_add_data_blacklist_match_inverted(data_definition_t *dd, oconfig_item_t *ci)
  {
 -  if ((ci->values_num != 1)
 -      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
 +  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
    {
 -    WARNING ("snmp plugin: The `Scale' config option needs exactly one number argument.");
 +    WARNING ("snmp plugin: `InvertMatch' needs exactly one boolean argument.");
      return (-1);
    }
  
 -  dd->scale = ci->values[0].value.number;
 +  dd->invert_match = ci->values[0].value.boolean ? 1 : 0;
  
    return (0);
 -} /* int csnmp_config_add_data_scale */
 +} /* int csnmp_config_add_data_blacklist_match_inverted */
  
  static int csnmp_config_add_data (oconfig_item_t *ci)
  {
    int status = 0;
    int i;
  
 -  if ((ci->values_num != 1)
 -      || (ci->values[0].type != OCONFIG_TYPE_STRING))
 -  {
 -    WARNING ("snmp plugin: The `Data' config option needs exactly one string argument.");
 -    return (-1);
 -  }
 -
    dd = (data_definition_t *) malloc (sizeof (data_definition_t));
    if (dd == NULL)
      return (-1);
    memset (dd, '\0', sizeof (data_definition_t));
  
 -  dd->name = strdup (ci->values[0].value.string);
 -  if (dd->name == NULL)
 +  status = cf_util_get_string(ci, &dd->name);
 +  if (status != 0)
    {
      free (dd);
      return (-1);
    }
 +
    dd->scale = 1.0;
    dd->shift = 0.0;
  
      status = 0;
  
      if (strcasecmp ("Type", option->key) == 0)
 -      status = csnmp_config_add_data_type (dd, option);
 +      status = cf_util_get_string(option, &dd->type);
      else if (strcasecmp ("Table", option->key) == 0)
 -      status = csnmp_config_add_data_table (dd, option);
 +      status = cf_util_get_boolean(option, &dd->is_table);
      else if (strcasecmp ("Instance", option->key) == 0)
        status = csnmp_config_add_data_instance (dd, option);
      else if (strcasecmp ("InstancePrefix", option->key) == 0)
      else if (strcasecmp ("Values", option->key) == 0)
        status = csnmp_config_add_data_values (dd, option);
      else if (strcasecmp ("Shift", option->key) == 0)
 -      status = csnmp_config_add_data_shift (dd, option);
 +      status = cf_util_get_double(option, &dd->shift);
      else if (strcasecmp ("Scale", option->key) == 0)
 -      status = csnmp_config_add_data_scale (dd, option);
 +      status = cf_util_get_double(option, &dd->scale);
 +    else if (strcasecmp ("Ignore", option->key) == 0)
 +      status = csnmp_config_add_data_blacklist(dd, option);
 +    else if (strcasecmp ("InvertMatch", option->key) == 0)
 +      status = csnmp_config_add_data_blacklist_match_inverted(dd, option);
      else
      {
        WARNING ("snmp plugin: Option `%s' not allowed here.", option->key);
      sfree (dd->name);
      sfree (dd->instance_prefix);
      sfree (dd->values);
 +    sfree (dd->ignores);
      sfree (dd);
      return (-1);
    }
    return (0);
  } /* int csnmp_config_add_data */
  
 -static int csnmp_config_add_host_address (host_definition_t *hd, oconfig_item_t *ci)
 -{
 -  if ((ci->values_num != 1)
 -      || (ci->values[0].type != OCONFIG_TYPE_STRING))
 -  {
 -    WARNING ("snmp plugin: The `Address' config option needs exactly one string argument.");
 -    return (-1);
 -  }
 -
 -  if (hd->address == NULL)
 -    free (hd->address);
 -
 -  hd->address = strdup (ci->values[0].value.string);
 -  if (hd->address == NULL)
 -    return (-1);
 -
 -  DEBUG ("snmp plugin: host = %s; host->address = %s;",
 -      hd->name, hd->address);
 -
 -  return (0);
 -} /* int csnmp_config_add_host_address */
 -
 -static int csnmp_config_add_host_community (host_definition_t *hd, oconfig_item_t *ci)
 -{
 -  if ((ci->values_num != 1)
 -      || (ci->values[0].type != OCONFIG_TYPE_STRING))
 -  {
 -    WARNING ("snmp plugin: The `Community' config option needs exactly one string argument.");
 -    return (-1);
 -  }
 -
 -  if (hd->community == NULL)
 -    free (hd->community);
 -
 -  hd->community = strdup (ci->values[0].value.string);
 -  if (hd->community == NULL)
 -    return (-1);
 -
 -  DEBUG ("snmp plugin: host = %s; host->community = %s;",
 -      hd->name, hd->community);
 -
 -  return (0);
 -} /* int csnmp_config_add_host_community */
 -
  static int csnmp_config_add_host_version (host_definition_t *hd, oconfig_item_t *ci)
  {
    int version;
    }
  
    version = (int) ci->values[0].value.number;
 -  if ((version != 1) && (version != 2))
 +  if ((version < 1) || (version > 3))
    {
 -    WARNING ("snmp plugin: `Version' must either be `1' or `2'.");
 +    WARNING ("snmp plugin: `Version' must either be `1', `2', or `3'.");
      return (-1);
    }
  
@@@ -551,92 -590,6 +551,92 @@@ static int csnmp_config_add_host_collec
    return (0);
  } /* int csnmp_config_add_host_collect */
  
 +static int csnmp_config_add_host_auth_protocol (host_definition_t *hd, oconfig_item_t *ci)
 +{
 +  char buffer[4];
 +  int status;
 +
 +  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
 +  if (status != 0)
 +    return status;
 +
 +  if (strcasecmp("MD5", buffer) == 0) {
 +    hd->auth_protocol = usmHMACMD5AuthProtocol;
 +    hd->auth_protocol_len = sizeof(usmHMACMD5AuthProtocol)/sizeof(oid);
 +  }
 +  else if (strcasecmp("SHA", buffer) == 0) {
 +    hd->auth_protocol = usmHMACSHA1AuthProtocol;
 +    hd->auth_protocol_len = sizeof(usmHMACSHA1AuthProtocol)/sizeof(oid);
 +  }
 +  else
 +  {
 +    WARNING ("snmp plugin: The `AuthProtocol' config option must be `MD5' or `SHA'.");
 +    return (-1);
 +  }
 +
 +  DEBUG ("snmp plugin: host = %s; host->auth_protocol = %s;",
 +      hd->name, hd->auth_protocol == usmHMACMD5AuthProtocol ? "MD5" : "SHA");
 +
 +  return (0);
 +} /* int csnmp_config_add_host_auth_protocol */
 +
 +static int csnmp_config_add_host_priv_protocol (host_definition_t *hd, oconfig_item_t *ci)
 +{
 +  char buffer[4];
 +  int status;
 +
 +  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
 +  if (status != 0)
 +    return status;
 +
 +  if (strcasecmp("AES", buffer) == 0)
 +  {
 +    hd->priv_protocol = usmAESPrivProtocol;
 +    hd->priv_protocol_len = sizeof(usmAESPrivProtocol)/sizeof(oid);
 +  }
 +  else if (strcasecmp("DES", buffer) == 0) {
 +    hd->priv_protocol = usmDESPrivProtocol;
 +    hd->priv_protocol_len = sizeof(usmDESPrivProtocol)/sizeof(oid);
 +  }
 +  else
 +  {
 +    WARNING ("snmp plugin: The `PrivProtocol' config option must be `AES' or `DES'.");
 +    return (-1);
 +  }
 +
 +  DEBUG ("snmp plugin: host = %s; host->priv_protocol = %s;",
 +      hd->name, hd->priv_protocol == usmAESPrivProtocol ? "AES" : "DES");
 +
 +  return (0);
 +} /* int csnmp_config_add_host_priv_protocol */
 +
 +static int csnmp_config_add_host_security_level (host_definition_t *hd, oconfig_item_t *ci)
 +{
 +  char buffer[16];
 +  int status;
 +
 +  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
 +  if (status != 0)
 +    return status;
 +
 +  if (strcasecmp("noAuthNoPriv", buffer) == 0)
 +    hd->security_level = SNMP_SEC_LEVEL_NOAUTH;
 +  else if (strcasecmp("authNoPriv", buffer) == 0)
 +    hd->security_level = SNMP_SEC_LEVEL_AUTHNOPRIV;
 +  else if (strcasecmp("authPriv", buffer) == 0)
 +    hd->security_level = SNMP_SEC_LEVEL_AUTHPRIV;
 +  else
 +  {
 +    WARNING ("snmp plugin: The `SecurityLevel' config option must be `noAuthNoPriv', `authNoPriv', or `authPriv'.");
 +    return (-1);
 +  }
 +
 +  DEBUG ("snmp plugin: host = %s; host->security_level = %d;",
 +      hd->name, hd->security_level);
 +
 +  return (0);
 +} /* int csnmp_config_add_host_security_level */
 +
  static int csnmp_config_add_host (oconfig_item_t *ci)
  {
    host_definition_t *hd;
    user_data_t cb_data;
    struct timespec cb_interval;
  
 -  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
 -  {
 -    WARNING ("snmp plugin: `Host' needs exactly one string argument.");
 -    return (-1);
 -  }
 -
    hd = (host_definition_t *) malloc (sizeof (host_definition_t));
    if (hd == NULL)
      return (-1);
    hd->version = 2;
    C_COMPLAIN_INIT (&hd->complaint);
  
 -  hd->name = strdup (ci->values[0].value.string);
 -  if (hd->name == NULL)
 -  {
 -    free (hd);
 -    return (-1);
 -  }
 +  status = cf_util_get_string(ci, &hd->name);
 +  if (status != 0)
 +    return status;
  
    hd->sess_handle = NULL;
    hd->interval = 0;
      status = 0;
  
      if (strcasecmp ("Address", option->key) == 0)
 -      status = csnmp_config_add_host_address (hd, option);
 +      status = cf_util_get_string(option, &hd->address);
      else if (strcasecmp ("Community", option->key) == 0)
 -      status = csnmp_config_add_host_community (hd, option);
 +      status = cf_util_get_string(option, &hd->community);
      else if (strcasecmp ("Version", option->key) == 0)
        status = csnmp_config_add_host_version (hd, option);
      else if (strcasecmp ("Collect", option->key) == 0)
        csnmp_config_add_host_collect (hd, option);
      else if (strcasecmp ("Interval", option->key) == 0)
        cf_util_get_cdtime (option, &hd->interval);
 +    else if (strcasecmp ("Username", option->key) == 0)
 +      status = cf_util_get_string(option, &hd->username);
 +    else if (strcasecmp ("AuthProtocol", option->key) == 0)
 +      status = csnmp_config_add_host_auth_protocol (hd, option);
 +    else if (strcasecmp ("PrivacyProtocol", option->key) == 0)
 +      status = csnmp_config_add_host_priv_protocol (hd, option);
 +    else if (strcasecmp ("AuthPassphrase", option->key) == 0)
 +      status = cf_util_get_string(option, &hd->auth_passphrase);
 +    else if (strcasecmp ("PrivacyPassphrase", option->key) == 0)
 +      status = cf_util_get_string(option, &hd->priv_passphrase);
 +    else if (strcasecmp ("SecurityLevel", option->key) == 0)
 +      status = csnmp_config_add_host_security_level (hd, option);
 +    else if (strcasecmp ("Context", option->key) == 0)
 +      status = cf_util_get_string(option, &hd->context);
      else
      {
        WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
        status = -1;
        break;
      }
 -    if (hd->community == NULL)
 +    if (hd->community == NULL && hd->version < 3)
      {
        WARNING ("snmp plugin: `Community' not given for host `%s'", hd->name);
        status = -1;
        break;
      }
 +    if (hd->version == 3)
 +    {
 +      if (hd->username == NULL)
 +      {
 +        WARNING ("snmp plugin: `Username' not given for host `%s'", hd->name);
 +        status = -1;
 +        break;
 +      }
 +      if (hd->security_level == 0)
 +      {
 +        WARNING ("snmp plugin: `SecurityLevel' not given for host `%s'", hd->name);
 +        status = -1;
 +        break;
 +      }
 +      if (hd->security_level == SNMP_SEC_LEVEL_AUTHNOPRIV || hd->security_level == SNMP_SEC_LEVEL_AUTHPRIV)
 +      {
 +      if (hd->auth_protocol == NULL)
 +      {
 +        WARNING ("snmp plugin: `AuthProtocol' not given for host `%s'", hd->name);
 +        status = -1;
 +        break;
 +      }
 +      if (hd->auth_passphrase == NULL)
 +      {
 +        WARNING ("snmp plugin: `AuthPassphrase' not given for host `%s'", hd->name);
 +        status = -1;
 +        break;
 +      }
 +      }
 +      if (hd->security_level == SNMP_SEC_LEVEL_AUTHPRIV)
 +      {
 +      if (hd->priv_protocol == NULL)
 +      {
 +        WARNING ("snmp plugin: `PrivacyProtocol' not given for host `%s'", hd->name);
 +        status = -1;
 +        break;
 +      }
 +      if (hd->priv_passphrase == NULL)
 +      {
 +        WARNING ("snmp plugin: `PrivacyPassphrase' not given for host `%s'", hd->name);
 +        status = -1;
 +        break;
 +      }
 +      }
 +    }
  
      break;
    } /* while (status == 0) */
@@@ -821,75 -724,15 +821,75 @@@ static int csnmp_config (oconfig_item_
  static void csnmp_host_open_session (host_definition_t *host)
  {
    struct snmp_session sess;
 +  int error;
  
    if (host->sess_handle != NULL)
      csnmp_host_close_session (host);
  
    snmp_sess_init (&sess);
    sess.peername = host->address;
 -  sess.community = (u_char *) host->community;
 -  sess.community_len = strlen (host->community);
 -  sess.version = (host->version == 1) ? SNMP_VERSION_1 : SNMP_VERSION_2c;
 +  switch (host->version)
 +  {
 +    case 1:
 +      sess.version = SNMP_VERSION_1;
 +      break;
 +    case 3:
 +      sess.version = SNMP_VERSION_3;
 +      break;
 +    default:
 +      sess.version = SNMP_VERSION_2c;
 +      break;
 +  }
 +
 +  if (host->version == 3)
 +  {
 +    sess.securityName = host->username;
 +    sess.securityNameLen = strlen (host->username);
 +    sess.securityLevel = host->security_level;
 +
 +    if (sess.securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV)
 +    {
 +      sess.securityAuthProto = host->auth_protocol;
 +      sess.securityAuthProtoLen = host->auth_protocol_len;
 +      sess.securityAuthKeyLen = USM_AUTH_KU_LEN;
 +      error = generate_Ku (sess.securityAuthProto,
 +          sess.securityAuthProtoLen,
 +          (u_char *) host->auth_passphrase,
 +          strlen(host->auth_passphrase),
 +          sess.securityAuthKey,
 +          &sess.securityAuthKeyLen);
 +      if (error != SNMPERR_SUCCESS) {
 +      ERROR ("snmp plugin: host %s: Error generating Ku from auth_passphrase. (Error %d)", host->name, error);
 +      }
 +    }
 +
 +    if (sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV)
 +    {
 +      sess.securityPrivProto = host->priv_protocol;
 +      sess.securityPrivProtoLen = host->priv_protocol_len;
 +      sess.securityPrivKeyLen = USM_PRIV_KU_LEN;
 +      error = generate_Ku (sess.securityAuthProto,
 +          sess.securityAuthProtoLen,
 +          (u_char *) host->priv_passphrase,
 +          strlen(host->priv_passphrase),
 +          sess.securityPrivKey,
 +          &sess.securityPrivKeyLen);
 +      if (error != SNMPERR_SUCCESS) {
 +      ERROR ("snmp plugin: host %s: Error generating Ku from priv_passphrase. (Error %d)", host->name, error);
 +      }
 +    }
 +
 +    if (host->context != NULL)
 +    {
 +      sess.contextName = host->context;
 +      sess.contextNameLen = strlen (host->context);
 +    }
 +  }
 +  else /* SNMPv1/2 "authenticates" with community string */
 +  {
 +    sess.community = (u_char *) host->community;
 +    sess.community_len = strlen (host->community);
 +  }
  
    /* snmp_sess_open will copy the `struct snmp_session *'. */
    host->sess_handle = snmp_sess_open (&sess);
@@@ -1128,8 -971,6 +1128,8 @@@ static int csnmp_instance_list_add (csn
    struct variable_list *vb;
    oid_t vb_name;
    int status;
 +  uint32_t i;
 +  uint32_t is_matched;
  
    /* Set vb on the last variable */
    for (vb = res->variables;
      char *ptr;
  
      csnmp_strvbcopy (il->instance, vb, sizeof (il->instance));
 -
 +    is_matched = 0;
 +    for (i = 0; i < dd->ignores_len; i++)
 +    {
 +      status = fnmatch(dd->ignores[i], il->instance, 0);
 +      if (status == 0)
 +      {
 +        if (dd->invert_match == 0)
 +        {
 +          sfree(il);
 +          return 0;
 +        }
 +      else
 +      {
 +          is_matched = 1;
 +        break;
 +      }
 +      }
 +    }
 +    if (dd->invert_match != 0 && is_matched == 0)
 +    {
 +      sfree(il);
 +      return 0;
 +    }
      for (ptr = il->instance; *ptr != '\0'; ptr++)
      {
        if ((*ptr > 0) && (*ptr < 32))
@@@ -1618,6 -1437,10 +1618,10 @@@ static int csnmp_read_table (host_defin
      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);
  
@@@ -1836,7 -1659,6 +1840,7 @@@ static int csnmp_shutdown (void
      sfree (data_this->name);
      sfree (data_this->type);
      sfree (data_this->values);
 +    sfree (data_this->ignores);
      sfree (data_this);
  
      data_this = data_next;
diff --combined src/tcpconns.c
@@@ -17,7 -17,7 +17,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>
   *   Michael Stapelberg <michael+git at stapelberg.de>
   **/
  
@@@ -74,7 -74,9 +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[] =
  {
@@@ -215,13 -219,13 +219,13 @@@ static const char *tcp_state[] 
    "CLOSED",
    "LISTEN",
    "SYN_SENT",
 -  "SYN_RCVD",
 +  "SYN_RECV",
    "ESTABLISHED",
    "CLOSE_WAIT",
 -  "FIN_WAIT_1",
 +  "FIN_WAIT1",
    "CLOSING",
    "LAST_ACK",
 -  "FIN_WAIT_2",
 +  "FIN_WAIT2",
    "TIME_WAIT"
  };
  
@@@ -276,7 -280,12 +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 +455,7 @@@ static int conn_handle_ports (uint16_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;
  
    /* 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)
diff --combined src/utils_vl_lookup.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/utils_vl_lookup.c
 - * Copyright (C) 2012  Florian Forster
 + * Copyright (C) 2012       Florian Forster
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
@@@ -26,6 -26,7 +26,7 @@@
  
  #include "collectd.h"
  
+ #include <pthread.h>
  #include <regex.h>
  
  #include "common.h"
@@@ -86,6 -87,7 +87,7 @@@ struct user_obj_
  
  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 +193,7 @@@ static int lu_copy_ident_to_match (iden
    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)
    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 +298,17 @@@ static int lu_handle_user_class (lookup
        || !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 +409,7 @@@ static int lu_add_by_plugin (by_type_en
    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 +494,7 @@@ static void lu_destroy_user_class_list 
  
      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 +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;
diff --combined src/write_http.c
@@@ -18,7 -18,7 +18,7 @@@
   * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   *
   * Authors:
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Doug MacEachern <dougm@hyperic.com>
   *   Paul Sadauskas <psadauskas@gmail.com>
   **/
@@@ -46,15 -46,10 +46,15 @@@ struct wh_callback_
          char *user;
          char *pass;
          char *credentials;
 -        int   verify_peer;
 -        int   verify_host;
 +        _Bool verify_peer;
 +        _Bool verify_host;
          char *cacert;
 -        int   store_rates;
 +        char *capath;
 +        char *clientkey;
 +        char *clientcert;
 +        char *clientkeypass;
 +        long sslversion;
 +        _Bool store_rates;
  
  #define WH_FORMAT_COMMAND 0
  #define WH_FORMAT_JSON    1
@@@ -117,7 -112,7 +117,7 @@@ static int wh_callback_init (wh_callbac
          }
  
          curl_easy_setopt (cb->curl, CURLOPT_NOSIGNAL, 1L);
 -        curl_easy_setopt (cb->curl, CURLOPT_USERAGENT, PACKAGE_NAME"/"PACKAGE_VERSION);
 +        curl_easy_setopt (cb->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT);
  
          headers = NULL;
          headers = curl_slist_append (headers, "Accept:  */*");
          curl_easy_setopt (cb->curl, CURLOPT_SSL_VERIFYPEER, (long) cb->verify_peer);
          curl_easy_setopt (cb->curl, CURLOPT_SSL_VERIFYHOST,
                          cb->verify_host ? 2L : 0L);
 +        curl_easy_setopt (cb->curl, CURLOPT_SSLVERSION, cb->sslversion);
          if (cb->cacert != NULL)
                  curl_easy_setopt (cb->curl, CURLOPT_CAINFO, cb->cacert);
 +        if (cb->capath != NULL)
 +                curl_easy_setopt (cb->curl, CURLOPT_CAPATH, cb->capath);
 +
 +        if (cb->clientkey != NULL && cb->clientcert != NULL)
 +        {
 +            curl_easy_setopt (cb->curl, CURLOPT_SSLKEY, cb->clientkey);
 +            curl_easy_setopt (cb->curl, CURLOPT_SSLCERT, cb->clientcert);
 +
 +            if (cb->clientkeypass != NULL)
 +                curl_easy_setopt (cb->curl, CURLOPT_SSLKEYPASSWD, cb->clientkeypass);
 +        }
  
          wh_reset_buffer (cb);
  
@@@ -286,10 -269,6 +286,10 @@@ static void wh_callback_free (void *dat
          sfree (cb->pass);
          sfree (cb->credentials);
          sfree (cb->cacert);
 +        sfree (cb->capath);
 +        sfree (cb->clientkey);
 +        sfree (cb->clientcert);
 +        sfree (cb->clientkeypass);
  
          sfree (cb);
  } /* }}} void wh_callback_free */
@@@ -454,6 -433,47 +454,6 @@@ static int wh_write (const data_set_t *
          return (status);
  } /* }}} int wh_write */
  
 -static int 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 ("write_http 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 ("write_http plugin: strdup failed.");
 -                return (-1);
 -        }
 -
 -        if (*ret_string != NULL)
 -                free (*ret_string);
 -        *ret_string = string;
 -
 -        return (0);
 -} /* }}} int config_set_string */
 -
 -static int config_set_boolean (int *dest, oconfig_item_t *ci) /* {{{ */
 -{
 -        if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
 -        {
 -                WARNING ("write_http plugin: The `%s' config option "
 -                                "needs exactly one boolean argument.", ci->key);
 -                return (-1);
 -        }
 -
 -        *dest = ci->values[0].value.boolean ? 1 : 0;
 -
 -        return (0);
 -} /* }}} int config_set_boolean */
 -
  static int config_set_format (wh_callback_t *cb, /* {{{ */
                  oconfig_item_t *ci)
  {
          }
  
          return (0);
 -} /* }}} int config_set_string */
 +} /* }}} int config_set_format */
  
  static int wh_config_url (oconfig_item_t *ci) /* {{{ */
  {
                  return (-1);
          }
          memset (cb, 0, sizeof (*cb));
 -        cb->location = NULL;
 -        cb->user = NULL;
 -        cb->pass = NULL;
 -        cb->credentials = NULL;
          cb->verify_peer = 1;
          cb->verify_host = 1;
 -        cb->cacert = NULL;
          cb->format = WH_FORMAT_COMMAND;
 -        cb->curl = NULL;
 +        cb->sslversion = CURL_SSLVERSION_DEFAULT;
  
          pthread_mutex_init (&cb->send_lock, /* attr = */ NULL);
  
 -        config_set_string (&cb->location, ci);
 +        cf_util_get_string (ci, &cb->location);
          if (cb->location == NULL)
                  return (-1);
  
                  oconfig_item_t *child = ci->children + i;
  
                  if (strcasecmp ("User", child->key) == 0)
 -                        config_set_string (&cb->user, child);
 +                        cf_util_get_string (child, &cb->user);
                  else if (strcasecmp ("Password", child->key) == 0)
 -                        config_set_string (&cb->pass, child);
 +                        cf_util_get_string (child, &cb->pass);
                  else if (strcasecmp ("VerifyPeer", child->key) == 0)
 -                        config_set_boolean (&cb->verify_peer, child);
 +                        cf_util_get_boolean (child, &cb->verify_peer);
                  else if (strcasecmp ("VerifyHost", child->key) == 0)
 -                        config_set_boolean (&cb->verify_host, child);
 +                        cf_util_get_boolean (child, &cb->verify_host);
                  else if (strcasecmp ("CACert", child->key) == 0)
 -                        config_set_string (&cb->cacert, child);
 +                        cf_util_get_string (child, &cb->cacert);
 +                else if (strcasecmp ("CAPath", child->key) == 0)
 +                        cf_util_get_string (child, &cb->capath);
 +                else if (strcasecmp ("ClientKey", child->key) == 0)
 +                        cf_util_get_string (child, &cb->clientkey);
 +                else if (strcasecmp ("ClientCert", child->key) == 0)
 +                        cf_util_get_string (child, &cb->clientcert);
 +                else if (strcasecmp ("ClientKeyPass", child->key) == 0)
 +                        cf_util_get_string (child, &cb->clientkeypass);
 +                else if (strcasecmp ("SSLVersion", child->key) == 0)
 +                {
 +                        char *value = NULL;
 +
 +                        cf_util_get_string (child, &value);
 +
 +                        if (value == NULL || strcasecmp ("default", value) == 0)
 +                                cb->sslversion = CURL_SSLVERSION_DEFAULT;
 +                        else if (strcasecmp ("SSLv2", value) == 0)
 +                                cb->sslversion = CURL_SSLVERSION_SSLv2;
 +                        else if (strcasecmp ("SSLv3", value) == 0)
 +                                cb->sslversion = CURL_SSLVERSION_SSLv3;
 +                        else if (strcasecmp ("TLSv1", value) == 0)
 +                                cb->sslversion = CURL_SSLVERSION_TLSv1;
 +#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 34)
 +                        else if (strcasecmp ("TLSv1_0", value) == 0)
 +                                cb->sslversion = CURL_SSLVERSION_TLSv1_0;
 +                        else if (strcasecmp ("TLSv1_1", value) == 0)
 +                                cb->sslversion = CURL_SSLVERSION_TLSv1_1;
 +                        else if (strcasecmp ("TLSv1_2", value) == 0)
 +                                cb->sslversion = CURL_SSLVERSION_TLSv1_2;
 +#endif
 +                        else
 +                                ERROR ("write_http plugin: Invalid SSLVersion "
 +                                                "option: %s.", value);
 +
 +                        sfree(value);
 +                }
                  else if (strcasecmp ("Format", child->key) == 0)
                          config_set_format (cb, child);
                  else if (strcasecmp ("StoreRates", child->key) == 0)
 -                        config_set_boolean (&cb->store_rates, child);
 +                        cf_util_get_boolean (child, &cb->store_rates);
                  else
                  {
                          ERROR ("write_http plugin: Invalid configuration "
@@@ -601,9 -590,18 +601,18 @@@ static int wh_config (oconfig_item_t *c
          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 : */
diff --combined src/write_riemann.c
@@@ -1,25 -1,20 +1,25 @@@
  /**
   * collectd - src/write_riemann.c
 - *
   * Copyright (C) 2012,2013  Pierre-Yves Ritschard
   * Copyright (C) 2013       Florian octo Forster
   *
 - * Permission to use, copy, modify, and distribute this software for any
 - * purpose with or without fee is hereby granted, provided that the above
 - * copyright notice and this permission notice appear in all copies.
 + * 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" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 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:
   *   Pierre-Yves Ritschard <pyr at spootnik.org>
  #define RIEMANN_PORT          "5555"
  #define RIEMANN_TTL_FACTOR      2.0
  
 +int write_riemann_threshold_check(const data_set_t *, const value_list_t *, int *);
 +
  struct riemann_host {
        char                    *name;
  #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;
@@@ -66,8 -57,6 +66,8 @@@
  
  static char   **riemann_tags;
  static size_t   riemann_tags_num;
 +static char   **riemann_attrs;
 +static size_t     riemann_attrs_num;
  
  static void riemann_event_protobuf_free (Event *event) /* {{{ */
  {
@@@ -97,7 -86,7 +97,7 @@@
        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;
  
@@@ -159,7 -148,7 +159,7 @@@ static int riemann_connect(struct riema
                }
  
                host->flags |= F_CONNECT;
 -              DEBUG("write_riemann plugin: got a succesful connection for: %s:%s",
 +              DEBUG("write_riemann plugin: got a successful connection for: %s:%s",
                                node, service);
                break;
        }
@@@ -319,7 -308,7 +319,7 @@@ static int riemann_event_add_tag (Even
        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;
        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;
                riemann_event_add_attribute (event, "type_instance",
                                n->type_instance);
  
 +      for (i = 0; i < riemann_attrs_num; i += 2)
 +              riemann_event_add_attribute(event,
 +                                          riemann_attrs[i],
 +                                          riemann_attrs[i +1]);
 +
        for (i = 0; i < riemann_tags_num; i++)
                riemann_event_add_tag (event, riemann_tags[i]);
  
                        n->type, n->type_instance);
        event->service = strdup (&service_buffer[1]);
  
 -      /* Pull in values from threshold */
 +      if (n->message[0] != 0)
 +              riemann_event_add_attribute (event, "description", n->message);
 +
 +      /* Pull in values from threshold and add extra attributes */
        for (meta = n->meta; meta != NULL; meta = meta->next)
        {
 -              if (strcasecmp ("CurrentValue", meta->name) != 0)
 +              if (strcasecmp ("CurrentValue", meta->name) == 0 && meta->type == NM_TYPE_DOUBLE)
 +              {
 +                      event->metric_d = meta->nm_value.nm_double;
 +                      event->has_metric_d = 1;
                        continue;
 +              }
  
 -              event->metric_d = meta->nm_value.nm_double;
 -              event->has_metric_d = 1;
 -              break;
 +              if (meta->type == NM_TYPE_STRING) {
 +                      riemann_event_add_attribute (event, meta->name, meta->nm_value.nm_string);
 +                      continue;
 +              }
        }
  
        DEBUG ("write_riemann plugin: Successfully created protobuf for notification: "
        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)
 +                                       gauge_t const *rates,
 +                                       int status)
  {
        Event *event;
        char name_buffer[5 * DATA_MAX_NAME_LEN];
        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;
        event->has_ttl = 1;
                riemann_event_add_attribute (event, "ds_index", ds_index);
        }
  
 +      for (i = 0; i < riemann_attrs_num; i += 2)
 +              riemann_event_add_attribute(event,
 +                                          riemann_attrs[i],
 +                                          riemann_attrs[i +1]);
 +
        for (i = 0; i < riemann_tags_num; i++)
                riemann_event_add_tag (event, riemann_tags[i]);
  
        return (event);
  } /* }}} Event *riemann_value_to_protobuf */
  
 -static Msg *riemann_value_list_to_protobuf(struct riemann_host const *host, /* {{{ */
 -              data_set_t const *ds,
 -              value_list_t const *vl)
 +static Msg *riemann_value_list_to_protobuf (struct riemann_host const *host, /* {{{ */
 +                                          data_set_t const *ds,
 +                                          value_list_t const *vl,
 +                                          int *statuses)
  {
        Msg *msg;
        size_t i;
        for (i = 0; i < msg->n_events; i++)
        {
                msg->events[i] = riemann_value_to_protobuf (host, ds, vl,
 -                              (int) i, rates);
 +                                                          (int) i, rates, statuses[i]);
                if (msg->events[i] == NULL)
                {
                        riemann_msg_protobuf_free (msg);
@@@ -645,9 -597,6 +645,9 @@@ static int riemann_notification(const n
        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)
                return (-1);
@@@ -666,13 -615,10 +666,13 @@@ static int riemann_write(const data_set
              user_data_t *ud)
  {
        int                      status;
 +      int                      statuses[vl->values_len];
        struct riemann_host     *host = ud->data;
        Msg                     *msg;
  
-     if (host->check_thresholds)
-         write_riemann_threshold_check(ds, vl, statuses);
 -      msg = riemann_value_list_to_protobuf (host, ds, vl);
++      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 -671,6 +725,8 @@@ static int riemann_config_node(oconfig_
        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;
                        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) {
@@@ -887,32 -823,6 +887,32 @@@ static int riemann_config(oconfig_item_
  
                if (strcasecmp("Node", child->key) == 0) {
                        riemann_config_node (child);
 +              } else if (strcasecmp(child->key, "attribute") == 0) {
 +                      char *key = NULL;
 +                      char *val = NULL;
 +
 +                      if (child->values_num != 2) {
 +                              WARNING("riemann attributes need both a key and a value.");
 +                              return (-1);
 +                      }
 +                      if (child->values[0].type != OCONFIG_TYPE_STRING ||
 +                          child->values[1].type != OCONFIG_TYPE_STRING) {
 +                              WARNING("riemann attribute needs string arguments.");
 +                              return (-1);
 +                      }
 +                      if ((key = strdup(child->values[0].value.string)) == NULL) {
 +                              WARNING("cannot allocate memory for attribute key.");
 +                              return (-1);
 +                      }
 +                      if ((val = strdup(child->values[1].value.string)) == NULL) {
 +                              WARNING("cannot allocate memory for attribute value.");
 +                              return (-1);
 +                      }
 +                      strarray_add(&riemann_attrs, &riemann_attrs_num, key);
 +                      strarray_add(&riemann_attrs, &riemann_attrs_num, val);
 +                      DEBUG("write_riemann: got attr: %s => %s", key, val);
 +                      sfree(key);
 +                      sfree(val);
                } else if (strcasecmp(child->key, "tag") == 0) {
                        char *tmp = NULL;
                        status = cf_util_get_string(child, &tmp);
                                 child->key);
                }
        }
-     return 0;
+       return (0);
  } /* }}} int riemann_config */
  
  void module_register(void)
diff --combined version-gen.sh
@@@ -1,8 -1,8 +1,8 @@@
  #!/usr/bin/env bash
  
- DEFAULT_VERSION="5.4.0.git"
+ DEFAULT_VERSION="5.4.1.git"
  
 -VERSION="`git describe 2> /dev/null | sed -e 's/^collectd-//'`"
 +VERSION="`git describe 2> /dev/null | grep collectd | sed -e 's/^collectd-//'`"
  
  if test -z "$VERSION"; then
        VERSION="$DEFAULT_VERSION"